1+ import { handler } from './index' ;
2+ import { S3 } from 'aws-sdk' ;
3+ import { APIGatewayProxyEvent } from 'aws-lambda' ;
4+ import { Request , AWSError , Response } from 'aws-sdk/lib/core' ;
5+ import { PromiseResult } from 'aws-sdk/lib/request' ;
6+
7+ interface MockS3Response < T > extends Request < T , AWSError > {
8+ promise : ( ) => Promise < PromiseResult < T , AWSError > > ;
9+ }
10+
11+ jest . mock ( 'aws-sdk' , ( ) => {
12+ const mockS3 = {
13+ getObject : jest . fn ( ) ,
14+ putObject : jest . fn ( )
15+ } ;
16+ return {
17+ S3 : jest . fn ( ( ) => mockS3 )
18+ } ;
19+ } ) ;
20+
21+ describe ( 'NewsPassID Lambda Handler' , ( ) => {
22+ const mockS3 = new S3 ( ) as jest . Mocked < S3 > ;
23+
24+ beforeEach ( ( ) => {
25+ jest . clearAllMocks ( ) ;
26+ process . env . STORAGE_BUCKET = 'test-bucket' ;
27+ process . env . ID_FOLDER = 'newspassid' ;
28+ } ) ;
29+
30+ it ( 'should process valid request and return success' , async ( ) => {
31+ // Mock S3 responses
32+ mockS3 . getObject . mockReturnValue ( {
33+ promise : ( ) => Promise . resolve ( {
34+ Body : Buffer . from ( 'segments,expire_timestamp\nsegment1,9999999999999' ) ,
35+ $response : { } as Response < S3 . GetObjectOutput , AWSError >
36+ } )
37+ } as MockS3Response < S3 . GetObjectOutput > ) ;
38+ mockS3 . putObject . mockReturnValue ( {
39+ promise : ( ) => Promise . resolve ( {
40+ $response : { } as Response < S3 . PutObjectOutput , AWSError >
41+ } )
42+ } as MockS3Response < S3 . PutObjectOutput > ) ;
43+
44+ const event : Partial < APIGatewayProxyEvent > = {
45+ body : JSON . stringify ( {
46+ id : 'publisher-123' ,
47+ timestamp : 1234567890 ,
48+ url : 'https://example.com' ,
49+ consentString : 'consent123' ,
50+ previousId : 'publisher-122' ,
51+ publisherSegments : [ 'seg1' , 'seg2' ]
52+ } ) ,
53+ headers : {
54+ origin : 'https://example.com'
55+ }
56+ } ;
57+
58+ const response = await handler ( event as APIGatewayProxyEvent ) ;
59+ expect ( response . statusCode ) . toBe ( 200 ) ;
60+ expect ( JSON . parse ( response . body ) ) . toEqual ( {
61+ success : true ,
62+ id : 'publisher-123' ,
63+ segments : [ 'segment1' ]
64+ } ) ;
65+
66+ // Verify S3 calls
67+ expect ( mockS3 . putObject ) . toHaveBeenCalledTimes ( 2 ) ;
68+ expect ( mockS3 . putObject ) . toHaveBeenCalledWith (
69+ expect . objectContaining ( {
70+ Bucket : 'test-bucket' ,
71+ Key : 'newspassid/publisher/example.com/publisher-123/1234567890.csv' ,
72+ ContentType : 'text/csv'
73+ } )
74+ ) ;
75+ } ) ;
76+
77+ it ( 'should handle missing required fields' , async ( ) => {
78+ const event : Partial < APIGatewayProxyEvent > = {
79+ body : JSON . stringify ( {
80+ id : 'publisher-123' ,
81+ timestamp : 1234567890
82+ // Missing url and consentString
83+ } )
84+ } ;
85+
86+ const response = await handler ( event as APIGatewayProxyEvent ) ;
87+ expect ( response . statusCode ) . toBe ( 400 ) ;
88+ expect ( JSON . parse ( response . body ) ) . toEqual ( {
89+ success : false ,
90+ error : 'Missing required fields. All requests must include id, timestamp, url, and consentString.'
91+ } ) ;
92+ } ) ;
93+
94+ it ( 'should handle invalid ID format' , async ( ) => {
95+ const event : Partial < APIGatewayProxyEvent > = {
96+ body : JSON . stringify ( {
97+ id : 'invalid-id-without-publisher-prefix' ,
98+ timestamp : 1234567890 ,
99+ url : 'https://example.com' ,
100+ consentString : 'consent123'
101+ } )
102+ } ;
103+
104+ const response = await handler ( event as APIGatewayProxyEvent ) ;
105+ expect ( response . statusCode ) . toBe ( 400 ) ;
106+ expect ( JSON . parse ( response . body ) ) . toEqual ( {
107+ success : false ,
108+ error : 'Invalid ID format'
109+ } ) ;
110+ } ) ;
111+
112+ it ( 'should handle S3 errors gracefully' , async ( ) => {
113+ mockS3 . getObject . mockReturnValue ( {
114+ promise : ( ) => Promise . reject ( new Error ( 'S3 Error' ) )
115+ } as MockS3Response < S3 . GetObjectOutput > ) ;
116+
117+ const event : Partial < APIGatewayProxyEvent > = {
118+ body : JSON . stringify ( {
119+ id : 'publisher-123' ,
120+ timestamp : 1234567890 ,
121+ url : 'https://example.com' ,
122+ consentString : 'consent123'
123+ } )
124+ } ;
125+
126+ const response = await handler ( event as APIGatewayProxyEvent ) ;
127+ expect ( response . statusCode ) . toBe ( 500 ) ;
128+ expect ( JSON . parse ( response . body ) ) . toEqual ( {
129+ success : false ,
130+ error : 'Internal server error'
131+ } ) ;
132+ } ) ;
133+ } ) ;
0 commit comments