import { mockAwsS3 } from './mock' ; import { handler } from '../index' ; import { ImageHandlerError , ImageHandlerEvent , StatusCodes } from '../lib' ; describe ( 'index' , ( ) => { process . env . SOURCE_BUCKETS = 'source-bucket' ; const mockImage = Buffer . from ( 'SampleImageContent\n' ) ; const mockFallbackImage = Buffer . from ( 'SampleFallbackImageContent\n' ) ; describe ( 'TC: Success' , ( ) => { beforeEach ( ( ) => { mockAwsS3 . getObject . mockImplementationOnce ( ( ) => ( { promise ( ) { return Promise . resolve ( { Body : mockImage , ContentType : 'image/jpeg' } ) ; } } ) ) ; } ) ; it ( '001/should return the image when there is no error' , async ( ) => { const event = { path : '/test.jpg' } ; const result = await handler ( event ) ; const expectedResult = { statusCode : StatusCodes . OK , isBase64Encoded : true , headers : { 'Access-Control-Allow-Methods' : 'GET' , 'Access-Control-Allow-Headers' : 'Content-Type, Authorization' , 'Access-Control-Allow-Credentials' : true , 'Content-Type' : 'image/jpeg' , Expires : undefined , 'Cache-Control' : 'max-age=31536000,public' , 'Last-Modified' : undefined } , body : mockImage . toString ( 'base64' ) } ; expect ( mockAwsS3 . getObject ) . toHaveBeenCalledWith ( { Bucket : 'source-bucket' , Key : 'test.jpg' } ) ; expect ( result ) . toEqual ( expectedResult ) ; } ) ; it ( '002/should return the image with custom headers when custom headers are provided' , async ( ) => { const event = { path : '/eyJidWNrZXQiOiJzb3VyY2UtYnVja2V0Iiwia2V5IjoidGVzdC5qcGciLCJoZWFkZXJzIjp7IkN1c3RvbS1IZWFkZXIiOiJDdXN0b21WYWx1ZSJ9fQ==' } ; const result = await handler ( event ) ; const expectedResult = { statusCode : StatusCodes . OK , headers : { 'Access-Control-Allow-Methods' : 'GET' , 'Access-Control-Allow-Headers' : 'Content-Type, Authorization' , 'Access-Control-Allow-Credentials' : true , 'Content-Type' : 'image/jpeg' , Expires : undefined , 'Cache-Control' : 'max-age=31536000,public' , 'Last-Modified' : undefined , 'Custom-Header' : 'CustomValue' } , body : mockImage . toString ( 'base64' ) , isBase64Encoded : true } ; expect ( mockAwsS3 . getObject ) . toHaveBeenCalledWith ( { Bucket : 'source-bucket' , Key : 'test.jpg' } ) ; expect ( result ) . toEqual ( expectedResult ) ; } ) ; it ( '003/should return the image when the request is from ALB' , async ( ) => { const event = { path : '/test.jpg' , requestContext : { elb : { } } } ; const result = await handler ( event ) ; const expectedResult = { statusCode : StatusCodes . OK , isBase64Encoded : true , headers : { 'Access-Control-Allow-Methods' : 'GET' , 'Access-Control-Allow-Headers' : 'Content-Type, Authorization' , 'Content-Type' : 'image/jpeg' , Expires : undefined , 'Cache-Control' : 'max-age=31536000,public' , 'Last-Modified' : undefined } , body : mockImage . toString ( 'base64' ) } ; expect ( mockAwsS3 . getObject ) . toHaveBeenCalledWith ( { Bucket : 'source-bucket' , Key : 'test.jpg' } ) ; expect ( result ) . toEqual ( expectedResult ) ; } ) ; } ) ; describe ( 'TC: Error' , ( ) => { it ( '001/should return an error JSON when an error occurs' , async ( ) => { const event = { path : '/test.jpg' } ; mockAwsS3 . getObject . mockImplementationOnce ( ( ) => ( { promise ( ) { return Promise . reject ( new ImageHandlerError ( StatusCodes . NOT_FOUND , 'NoSuchKey' , 'NoSuchKey error happened.' ) ) ; } } ) ) ; const result = await handler ( event ) ; const expectedResult = { statusCode : StatusCodes . NOT_FOUND , isBase64Encoded : false , headers : { 'Access-Control-Allow-Methods' : 'GET' , 'Access-Control-Allow-Headers' : 'Content-Type, Authorization' , 'Access-Control-Allow-Credentials' : true , 'Content-Type' : 'application/json' } , body : JSON . stringify ( { status : StatusCodes . NOT_FOUND , code : 'NoSuchKey' , message : `The image test.jpg does not exist or the request may not be base64 encoded properly.` } ) } ; expect ( mockAwsS3 . getObject ) . toHaveBeenCalledWith ( { Bucket : 'source-bucket' , Key : 'test.jpg' } ) ; expect ( result ) . toEqual ( expectedResult ) ; } ) ; it ( '002/should return 500 error when there is no error status in the error' , async ( ) => { const event = { path : 'eyJidWNrZXQiOiJzb3VyY2UtYnVja2V0Iiwia2V5IjoidGVzdC5qcGciLCJlZGl0cyI6eyJ3cm9uZ0ZpbHRlciI6dHJ1ZX19' } ; mockAwsS3 . getObject . mockImplementationOnce ( ( ) => ( { promise ( ) { return Promise . resolve ( { Body : mockImage , ContentType : 'image/jpeg' } ) ; } } ) ) ; const result = await handler ( event ) ; const expectedResult = { statusCode : StatusCodes . INTERNAL_SERVER_ERROR , isBase64Encoded : false , headers : { 'Access-Control-Allow-Methods' : 'GET' , 'Access-Control-Allow-Headers' : 'Content-Type, Authorization' , 'Access-Control-Allow-Credentials' : true , 'Content-Type' : 'application/json' } , body : JSON . stringify ( { message : 'Internal error. Please contact the system administrator.' , code : 'InternalError' , status : StatusCodes . INTERNAL_SERVER_ERROR } ) } ; expect ( mockAwsS3 . getObject ) . toHaveBeenCalledWith ( { Bucket : 'source-bucket' , Key : 'test.jpg' } ) ; expect ( result ) . toEqual ( expectedResult ) ; } ) ; it ( '003/should return the default fallback image when an error occurs if the default fallback image is enabled' , async ( ) => { process . env . ENABLE_DEFAULT_FALLBACK_IMAGE = 'Yes' ; process . env . DEFAULT_FALLBACK_IMAGE_BUCKET = 'fallback-image-bucket' ; process . env . DEFAULT_FALLBACK_IMAGE_KEY = 'fallback-image.png' ; process . env . CORS_ENABLED = 'Yes' ; process . env . CORS_ORIGIN = '*' ; const event = { path : '/test.jpg' } ; mockAwsS3 . getObject . mockReset ( ) ; mockAwsS3 . getObject . mockImplementationOnce ( ( ) => ( { promise ( ) { return Promise . reject ( new ImageHandlerError ( StatusCodes . INTERNAL_SERVER_ERROR , 'UnknownError' , null ) ) ; } } ) ) . mockImplementationOnce ( ( ) => ( { promise ( ) { return Promise . resolve ( { Body : mockFallbackImage , ContentType : 'image/png' } ) ; } } ) ) ; const result = await handler ( event ) ; const expectedResult = { statusCode : StatusCodes . INTERNAL_SERVER_ERROR , isBase64Encoded : true , headers : { 'Access-Control-Allow-Methods' : 'GET' , 'Access-Control-Allow-Headers' : 'Content-Type, Authorization' , 'Access-Control-Allow-Credentials' : true , 'Access-Control-Allow-Origin' : '*' , 'Content-Type' : 'image/png' , 'Cache-Control' : 'max-age=31536000,public' , 'Last-Modified' : undefined } , body : mockFallbackImage . toString ( 'base64' ) } ; expect ( mockAwsS3 . getObject ) . toHaveBeenNthCalledWith ( 1 , { Bucket : 'source-bucket' , Key : 'test.jpg' } ) ; expect ( mockAwsS3 . getObject ) . toHaveBeenNthCalledWith ( 2 , { Bucket : 'fallback-image-bucket' , Key : 'fallback-image.png' } ) ; expect ( result ) . toEqual ( expectedResult ) ; } ) ; it ( '004/should return an error JSON when getting the default fallback image fails if the default fallback image is enabled' , async ( ) => { const event = { path : '/test.jpg' } ; mockAwsS3 . getObject . mockReset ( ) ; mockAwsS3 . getObject . mockImplementation ( ( ) => ( { promise ( ) { return Promise . reject ( new ImageHandlerError ( StatusCodes . NOT_FOUND , 'NoSuchKey' , 'NoSuchKey error happened.' ) ) ; } } ) ) ; const result = await handler ( event ) ; const expectedResult = { statusCode : StatusCodes . NOT_FOUND , isBase64Encoded : false , headers : { 'Access-Control-Allow-Methods' : 'GET' , 'Access-Control-Allow-Headers' : 'Content-Type, Authorization' , 'Access-Control-Allow-Credentials' : true , 'Access-Control-Allow-Origin' : '*' , 'Content-Type' : 'application/json' } , body : JSON . stringify ( { status : StatusCodes . NOT_FOUND , code : 'NoSuchKey' , message : `The image test.jpg does not exist or the request may not be base64 encoded properly.` } ) } ; expect ( mockAwsS3 . getObject ) . toHaveBeenNthCalledWith ( 1 , { Bucket : 'source-bucket' , Key : 'test.jpg' } ) ; expect ( mockAwsS3 . getObject ) . toHaveBeenNthCalledWith ( 2 , { Bucket : 'fallback-image-bucket' , Key : 'fallback-image.png' } ) ; expect ( result ) . toEqual ( expectedResult ) ; } ) ; it ( '005/should return an error JSON when the default fallback image key is not provided if the default fallback image is enabled' , async ( ) => { process . env . DEFAULT_FALLBACK_IMAGE_KEY = '' ; const event = { path : '/test.jpg' } ; mockAwsS3 . getObject . mockImplementationOnce ( ( ) => ( { promise ( ) { return Promise . reject ( new ImageHandlerError ( StatusCodes . NOT_FOUND , 'NoSuchKey' , 'NoSuchKey error happened.' ) ) ; } } ) ) ; const result = await handler ( event ) ; const expectedResult = { statusCode : StatusCodes . NOT_FOUND , isBase64Encoded : false , headers : { 'Access-Control-Allow-Methods' : 'GET' , 'Access-Control-Allow-Headers' : 'Content-Type, Authorization' , 'Access-Control-Allow-Credentials' : true , 'Access-Control-Allow-Origin' : '*' , 'Content-Type' : 'application/json' } , body : JSON . stringify ( { status : StatusCodes . NOT_FOUND , code : 'NoSuchKey' , message : `The image test.jpg does not exist or the request may not be base64 encoded properly.` } ) } ; expect ( mockAwsS3 . getObject ) . toHaveBeenCalledWith ( { Bucket : 'source-bucket' , Key : 'test.jpg' } ) ; expect ( result ) . toEqual ( expectedResult ) ; } ) ; it ( '006/should return an error JSON when the default fallback image bucket is not provided if the default fallback image is enabled' , async ( ) => { process . env . DEFAULT_FALLBACK_IMAGE_BUCKET = '' ; const event = { path : '/test.jpg' } ; mockAwsS3 . getObject . mockImplementationOnce ( ( ) => ( { promise ( ) { return Promise . reject ( new ImageHandlerError ( StatusCodes . NOT_FOUND , 'NoSuchKey' , 'NoSuchKey error happened.' ) ) ; } } ) ) ; const result = await handler ( event ) ; const expectedResult = { statusCode : StatusCodes . NOT_FOUND , isBase64Encoded : false , headers : { 'Access-Control-Allow-Methods' : 'GET' , 'Access-Control-Allow-Headers' : 'Content-Type, Authorization' , 'Access-Control-Allow-Credentials' : true , 'Access-Control-Allow-Origin' : '*' , 'Content-Type' : 'application/json' } , body : JSON . stringify ( { status : StatusCodes . NOT_FOUND , code : 'NoSuchKey' , message : `The image test.jpg does not exist or the request may not be base64 encoded properly.` } ) } ; expect ( mockAwsS3 . getObject ) . toHaveBeenCalledWith ( { Bucket : 'source-bucket' , Key : 'test.jpg' } ) ; expect ( result ) . toEqual ( expectedResult ) ; } ) ; } ) ; it ( '007/should return an error JSON when ALB request is failed' , async ( ) => { const event = { path : '/test.jpg' , requestContext : { elb : { } } } ; mockAwsS3 . getObject . mockImplementationOnce ( ( ) => ( { promise ( ) { return Promise . reject ( new ImageHandlerError ( StatusCodes . NOT_FOUND , 'NoSuchKey' , 'NoSuchKey error happened.' ) ) ; } } ) ) ; const result = await handler ( event ) ; const expectedResult = { statusCode : StatusCodes . NOT_FOUND , isBase64Encoded : false , headers : { 'Access-Control-Allow-Methods' : 'GET' , 'Access-Control-Allow-Headers' : 'Content-Type, Authorization' , 'Access-Control-Allow-Origin' : '*' , 'Content-Type' : 'application/json' } , body : JSON . stringify ( { status : StatusCodes . NOT_FOUND , code : 'NoSuchKey' , message : `The image test.jpg does not exist or the request may not be base64 encoded properly.` } ) } ; expect ( mockAwsS3 . getObject ) . toHaveBeenCalledWith ( { Bucket : 'source-bucket' , Key : 'test.jpg' } ) ; expect ( result ) . toEqual ( expectedResult ) ; } ) ; } ) ;