Skip to content

Commit 54e6a83

Browse files
Adding tests
1 parent f114b63 commit 54e6a83

File tree

10 files changed

+610
-54
lines changed

10 files changed

+610
-54
lines changed

lambdas/core-notifier/src/__tests__/app/notify-api-client.test.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type { Logger } from 'utils';
1010
import { mockRequest1, mockResponse } from '__tests__/constants';
1111
import { IAccessTokenRepository, NotifyClient } from 'app/notify-api-client';
1212
import { RequestAlreadyReceivedError } from 'domain/request-already-received-error';
13+
import { RequestNotifyError } from 'domain/request-notify-error';
1314

1415
jest.mock('utils');
1516
jest.mock('node:crypto');
@@ -214,7 +215,28 @@ describe('sendRequest', () => {
214215

215216
const error = {
216217
isAxiosError: true,
217-
response: { status },
218+
response: {
219+
status,
220+
data: {
221+
errors: [
222+
{
223+
id: 'rrt-1931948104716186917-c-geu2-10664-3111479-3.0',
224+
code: 'CM_MISSING_ROUTING_PLAN_TEMPLATE',
225+
links: {
226+
about:
227+
'https://digital.nhs.uk/developer/api-catalogue/nhs-notify',
228+
},
229+
status,
230+
title: 'Templates missing',
231+
detail:
232+
'The templates required to use the routing plan were not found.',
233+
source: {
234+
pointer: '/data/attributes/routingPlanId',
235+
},
236+
},
237+
],
238+
},
239+
},
218240
};
219241

220242
mocks.axiosInstance.post.mockRejectedValue(error);
@@ -224,7 +246,10 @@ describe('sendRequest', () => {
224246
mockRequest1,
225247
mockRequest1.data.attributes.messageReference,
226248
),
227-
).rejects.toEqual(error);
249+
).rejects.toMatchObject({
250+
errorCode: 'CM_MISSING_ROUTING_PLAN_TEMPLATE',
251+
correlationId: 'request-item-id_request-item-plan-id',
252+
});
228253
},
229254
);
230255

