@nlabs/lex 1.49.4 → 1.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.swcrc +35 -0
- package/README.md +43 -59
- package/__mocks__/chalk.js +19 -17
- package/config.json +32 -8
- package/examples/lex.config.js +110 -10
- package/index.cjs +1 -5
- package/lex.config.js +34 -7
- package/lib/Button.stories.js +99 -0
- package/lib/LexConfig.d.ts +60 -22
- package/lib/LexConfig.js +285 -244
- package/lib/commands/ai/ai.js +287 -288
- package/lib/commands/ai/index.js +8 -7
- package/lib/commands/build/build.d.ts +2 -2
- package/lib/commands/build/build.js +349 -458
- package/lib/commands/clean/clean.js +45 -33
- package/lib/commands/compile/compile.js +214 -227
- package/lib/commands/config/config.js +46 -42
- package/lib/commands/copy/copy.js +36 -35
- package/lib/commands/create/create.js +200 -121
- package/lib/commands/dev/dev.d.ts +2 -0
- package/lib/commands/dev/dev.js +259 -263
- package/lib/commands/init/init.js +108 -88
- package/lib/commands/link/link.js +18 -14
- package/lib/commands/lint/lint.js +735 -742
- package/lib/commands/migrate/migrate.js +49 -36
- package/lib/commands/publish/publish.js +116 -96
- package/lib/commands/serverless/serverless.js +611 -585
- package/lib/commands/storybook/storybook.js +242 -238
- package/lib/commands/test/test.d.ts +1 -1
- package/lib/commands/test/test.js +382 -394
- package/lib/commands/update/update.js +141 -120
- package/lib/commands/upgrade/upgrade.js +51 -44
- package/lib/commands/versions/versions.d.ts +1 -1
- package/lib/commands/versions/versions.js +36 -38
- package/lib/create/changelog.js +136 -125
- package/lib/index.js +40 -38
- package/lib/lex.js +95 -68
- package/lib/storybook/index.js +6 -1
- package/lib/test-react/index.js +7 -84
- package/lib/types.d.ts +1 -1
- package/lib/types.js +7 -1
- package/lib/utils/aiService.js +240 -227
- package/lib/utils/app.js +274 -273
- package/lib/utils/deepMerge.js +37 -23
- package/lib/utils/file.js +218 -215
- package/lib/utils/log.js +29 -27
- package/lib/utils/reactShim.js +7 -85
- package/lib/utils/translations.js +91 -65
- package/package.json +63 -64
- package/templates/typescript/DataLayer.js.txt +218 -0
- package/templates/typescript/DataLayer.test.js.txt +268 -0
- package/templates/typescript/DataLayer.test.ts.txt +269 -0
- package/templates/typescript/DataLayer.ts.txt +227 -0
- package/webpack.config.js +53 -26
- package/lib/commands/lint/autofix.d.ts +0 -2
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2018-Present, Nitrogen Labs, Inc.
|
|
3
|
+
* Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
class DataLayer {
|
|
7
|
+
constructor(options = {}) {
|
|
8
|
+
this.options = {
|
|
9
|
+
tableName: process.env.TABLE_NAME || 'default-table',
|
|
10
|
+
region: process.env.AWS_REGION || 'us-east-1',
|
|
11
|
+
endpoint: process.env.DYNAMODB_ENDPOINT,
|
|
12
|
+
...options
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get a single item by ID
|
|
18
|
+
*/
|
|
19
|
+
async getItem(id) {
|
|
20
|
+
try {
|
|
21
|
+
// TODO: Implement DynamoDB getItem logic
|
|
22
|
+
console.log(`Getting item with ID: ${id}`);
|
|
23
|
+
|
|
24
|
+
// Example response structure
|
|
25
|
+
return {
|
|
26
|
+
id,
|
|
27
|
+
data: 'sample data',
|
|
28
|
+
timestamp: new Date().toISOString()
|
|
29
|
+
};
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error('Error getting item:', error);
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Create a new item
|
|
38
|
+
*/
|
|
39
|
+
async createItem(data) {
|
|
40
|
+
try {
|
|
41
|
+
// TODO: Implement DynamoDB putItem logic
|
|
42
|
+
console.log('Creating new item:', data);
|
|
43
|
+
|
|
44
|
+
const newItem = {
|
|
45
|
+
id: data.id || `item-${Date.now()}`,
|
|
46
|
+
...data,
|
|
47
|
+
createdAt: new Date().toISOString(),
|
|
48
|
+
updatedAt: new Date().toISOString()
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return newItem;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error('Error creating item:', error);
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Update an existing item
|
|
60
|
+
*/
|
|
61
|
+
async updateItem(id, data) {
|
|
62
|
+
try {
|
|
63
|
+
// TODO: Implement DynamoDB updateItem logic
|
|
64
|
+
console.log(`Updating item ${id}:`, data);
|
|
65
|
+
|
|
66
|
+
const updatedItem = {
|
|
67
|
+
id,
|
|
68
|
+
...data,
|
|
69
|
+
updatedAt: new Date().toISOString()
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return updatedItem;
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.error('Error updating item:', error);
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Delete an item by ID
|
|
81
|
+
*/
|
|
82
|
+
async deleteItem(id) {
|
|
83
|
+
try {
|
|
84
|
+
// TODO: Implement DynamoDB deleteItem logic
|
|
85
|
+
console.log(`Deleting item with ID: ${id}`);
|
|
86
|
+
|
|
87
|
+
return true;
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error('Error deleting item:', error);
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* List items with optional filtering
|
|
96
|
+
*/
|
|
97
|
+
async listItems(filters) {
|
|
98
|
+
try {
|
|
99
|
+
// TODO: Implement DynamoDB scan/query logic
|
|
100
|
+
console.log('Listing items with filters:', filters);
|
|
101
|
+
|
|
102
|
+
// Example response
|
|
103
|
+
return [
|
|
104
|
+
{
|
|
105
|
+
id: 'item-1',
|
|
106
|
+
data: 'sample data 1',
|
|
107
|
+
timestamp: new Date().toISOString()
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
id: 'item-2',
|
|
111
|
+
data: 'sample data 2',
|
|
112
|
+
timestamp: new Date().toISOString()
|
|
113
|
+
}
|
|
114
|
+
];
|
|
115
|
+
} catch (error) {
|
|
116
|
+
console.error('Error listing items:', error);
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Lambda handler for HTTP requests
|
|
123
|
+
*/
|
|
124
|
+
async handleRequest(event, context) {
|
|
125
|
+
try {
|
|
126
|
+
const {httpMethod, pathParameters, body, queryStringParameters} = event;
|
|
127
|
+
const id = pathParameters?.id;
|
|
128
|
+
|
|
129
|
+
let result;
|
|
130
|
+
|
|
131
|
+
switch (httpMethod) {
|
|
132
|
+
case 'GET':
|
|
133
|
+
if (id) {
|
|
134
|
+
result = await this.getItem(id);
|
|
135
|
+
} else {
|
|
136
|
+
result = await this.listItems(queryStringParameters);
|
|
137
|
+
}
|
|
138
|
+
break;
|
|
139
|
+
|
|
140
|
+
case 'POST':
|
|
141
|
+
const createData = body ? JSON.parse(body) : {};
|
|
142
|
+
result = await this.createItem(createData);
|
|
143
|
+
break;
|
|
144
|
+
|
|
145
|
+
case 'PUT':
|
|
146
|
+
case 'PATCH':
|
|
147
|
+
if (!id) {
|
|
148
|
+
return {
|
|
149
|
+
statusCode: 400,
|
|
150
|
+
headers: {
|
|
151
|
+
'Content-Type': 'application/json',
|
|
152
|
+
'Access-Control-Allow-Origin': '*'
|
|
153
|
+
},
|
|
154
|
+
body: JSON.stringify({error: 'ID is required for update operations'})
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const updateData = body ? JSON.parse(body) : {};
|
|
158
|
+
result = await this.updateItem(id, updateData);
|
|
159
|
+
break;
|
|
160
|
+
|
|
161
|
+
case 'DELETE':
|
|
162
|
+
if (!id) {
|
|
163
|
+
return {
|
|
164
|
+
statusCode: 400,
|
|
165
|
+
headers: {
|
|
166
|
+
'Content-Type': 'application/json',
|
|
167
|
+
'Access-Control-Allow-Origin': '*'
|
|
168
|
+
},
|
|
169
|
+
body: JSON.stringify({error: 'ID is required for delete operations'})
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
await this.deleteItem(id);
|
|
173
|
+
result = {message: 'Item deleted successfully'};
|
|
174
|
+
break;
|
|
175
|
+
|
|
176
|
+
default:
|
|
177
|
+
return {
|
|
178
|
+
statusCode: 405,
|
|
179
|
+
headers: {
|
|
180
|
+
'Content-Type': 'application/json',
|
|
181
|
+
'Access-Control-Allow-Origin': '*'
|
|
182
|
+
},
|
|
183
|
+
body: JSON.stringify({error: 'Method not allowed'})
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
statusCode: 200,
|
|
189
|
+
headers: {
|
|
190
|
+
'Content-Type': 'application/json',
|
|
191
|
+
'Access-Control-Allow-Origin': '*'
|
|
192
|
+
},
|
|
193
|
+
body: JSON.stringify(result)
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
} catch (error) {
|
|
197
|
+
console.error('Handler error:', error);
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
statusCode: 500,
|
|
201
|
+
headers: {
|
|
202
|
+
'Content-Type': 'application/json',
|
|
203
|
+
'Access-Control-Allow-Origin': '*'
|
|
204
|
+
},
|
|
205
|
+
body: JSON.stringify({
|
|
206
|
+
error: 'Internal server error',
|
|
207
|
+
message: error instanceof Error ? error.message : 'Unknown error'
|
|
208
|
+
})
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Export the handler function for Lambda
|
|
215
|
+
export const handler = async (event, context) => {
|
|
216
|
+
const dataLayer = new DataLayer();
|
|
217
|
+
return dataLayer.handleRequest(event, context);
|
|
218
|
+
};
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2018-Present, Nitrogen Labs, Inc.
|
|
3
|
+
* Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {DataLayer, handler} from './DataLayer.js';
|
|
7
|
+
|
|
8
|
+
describe('DataLayer', () => {
|
|
9
|
+
let dataLayer;
|
|
10
|
+
let mockContext;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
dataLayer = new DataLayer({
|
|
14
|
+
tableName: 'test-table',
|
|
15
|
+
region: 'us-east-1'
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
mockContext = {
|
|
19
|
+
awsRequestId: 'test-request-id',
|
|
20
|
+
functionName: 'test-function',
|
|
21
|
+
functionVersion: '$LATEST',
|
|
22
|
+
getRemainingTimeInMillis: () => 30000,
|
|
23
|
+
invokedFunctionArn: 'arn:aws:lambda:us-east-1:123456789012:function:test-function',
|
|
24
|
+
logGroupName: '/aws/lambda/test-function',
|
|
25
|
+
logStreamName: 'test-log-stream',
|
|
26
|
+
memoryLimitInMB: '128'
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('getItem', () => {
|
|
31
|
+
it('should get an item by ID', async () => {
|
|
32
|
+
const result = await dataLayer.getItem('test-id');
|
|
33
|
+
|
|
34
|
+
expect(result).toEqual({
|
|
35
|
+
id: 'test-id',
|
|
36
|
+
data: 'sample data',
|
|
37
|
+
timestamp: expect.any(String)
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('createItem', () => {
|
|
43
|
+
it('should create a new item', async () => {
|
|
44
|
+
const itemData = {
|
|
45
|
+
name: 'Test Item',
|
|
46
|
+
description: 'A test item'
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const result = await dataLayer.createItem(itemData);
|
|
50
|
+
|
|
51
|
+
expect(result).toEqual({
|
|
52
|
+
id: expect.stringMatching(/^item-\d+$/),
|
|
53
|
+
name: 'Test Item',
|
|
54
|
+
description: 'A test item',
|
|
55
|
+
createdAt: expect.any(String),
|
|
56
|
+
updatedAt: expect.any(String)
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should create an item with custom ID', async () => {
|
|
61
|
+
const itemData = {
|
|
62
|
+
id: 'custom-id',
|
|
63
|
+
name: 'Test Item'
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const result = await dataLayer.createItem(itemData);
|
|
67
|
+
|
|
68
|
+
expect(result.id).toBe('custom-id');
|
|
69
|
+
expect(result.name).toBe('Test Item');
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('updateItem', () => {
|
|
74
|
+
it('should update an existing item', async () => {
|
|
75
|
+
const updateData = {
|
|
76
|
+
name: 'Updated Item',
|
|
77
|
+
description: 'Updated description'
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const result = await dataLayer.updateItem('test-id', updateData);
|
|
81
|
+
|
|
82
|
+
expect(result).toEqual({
|
|
83
|
+
id: 'test-id',
|
|
84
|
+
name: 'Updated Item',
|
|
85
|
+
description: 'Updated description',
|
|
86
|
+
updatedAt: expect.any(String)
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('deleteItem', () => {
|
|
92
|
+
it('should delete an item by ID', async () => {
|
|
93
|
+
const result = await dataLayer.deleteItem('test-id');
|
|
94
|
+
|
|
95
|
+
expect(result).toBe(true);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('listItems', () => {
|
|
100
|
+
it('should list items without filters', async () => {
|
|
101
|
+
const result = await dataLayer.listItems();
|
|
102
|
+
|
|
103
|
+
expect(Array.isArray(result)).toBe(true);
|
|
104
|
+
expect(result.length).toBeGreaterThan(0);
|
|
105
|
+
expect(result[0]).toHaveProperty('id');
|
|
106
|
+
expect(result[0]).toHaveProperty('data');
|
|
107
|
+
expect(result[0]).toHaveProperty('timestamp');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should list items with filters', async () => {
|
|
111
|
+
const filters = {
|
|
112
|
+
status: 'active'
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const result = await dataLayer.listItems(filters);
|
|
116
|
+
|
|
117
|
+
expect(Array.isArray(result)).toBe(true);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe('handleRequest', () => {
|
|
122
|
+
it('should handle GET request for single item', async () => {
|
|
123
|
+
const event = {
|
|
124
|
+
httpMethod: 'GET',
|
|
125
|
+
pathParameters: {id: 'test-id'},
|
|
126
|
+
body: null,
|
|
127
|
+
queryStringParameters: null
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
131
|
+
|
|
132
|
+
expect(result.statusCode).toBe(200);
|
|
133
|
+
expect(result.headers['Content-Type']).toBe('application/json');
|
|
134
|
+
expect(result.headers['Access-Control-Allow-Origin']).toBe('*');
|
|
135
|
+
|
|
136
|
+
const body = JSON.parse(result.body);
|
|
137
|
+
expect(body.id).toBe('test-id');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should handle GET request for list items', async () => {
|
|
141
|
+
const event = {
|
|
142
|
+
httpMethod: 'GET',
|
|
143
|
+
pathParameters: null,
|
|
144
|
+
body: null,
|
|
145
|
+
queryStringParameters: {status: 'active'}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
149
|
+
|
|
150
|
+
expect(result.statusCode).toBe(200);
|
|
151
|
+
const body = JSON.parse(result.body);
|
|
152
|
+
expect(Array.isArray(body)).toBe(true);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should handle POST request', async () => {
|
|
156
|
+
const event = {
|
|
157
|
+
httpMethod: 'POST',
|
|
158
|
+
pathParameters: null,
|
|
159
|
+
body: JSON.stringify({
|
|
160
|
+
name: 'New Item',
|
|
161
|
+
description: 'A new item'
|
|
162
|
+
}),
|
|
163
|
+
queryStringParameters: null
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
167
|
+
|
|
168
|
+
expect(result.statusCode).toBe(200);
|
|
169
|
+
const body = JSON.parse(result.body);
|
|
170
|
+
expect(body.name).toBe('New Item');
|
|
171
|
+
expect(body.description).toBe('A new item');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should handle PUT request', async () => {
|
|
175
|
+
const event = {
|
|
176
|
+
httpMethod: 'PUT',
|
|
177
|
+
pathParameters: {id: 'test-id'},
|
|
178
|
+
body: JSON.stringify({
|
|
179
|
+
name: 'Updated Item'
|
|
180
|
+
}),
|
|
181
|
+
queryStringParameters: null
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
185
|
+
|
|
186
|
+
expect(result.statusCode).toBe(200);
|
|
187
|
+
const body = JSON.parse(result.body);
|
|
188
|
+
expect(body.id).toBe('test-id');
|
|
189
|
+
expect(body.name).toBe('Updated Item');
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('should handle DELETE request', async () => {
|
|
193
|
+
const event = {
|
|
194
|
+
httpMethod: 'DELETE',
|
|
195
|
+
pathParameters: {id: 'test-id'},
|
|
196
|
+
body: null,
|
|
197
|
+
queryStringParameters: null
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
201
|
+
|
|
202
|
+
expect(result.statusCode).toBe(200);
|
|
203
|
+
const body = JSON.parse(result.body);
|
|
204
|
+
expect(body.message).toBe('Item deleted successfully');
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('should return 400 for PUT without ID', async () => {
|
|
208
|
+
const event = {
|
|
209
|
+
httpMethod: 'PUT',
|
|
210
|
+
pathParameters: null,
|
|
211
|
+
body: JSON.stringify({name: 'Updated Item'}),
|
|
212
|
+
queryStringParameters: null
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
216
|
+
|
|
217
|
+
expect(result.statusCode).toBe(400);
|
|
218
|
+
const body = JSON.parse(result.body);
|
|
219
|
+
expect(body.error).toBe('ID is required for update operations');
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('should return 400 for DELETE without ID', async () => {
|
|
223
|
+
const event = {
|
|
224
|
+
httpMethod: 'DELETE',
|
|
225
|
+
pathParameters: null,
|
|
226
|
+
body: null,
|
|
227
|
+
queryStringParameters: null
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
231
|
+
|
|
232
|
+
expect(result.statusCode).toBe(400);
|
|
233
|
+
const body = JSON.parse(result.body);
|
|
234
|
+
expect(body.error).toBe('ID is required for delete operations');
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('should return 405 for unsupported method', async () => {
|
|
238
|
+
const event = {
|
|
239
|
+
httpMethod: 'OPTIONS',
|
|
240
|
+
pathParameters: null,
|
|
241
|
+
body: null,
|
|
242
|
+
queryStringParameters: null
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
246
|
+
|
|
247
|
+
expect(result.statusCode).toBe(405);
|
|
248
|
+
const body = JSON.parse(result.body);
|
|
249
|
+
expect(body.error).toBe('Method not allowed');
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
describe('handler function', () => {
|
|
254
|
+
it('should work as Lambda handler', async () => {
|
|
255
|
+
const event = {
|
|
256
|
+
httpMethod: 'GET',
|
|
257
|
+
pathParameters: {id: 'test-id'},
|
|
258
|
+
body: null,
|
|
259
|
+
queryStringParameters: null
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const result = await handler(event, mockContext);
|
|
263
|
+
|
|
264
|
+
expect(result.statusCode).toBe(200);
|
|
265
|
+
expect(result.headers['Content-Type']).toBe('application/json');
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
});
|