1- import { createHandler } from 'apis/sqs-handler' ;
2- import { Logger } from 'utils' ;
3- import { SQSEvent , SQSRecord } from 'aws-lambda' ;
41import { mock } from 'jest-mock-extended' ;
2+ import { randomUUID } from 'node:crypto' ;
3+ import { createHandler } from 'apis/sqs-handler' ;
4+ import { EventPublisher , Logger } from 'utils' ;
5+ import { Pdm } from 'app/pdm' ;
6+ import {
7+ pdmResourceSubmittedEvent ,
8+ pdmResourceUnavailableEvent ,
9+ recordEvent ,
10+ } from '__tests__/test-data' ;
511
612const logger = mock < Logger > ( ) ;
13+ const eventPublisher = mock < EventPublisher > ( ) ;
14+ const pdm = mock < Pdm > ( ) ;
15+
16+ jest . mock ( 'node:crypto' , ( ) => ( {
17+ randomUUID : jest . fn ( ) ,
18+ } ) ) ;
719
8- const event = {
9- sourceEventId : 'test-event-id' ,
10- } ;
11-
12- const sqsRecord1 : SQSRecord = {
13- messageId : '1' ,
14- receiptHandle : 'abc' ,
15- body : JSON . stringify ( event ) ,
16- attributes : {
17- ApproximateReceiveCount : '1' ,
18- SentTimestamp : '2025-07-03T14:23:30Z' ,
19- SenderId : 'sender-id' ,
20- ApproximateFirstReceiveTimestamp : '2025-07-03T14:23:30Z' ,
21- } ,
22- messageAttributes : { } ,
23- md5OfBody : '' ,
24- eventSource : 'aws:sqs' ,
25- eventSourceARN : '' ,
26- awsRegion : '' ,
27- } ;
28-
29- const singleRecordEvent : SQSEvent = {
30- Records : [ sqsRecord1 ] ,
31- } ;
20+ const mockRandomUUID = randomUUID as jest . MockedFunction < typeof randomUUID > ;
21+ const mockDate = jest . spyOn ( Date . prototype , 'toISOString' ) ;
22+ mockRandomUUID . mockReturnValue ( '550e8400-e29b-41d4-a716-446655440001' ) ;
23+ mockDate . mockReturnValue ( '2023-06-20T12:00:00.250Z' ) ;
3224
3325const handler = createHandler ( {
26+ eventPublisher,
27+ pdm,
3428 logger,
3529} ) ;
3630
@@ -39,35 +33,169 @@ describe('SQS Handler', () => {
3933 jest . clearAllMocks ( ) ;
4034 } ) ;
4135
42- it ( 'processes a single record' , async ( ) => {
43- const response = await handler ( singleRecordEvent ) ;
36+ describe ( 'pdm.resource.submitted' , ( ) => {
37+ it ( 'should send pdm.resource.available event when the document is ready' , async ( ) => {
38+ pdm . poll . mockResolvedValueOnce ( 'available' ) ;
39+
40+ const response = await handler ( recordEvent ( [ pdmResourceSubmittedEvent ] ) ) ;
41+
42+ expect ( eventPublisher . sendEvents ) . toHaveBeenCalledWith ( [
43+ {
44+ ...pdmResourceSubmittedEvent ,
45+ id : '550e8400-e29b-41d4-a716-446655440001' ,
46+ time : '2023-06-20T12:00:00.250Z' ,
47+ recordedtime : '2023-06-20T12:00:00.250Z' ,
48+ type : 'uk.nhs.notify.digital.letters.pdm.resource.available.v1' ,
49+ } ,
50+ ] ) ;
51+ expect ( logger . info ) . toHaveBeenCalledWith (
52+ 'Received SQS Event of 1 record(s)' ,
53+ ) ;
54+ expect ( logger . info ) . toHaveBeenCalledWith (
55+ '1 of 1 records processed successfully' ,
56+ ) ;
57+ expect ( response ) . toEqual ( { batchItemFailures : [ ] } ) ;
58+ } ) ;
4459
45- expect ( logger . info ) . toHaveBeenCalledWith (
46- 'Received SQS Event of 1 record(s)' ,
47- ) ;
48- expect ( logger . info ) . toHaveBeenCalledWith (
49- '1 of 1 records processed successfully' ,
50- ) ;
51- expect ( response ) . toEqual ( { batchItemFailures : [ ] } ) ;
60+ it ( 'should send pdm.resource.unavailable event when the document is not ready' , async ( ) => {
61+ pdm . poll . mockResolvedValueOnce ( 'unavailable' ) ;
62+
63+ const response = await handler ( recordEvent ( [ pdmResourceSubmittedEvent ] ) ) ;
64+
65+ expect ( eventPublisher . sendEvents ) . toHaveBeenCalledWith ( [
66+ {
67+ ...pdmResourceSubmittedEvent ,
68+ id : '550e8400-e29b-41d4-a716-446655440001' ,
69+ time : '2023-06-20T12:00:00.250Z' ,
70+ recordedtime : '2023-06-20T12:00:00.250Z' ,
71+ type : 'uk.nhs.notify.digital.letters.pdm.resource.unavailable.v1' ,
72+ data : {
73+ ...pdmResourceSubmittedEvent . data ,
74+ retryCount : 1 ,
75+ } ,
76+ } ,
77+ ] ) ;
78+ expect ( logger . info ) . toHaveBeenCalledWith (
79+ 'Received SQS Event of 1 record(s)' ,
80+ ) ;
81+ expect ( logger . info ) . toHaveBeenCalledWith (
82+ '1 of 1 records processed successfully' ,
83+ ) ;
84+ expect ( response ) . toEqual ( { batchItemFailures : [ ] } ) ;
85+ } ) ;
5286 } ) ;
5387
54- it ( 'should return failed items to the queue if an error occurs while processing them' , async ( ) => {
55- singleRecordEvent . Records [ 0 ] . body = 'not-json' ;
88+ describe ( 'pdm.resource.unavailable' , ( ) => {
89+ it ( 'should send pdm.resource.available event when the document is ready' , async ( ) => {
90+ pdm . poll . mockResolvedValueOnce ( 'available' ) ;
91+
92+ const response = await handler (
93+ recordEvent ( [ pdmResourceUnavailableEvent ] ) ,
94+ ) ;
95+
96+ expect ( eventPublisher . sendEvents ) . toHaveBeenCalledWith ( [
97+ {
98+ ...pdmResourceUnavailableEvent ,
99+ id : '550e8400-e29b-41d4-a716-446655440001' ,
100+ time : '2023-06-20T12:00:00.250Z' ,
101+ recordedtime : '2023-06-20T12:00:00.250Z' ,
102+ type : 'uk.nhs.notify.digital.letters.pdm.resource.available.v1' ,
103+ } ,
104+ ] ) ;
105+ expect ( logger . info ) . toHaveBeenCalledWith (
106+ 'Received SQS Event of 1 record(s)' ,
107+ ) ;
108+ expect ( logger . info ) . toHaveBeenCalledWith (
109+ '1 of 1 records processed successfully' ,
110+ ) ;
111+ expect ( response ) . toEqual ( { batchItemFailures : [ ] } ) ;
112+ } ) ;
113+
114+ it ( 'should send pdm.resource.unavailable event when the document is not ready' , async ( ) => {
115+ pdm . poll . mockResolvedValueOnce ( 'unavailable' ) ;
56116
57- const result = await handler ( singleRecordEvent ) ;
117+ const response = await handler (
118+ recordEvent ( [ pdmResourceUnavailableEvent ] ) ,
119+ ) ;
58120
59- expect ( logger . warn ) . toHaveBeenCalledWith ( {
60- error : `Unexpected token 'o', "not-json" is not valid JSON` ,
61- description : 'Failed processing message' ,
62- messageId : '1' ,
121+ expect ( eventPublisher . sendEvents ) . toHaveBeenCalledWith ( [
122+ {
123+ ...pdmResourceUnavailableEvent ,
124+ id : '550e8400-e29b-41d4-a716-446655440001' ,
125+ time : '2023-06-20T12:00:00.250Z' ,
126+ recordedtime : '2023-06-20T12:00:00.250Z' ,
127+ type : 'uk.nhs.notify.digital.letters.pdm.resource.unavailable.v1' ,
128+ data : {
129+ ...pdmResourceSubmittedEvent . data ,
130+ retryCount : 2 ,
131+ } ,
132+ } ,
133+ ] ) ;
134+ expect ( logger . info ) . toHaveBeenCalledWith (
135+ 'Received SQS Event of 1 record(s)' ,
136+ ) ;
137+ expect ( logger . info ) . toHaveBeenCalledWith (
138+ '1 of 1 records processed successfully' ,
139+ ) ;
140+ expect ( response ) . toEqual ( { batchItemFailures : [ ] } ) ;
63141 } ) ;
64142
65- expect ( logger . info ) . toHaveBeenCalledWith (
66- '0 of 1 records processed successfully' ,
67- ) ;
143+ it ( 'should send pdm.resource.retries.exceeded event when the document is not ready after 10 retries' , async ( ) => {
144+ pdm . poll . mockResolvedValueOnce ( 'unavailable' ) ;
145+
146+ const testEvent = {
147+ ...pdmResourceUnavailableEvent ,
148+ data : {
149+ ...pdmResourceUnavailableEvent . data ,
150+ retryCount : 9 ,
151+ } ,
152+ } ;
153+
154+ const response = await handler ( recordEvent ( [ testEvent ] ) ) ;
155+
156+ expect ( eventPublisher . sendEvents ) . toHaveBeenCalledWith ( [
157+ {
158+ ...pdmResourceUnavailableEvent ,
159+ id : '550e8400-e29b-41d4-a716-446655440001' ,
160+ time : '2023-06-20T12:00:00.250Z' ,
161+ recordedtime : '2023-06-20T12:00:00.250Z' ,
162+ type : 'uk.nhs.notify.digital.letters.pdm.resource.retries.exceeded.v1' ,
163+ data : {
164+ ...pdmResourceSubmittedEvent . data ,
165+ retryCount : 10 ,
166+ } ,
167+ } ,
168+ ] ) ;
169+ expect ( logger . info ) . toHaveBeenCalledWith (
170+ 'Received SQS Event of 1 record(s)' ,
171+ ) ;
172+ expect ( logger . info ) . toHaveBeenCalledWith (
173+ '1 of 1 records processed successfully' ,
174+ ) ;
175+ expect ( response ) . toEqual ( { batchItemFailures : [ ] } ) ;
176+ } ) ;
177+ } ) ;
178+
179+ describe ( 'errors' , ( ) => {
180+ it ( 'should return failed items to the queue if an error occurs while processing them' , async ( ) => {
181+ const event = recordEvent ( [ pdmResourceSubmittedEvent ] ) ;
182+ event . Records [ 0 ] . body = 'not-json' ;
183+
184+ const result = await handler ( event ) ;
185+
186+ expect ( logger . warn ) . toHaveBeenCalledWith ( {
187+ error : `Unexpected token 'o', "not-json" is not valid JSON` ,
188+ description : 'Failed processing message' ,
189+ messageId : '1' ,
190+ } ) ;
191+
192+ expect ( logger . info ) . toHaveBeenCalledWith (
193+ '0 of 1 records processed successfully' ,
194+ ) ;
68195
69- expect ( result ) . toEqual ( {
70- batchItemFailures : [ { itemIdentifier : '1' } ] ,
196+ expect ( result ) . toEqual ( {
197+ batchItemFailures : [ { itemIdentifier : '1' } ] ,
198+ } ) ;
71199 } ) ;
72200 } ) ;
73201} ) ;
0 commit comments