lambdas/core-notifier/src/__tests__/app/notify-message-processor.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ describe('NotifyMessageProcessor', () => {
2424
it('completes when the API client succeeds', async () => {
2525
mockClient.sendRequest.mockResolvedValueOnce(mockResponse);
2626

27-
expect(await notifyMessageProcessor.process(mockRequest1)).toBeUndefined();
27+
expect(await notifyMessageProcessor.process(mockRequest1)).toEqual(
28+
mockResponse.data.id,
29+
);
2830

2931
expect(mockClient.sendRequest).toHaveBeenCalledTimes(1);
3032
expect(mockClient.sendRequest).toHaveBeenCalledWith(
Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
import { Sender, logger } from 'utils';
2+
import {
3+
mapPdmEventToMessageRequestRejected,
4+
mapPdmEventToMessageRequestSkipped,
5+
mapPdmEventToMessageRequestSubmitted,
6+
mapPdmEventToSingleMessageRequest,
7+
} from 'domain/mapper';
8+
import { PDMResourceAvailable } from 'digital-letters-events';
9+
import { randomUUID } from 'node:crypto';
10+
11+
jest.mock('utils');
12+
jest.mock('node:crypto');
13+
14+
const mockLogger = jest.mocked(logger);
15+
const mockRandomUUID = jest.mocked(randomUUID);
16+
17+
describe('mapper', () => {
18+
const mockSender: Sender = {
19+
senderId: 'test-sender-id',
20+
senderName: 'Test Sender',
21+
meshMailboxSenderId: 'mesh-sender',
22+
meshMailboxReportsId: 'mesh-reports',
23+
fallbackWaitTimeSeconds: 300,
24+
routingConfigId: 'routing-config-123',
25+
};
26+
27+
const mockPdmEvent: PDMResourceAvailable = {
28+
specversion: '1.0',
29+
id: 'event-123',
30+
source: 'pdm-service',
31+
subject: 'resource/available',
32+
type: 'uk.nhs.notify.digital.letters.pdm.resource.available.v1',
33+
time: '2024-01-15T10:30:00Z',
34+
datacontenttype: 'application/json',
35+
dataschema:
36+
'https://notify.nhs.uk/cloudevents/schemas/digital-letters/2025-10-draft/data/digital-letters-pdm-resource-available-data.schema.json',
37+
data: {
38+
messageReference: 'msg-ref-123',
39+
senderId: 'sender-456',
40+
resourceId: 'resource-789',
41+
nhsNumber: '9999999999',
42+
odsCode: 'ODS123',
43+
},
44+
traceparent: '00-trace-parent',
45+
recordedtime: '2024-01-15T10:30:00Z',
46+
severitynumber: 2,
47+
};
48+
49+
beforeEach(() => {
50+
jest.clearAllMocks();
51+
mockRandomUUID.mockReturnValue('mock-uuid-123');
52+
});
53+
54+
describe('mapPdmEventToSingleMessageRequest', () => {
55+
it('correctly maps PDM event to single message request', () => {
56+
const result = mapPdmEventToSingleMessageRequest(
57+
mockPdmEvent,
58+
mockSender,
59+
);
60+
61+
expect(result).toEqual({
62+
data: {
63+
type: 'Message',
64+
attributes: {
65+
routingPlanId: 'routing-config-123',
66+
messageReference: 'msg-ref-123',
67+
billingReference: 'test-sender-id',
68+
recipient: {
69+
nhsNumber: '9999999999',
70+
},
71+
originator: {
72+
odsCode: 'ODS123',
73+
},
74+
personalisation: {
75+
digitalLetterURL:
76+
'https://www.nhsapp.service.nhs.uk/digital-letters?letterid=resource-789',
77+
},
78+
},
79+
},
80+
});
81+
82+
expect(mockLogger.info).toHaveBeenCalledWith(
83+
'Mapping resource available with reference: msg-ref-123 for sender: test-sender-id',
84+
);
85+
});
86+
});
87+
88+
describe('mapPdmEventToMessageRequestSubmitted', () => {
89+
it('correctly maps PDM event to MessageRequestSubmitted', () => {
90+
const notifyId = 'notify-123';
91+
const mockDate = new Date('2024-01-15T12:00:00Z');
92+
jest.spyOn(globalThis, 'Date').mockImplementation(() => mockDate as any);
93+
94+
const result = mapPdmEventToMessageRequestSubmitted(
95+
mockPdmEvent,
96+
mockSender,
97+
notifyId,
98+
);
99+
100+
expect(result).toEqual({
101+
...mockPdmEvent,
102+
id: 'mock-uuid-123',
103+
time: '2024-01-15T12:00:00.000Z',
104+
recordedtime: '2024-01-15T12:00:00.000Z',
105+
type: 'uk.nhs.notify.digital.letters.messages.request.submitted.v1',
106+
dataschema:
107+
'https://notify.nhs.uk/cloudevents/schemas/digital-letters/2025-10-draft/data/digital-letters-message-request-submitted-data.schema.json',
108+
data: {
109+
messageReference: 'msg-ref-123',
110+
senderId: 'test-sender-id',
111+
notifyId: 'notify-123',
112+
messageUri:
113+
'https://www.nhsapp.service.nhs.uk/digital-letters?letterid=resource-789',
114+
},
115+
});
116+
117+
expect(mockRandomUUID).toHaveBeenCalledTimes(1);
118+
});
119+
});
120+
121+
describe('mapPdmEventToMessageRequestSkipped', () => {
122+
it('correctly maps PDM event to MessageRequestSkipped', () => {
123+
const mockDate = new Date('2024-01-15T12:00:00Z');
124+
jest.spyOn(globalThis, 'Date').mockImplementation(() => mockDate as any);
125+
126+
const result = mapPdmEventToMessageRequestSkipped(
127+
mockPdmEvent,
128+
mockSender,
129+
);
130+
131+
expect(result).toEqual({
132+
...mockPdmEvent,
133+
id: 'mock-uuid-123',
134+
time: '2024-01-15T12:00:00.000Z',
135+
recordedtime: '2024-01-15T12:00:00.000Z',
136+
type: 'uk.nhs.notify.digital.letters.messages.request.skipped.v1',
137+
dataschema:
138+
'https://notify.nhs.uk/cloudevents/schemas/digital-letters/2025-10-draft/data/digital-letters-message-request-skipped-data.schema.json',
139+
data: {
140+
messageReference: 'msg-ref-123',
141+
senderId: 'test-sender-id',
142+
},
143+
});
144+
145+
expect(mockRandomUUID).toHaveBeenCalled();
146+
});
147+
148+
it('generates new UUID for event', () => {
149+
mapPdmEventToMessageRequestSkipped(mockPdmEvent, mockSender);
150+
151+
expect(mockRandomUUID).toHaveBeenCalledTimes(1);
152+
});
153+
154+
it('includes messageReference in data', () => {
155+
const result = mapPdmEventToMessageRequestSkipped(
156+
mockPdmEvent,
157+
mockSender,
158+
);
159+
160+
expect(result.data.messageReference).toBe('msg-ref-123');
161+
});
162+
163+
it('uses sender senderId in data', () => {
164+
const result = mapPdmEventToMessageRequestSkipped(
165+
mockPdmEvent,
166+
mockSender,
167+
);
168+
169+
expect(result.data.senderId).toBe('test-sender-id');
170+
});
171+
172+
it('sets correct event type', () => {
173+
const result = mapPdmEventToMessageRequestSkipped(
174+
mockPdmEvent,
175+
mockSender,
176+
);
177+
178+
expect(result.type).toBe(
179+
'uk.nhs.notify.digital.letters.messages.request.skipped.v1',
180+
);
181+
});
182+
183+
it('sets correct dataschema', () => {
184+
const result = mapPdmEventToMessageRequestSkipped(
185+
mockPdmEvent,
186+
mockSender,
187+
);
188+
189+
expect(result.dataschema).toBe(
190+
'https://notify.nhs.uk/cloudevents/schemas/digital-letters/2025-10-draft/data/digital-letters-message-request-skipped-data.schema.json',
191+
);
192+
});
193+
194+
it('preserves CloudEvents properties from PDM event', () => {
195+
const result = mapPdmEventToMessageRequestSkipped(
196+
mockPdmEvent,
197+
mockSender,
198+
);
199+
200+
expect(result.specversion).toBe('1.0');
201+
expect(result.source).toBe('pdm-service');
202+
expect(result.subject).toBe('resource/available');
203+
expect(result.traceparent).toBe('00-trace-parent');
204+
});
205+
});
206+
207+
describe('mapPdmEventToMessageRequestRejected', () => {
208+
it('correctly maps PDM event to MessageRequestRejected', () => {
209+
const failureCode = 'INVALID_NHS_NUMBER';
210+
const mockDate = new Date('2024-01-15T12:00:00Z');
211+
jest.spyOn(globalThis, 'Date').mockImplementation(() => mockDate as any);
212+
213+
const result = mapPdmEventToMessageRequestRejected(
214+
mockPdmEvent,
215+
mockSender,
216+
failureCode,
217+
);
218+
219+
expect(result).toEqual({
220+
...mockPdmEvent,
221+
id: 'mock-uuid-123',
222+
time: '2024-01-15T12:00:00.000Z',
223+
recordedtime: '2024-01-15T12:00:00.000Z',
224+
type: 'uk.nhs.notify.digital.letters.messages.request.rejected.v1',
225+
dataschema:
226+
'https://notify.nhs.uk/cloudevents/schemas/digital-letters/2025-10-draft/data/digital-letters-message-request-rejected-data.schema.json',
227+
data: {
228+
messageReference: 'msg-ref-123',
229+
senderId: 'test-sender-id',
230+
failureCode: 'INVALID_NHS_NUMBER',
231+
messageUri:
232+
'https://www.nhsapp.service.nhs.uk/digital-letters?letterid=resource-789',
233+
},
234+
});
235+
236+
expect(mockRandomUUID).toHaveBeenCalled();
237+
});
238+
239+
it('generates new UUID for event', () => {
240+
const failureCode = 'VALIDATION_ERROR';
241+
mapPdmEventToMessageRequestRejected(
242+
mockPdmEvent,
243+
mockSender,
244+
failureCode,
245+
);
246+
247+
expect(mockRandomUUID).toHaveBeenCalledTimes(1);
248+
});
249+
250+
it('includes failureCode in data', () => {
251+
const failureCode = 'ROUTING_FAILED';
252+
const result = mapPdmEventToMessageRequestRejected(
253+
mockPdmEvent,
254+
mockSender,
255+
failureCode,
256+
);
257+
258+
expect(result.data.failureCode).toBe('ROUTING_FAILED');
259+
});
260+
261+
it('includes messageUri with resource ID', () => {
262+
const failureCode = 'TIMEOUT';
263+
const result = mapPdmEventToMessageRequestRejected(
264+
mockPdmEvent,
265+
mockSender,
266+
failureCode,
267+
);
268+
269+
expect(result.data.messageUri).toBe(
270+
'https://www.nhsapp.service.nhs.uk/digital-letters?letterid=resource-789',
271+
);
272+
});
273+
274+
it('uses sender senderId in data', () => {
275+
const failureCode = 'UNKNOWN_ERROR';
276+
const result = mapPdmEventToMessageRequestRejected(
277+
mockPdmEvent,
278+
mockSender,
279+
failureCode,
280+
);
281+
282+
expect(result.data.senderId).toBe('test-sender-id');
283+
});
284+
285+
it('uses messageReference from PDM event', () => {
286+
const failureCode = 'DUPLICATE_REQUEST';
287+
const result = mapPdmEventToMessageRequestRejected(
288+
mockPdmEvent,
289+
mockSender,
290+
failureCode,
291+
);
292+
293+
expect(result.data.messageReference).toBe('msg-ref-123');
294+
});
295+
296+
it('sets correct event type', () => {
297+
const failureCode = 'SYSTEM_ERROR';
298+
const result = mapPdmEventToMessageRequestRejected(
299+
mockPdmEvent,
300+
mockSender,
301+
failureCode,
302+
);
303+
304+
expect(result.type).toBe(
305+
'uk.nhs.notify.digital.letters.messages.request.rejected.v1',
306+
);
307+
});
308+
309+
it('sets correct dataschema', () => {
310+
const failureCode = 'CONFIG_ERROR';
311+
const result = mapPdmEventToMessageRequestRejected(
312+
mockPdmEvent,
313+
mockSender,
314+
failureCode,
315+
);
316+
317+
expect(result.dataschema).toBe(
318+
'https://notify.nhs.uk/cloudevents/schemas/digital-letters/2025-10-draft/data/digital-letters-message-request-rejected-data.schema.json',
319+
);
320+
});
321+
322+
it('preserves CloudEvents properties from PDM event', () => {
323+
const failureCode = 'NETWORK_ERROR';
324+
const result = mapPdmEventToMessageRequestRejected(
325+
mockPdmEvent,
326+
mockSender,
327+
failureCode,
328+
);
329+
330+
expect(result.specversion).toBe('1.0');
331+
expect(result.source).toBe('pdm-service');
332+
expect(result.subject).toBe('resource/available');
333+
expect(result.traceparent).toBe('00-trace-parent');
334+
});
335+
});
336+
});

0 commit comments

Comments
 (0)