@@ -214,45 +214,105 @@ describe('Path Utilities', () => {
214214 } ) ;
215215
216216 describe ( 'isAPIGatewayProxyEvent' , ( ) => {
217- it ( 'should return true for valid API Gateway Proxy event' , ( ) => {
218- const validEvent : APIGatewayProxyEvent = {
219- httpMethod : 'GET' ,
217+ const baseValidEvent = {
218+ httpMethod : 'GET' ,
219+ path : '/test' ,
220+ resource : '/test' ,
221+ headers : { } ,
222+ multiValueHeaders : { } ,
223+ queryStringParameters : { } ,
224+ multiValueQueryStringParameters : { } ,
225+ pathParameters : { } ,
226+ stageVariables : { } ,
227+ requestContext : { stage : 'test' } ,
228+ isBase64Encoded : false ,
229+ body : null ,
230+ } ;
231+
232+ it ( 'should return true for valid API Gateway Proxy event with all fields populated' , ( ) => {
233+ expect ( isAPIGatewayProxyEvent ( baseValidEvent ) ) . toBe ( true ) ;
234+ } ) ;
235+
236+ it ( 'should return true for real API Gateway event with null fields' , ( ) => {
237+ const realEvent = {
238+ resource : '/{proxy+}' ,
220239 path : '/test' ,
221- resource : '/test' ,
222- headers : { } ,
240+ httpMethod : 'GET' ,
241+ headers : null ,
242+ multiValueHeaders : null ,
243+ queryStringParameters : null ,
244+ multiValueQueryStringParameters : null ,
245+ pathParameters : { proxy : 'test' } ,
246+ stageVariables : null ,
223247 requestContext : {
224- accountId : '123456789012 ' ,
225- apiId : 'test-api ' ,
248+ resourceId : 'ovdb9g ' ,
249+ resourcePath : '/{proxy+} ' ,
226250 httpMethod : 'GET' ,
227- requestId : 'test-request-id' ,
228- resourceId : 'test-resource' ,
229- resourcePath : '/test' ,
230- stage : 'test' ,
231- identity : {
232- sourceIp : '127.0.0.1' ,
233- } ,
234- } as any ,
235- isBase64Encoded : false ,
251+ stage : 'test-invoke-stage' ,
252+ requestId : 'eecdfcfa-225a-4ee3-bdca-05fc31b6018a' ,
253+ identity : { sourceIp : 'test-invoke-source-ip' } ,
254+ } ,
236255 body : null ,
237- } as APIGatewayProxyEvent ;
256+ isBase64Encoded : false ,
257+ } ;
238258
239- expect ( isAPIGatewayProxyEvent ( validEvent ) ) . toBe ( true ) ;
259+ expect ( isAPIGatewayProxyEvent ( realEvent ) ) . toBe ( true ) ;
240260 } ) ;
241261
242- it ( 'should return true for valid event with string body' , ( ) => {
243- const validEvent = {
262+ it ( 'should return true for event with string body' , ( ) => {
263+ const eventWithBody = {
264+ ...baseValidEvent ,
244265 httpMethod : 'POST' ,
245- path : '/test' ,
246- resource : '/test' ,
247- headers : { 'content-type' : 'application/json' } ,
248- requestContext : { stage : 'test' } ,
249- isBase64Encoded : false ,
250266 body : '{"key":"value"}' ,
251267 } ;
252268
253- expect ( isAPIGatewayProxyEvent ( validEvent ) ) . toBe ( true ) ;
269+ expect ( isAPIGatewayProxyEvent ( eventWithBody ) ) . toBe ( true ) ;
254270 } ) ;
255271
272+ it . each ( [
273+ // Headers can be null in reality (even though types say otherwise)
274+ { field : 'headers' , value : null } ,
275+ { field : 'headers' , value : undefined } ,
276+ { field : 'multiValueHeaders' , value : null } ,
277+ { field : 'multiValueHeaders' , value : undefined } ,
278+ // These are officially nullable in the type definition
279+ { field : 'body' , value : null } ,
280+ { field : 'pathParameters' , value : null } ,
281+ { field : 'queryStringParameters' , value : null } ,
282+ { field : 'multiValueQueryStringParameters' , value : null } ,
283+ { field : 'stageVariables' , value : null } ,
284+ ] ) ( 'should return true when $field is $value' , ( { field, value } ) => {
285+ const event = { ...baseValidEvent , [ field ] : value } ;
286+ expect ( isAPIGatewayProxyEvent ( event ) ) . toBe ( true ) ;
287+ } ) ;
288+
289+ it . each ( [
290+ {
291+ field : 'headers' ,
292+ value : { 'content-type' : undefined , 'x-api-key' : 'test' } ,
293+ } ,
294+ {
295+ field : 'multiValueHeaders' ,
296+ value : { accept : undefined , 'x-custom' : [ 'val1' , 'val2' ] } ,
297+ } ,
298+ { field : 'pathParameters' , value : { id : undefined , name : 'test' } } ,
299+ {
300+ field : 'queryStringParameters' ,
301+ value : { filter : undefined , sort : 'asc' } ,
302+ } ,
303+ {
304+ field : 'multiValueQueryStringParameters' ,
305+ value : { tags : undefined , categories : [ 'a' , 'b' ] } ,
306+ } ,
307+ { field : 'stageVariables' , value : { env : undefined , version : 'v1' } } ,
308+ ] ) (
309+ 'should return true when $field contains undefined values' ,
310+ ( { field, value } ) => {
311+ const event = { ...baseValidEvent , [ field ] : value } ;
312+ expect ( isAPIGatewayProxyEvent ( event ) ) . toBe ( true ) ;
313+ }
314+ ) ;
315+
256316 it . each ( [
257317 { case : 'null' , event : null } ,
258318 { case : 'undefined' , event : undefined } ,
@@ -266,42 +326,52 @@ describe('Path Utilities', () => {
266326 it . each ( [
267327 { field : 'httpMethod' , value : 123 } ,
268328 { field : 'httpMethod' , value : null } ,
329+ { field : 'httpMethod' , value : undefined } ,
269330 { field : 'path' , value : 123 } ,
270331 { field : 'path' , value : null } ,
332+ { field : 'path' , value : undefined } ,
271333 { field : 'resource' , value : 123 } ,
272334 { field : 'resource' , value : null } ,
335+ { field : 'resource' , value : undefined } ,
273336 { field : 'headers' , value : 'not an object' } ,
274- { field : 'headers' , value : null } ,
337+ { field : 'headers' , value : 123 } ,
338+ { field : 'multiValueHeaders' , value : 'not an object' } ,
339+ { field : 'multiValueHeaders' , value : 123 } ,
340+ { field : 'queryStringParameters' , value : 'not an object' } ,
341+ { field : 'queryStringParameters' , value : 123 } ,
342+ { field : 'multiValueQueryStringParameters' , value : 'not an object' } ,
343+ { field : 'multiValueQueryStringParameters' , value : 123 } ,
344+ { field : 'pathParameters' , value : 'not an object' } ,
345+ { field : 'pathParameters' , value : 123 } ,
346+ { field : 'stageVariables' , value : 'not an object' } ,
347+ { field : 'stageVariables' , value : 123 } ,
275348 { field : 'requestContext' , value : 'not an object' } ,
276349 { field : 'requestContext' , value : null } ,
350+ { field : 'requestContext' , value : undefined } ,
351+ { field : 'requestContext' , value : 123 } ,
277352 { field : 'isBase64Encoded' , value : 'not a boolean' } ,
278353 { field : 'isBase64Encoded' , value : null } ,
354+ { field : 'isBase64Encoded' , value : undefined } ,
355+ { field : 'isBase64Encoded' , value : 123 } ,
279356 { field : 'body' , value : 123 } ,
357+ { field : 'body' , value : { } } ,
280358 ] ) (
281359 'should return false when $field is invalid ($value)' ,
282360 ( { field, value } ) => {
283- const baseEvent = {
284- httpMethod : 'GET' ,
285- path : '/test' ,
286- resource : '/test' ,
287- headers : { } ,
288- requestContext : { } ,
289- isBase64Encoded : false ,
290- body : null ,
291- } ;
292-
293- const invalidEvent = { ...baseEvent , [ field ] : value } ;
361+ const invalidEvent = { ...baseValidEvent , [ field ] : value } ;
294362 expect ( isAPIGatewayProxyEvent ( invalidEvent ) ) . toBe ( false ) ;
295363 }
296364 ) ;
297365
298- it ( 'should return false when required fields are missing' , ( ) => {
299- const incompleteEvent = {
300- httpMethod : 'GET' ,
301- path : '/test' ,
302- // missing resource, headers, requestContext, isBase64Encoded, body
303- } ;
304-
366+ it . each ( [
367+ 'httpMethod' ,
368+ 'path' ,
369+ 'resource' ,
370+ 'requestContext' ,
371+ 'isBase64Encoded' ,
372+ ] ) ( 'should return false when required field %s is missing' , ( field ) => {
373+ const incompleteEvent = { ...baseValidEvent } ;
374+ delete incompleteEvent [ field as keyof typeof incompleteEvent ] ;
305375 expect ( isAPIGatewayProxyEvent ( incompleteEvent ) ) . toBe ( false ) ;
306376 } ) ;
307377 } ) ;
0 commit comments