Skip to content

Commit 3108ada

Browse files
committed
playwright tests
1 parent 3f3f3a3 commit 3108ada

File tree

21 files changed

+1810
-127
lines changed

21 files changed

+1810
-127
lines changed

infrastructure/terraform/modules/backend-api/spec.tmpl.json

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -196,13 +196,10 @@
196196
},
197197
{
198198
"$ref": "#/components/schemas/CascadeItemWithConditional"
199-
},
200-
{
201-
"$ref": "#/components/schemas/CascadeItemUnpopulated"
202199
}
203200
]
204201
},
205-
"CascadeItemUnpopulated": {
202+
"CascadeItemBase": {
206203
"properties": {
207204
"cascadeGroups": {
208205
"items": {
@@ -227,7 +224,7 @@
227224
"CascadeItemWithConditional": {
228225
"allOf": [
229226
{
230-
"$ref": "#/components/schemas/CascadeItemUnpopulated"
227+
"$ref": "#/components/schemas/CascadeItemBase"
231228
},
232229
{
233230
"not": {
@@ -260,7 +257,7 @@
260257
"CascadeItemWithDefault": {
261258
"allOf": [
262259
{
263-
"$ref": "#/components/schemas/CascadeItemUnpopulated"
260+
"$ref": "#/components/schemas/CascadeItemBase"
264261
},
265262
{
266263
"not": {
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import type { APIGatewayProxyEvent, Context } from 'aws-lambda';
2+
import { mock } from 'jest-mock-extended';
3+
import type { RoutingConfig } from 'nhs-notify-backend-client';
4+
import { createHandler } from '@backend-api/templates/api/submit-routing-config';
5+
import { RoutingConfigClient } from '@backend-api/templates/app/routing-config-client';
6+
import { routingConfig } from '../fixtures/routing-config';
7+
8+
const setup = () => {
9+
const routingConfigClient = mock<RoutingConfigClient>();
10+
const mocks = { routingConfigClient };
11+
const handler = createHandler(mocks);
12+
13+
return { handler, mocks };
14+
};
15+
16+
describe('Submit Routing Config Handler', () => {
17+
beforeEach(jest.resetAllMocks);
18+
19+
test.each([
20+
['undefined', undefined],
21+
['missing user', { clientId: 'client-id', user: undefined }],
22+
['missing client', { clientId: undefined, user: 'user-id' }],
23+
])(
24+
'should return 400 - Invalid request when requestContext is %s',
25+
async (_, ctx) => {
26+
const { handler, mocks } = setup();
27+
28+
const event = mock<APIGatewayProxyEvent>({
29+
requestContext: { authorizer: ctx },
30+
pathParameters: { templateId: 'id' },
31+
});
32+
33+
const result = await handler(event, mock<Context>(), jest.fn());
34+
35+
expect(result).toEqual({
36+
statusCode: 400,
37+
body: JSON.stringify({
38+
statusCode: 400,
39+
technicalMessage: 'Invalid request',
40+
}),
41+
});
42+
43+
expect(
44+
mocks.routingConfigClient.submitRoutingConfig
45+
).not.toHaveBeenCalled();
46+
}
47+
);
48+
49+
test('should return 400 - Invalid request when, no routingConfigId', async () => {
50+
const { handler, mocks } = setup();
51+
52+
const event = mock<APIGatewayProxyEvent>({
53+
requestContext: {
54+
authorizer: { user: 'sub', clientId: 'nhs-notify-client-id' },
55+
},
56+
body: JSON.stringify({ name: 'test' }),
57+
pathParameters: { routingConfigId: undefined },
58+
});
59+
60+
const result = await handler(event, mock<Context>(), jest.fn());
61+
62+
expect(result).toEqual({
63+
statusCode: 400,
64+
body: JSON.stringify({
65+
statusCode: 400,
66+
technicalMessage: 'Invalid request',
67+
}),
68+
});
69+
70+
expect(
71+
mocks.routingConfigClient.submitRoutingConfig
72+
).not.toHaveBeenCalled();
73+
});
74+
75+
test('should return error when submitting routing config fails', async () => {
76+
const { handler, mocks } = setup();
77+
78+
mocks.routingConfigClient.submitRoutingConfig.mockResolvedValueOnce({
79+
error: {
80+
errorMeta: {
81+
code: 500,
82+
description: 'Internal server error',
83+
},
84+
},
85+
});
86+
87+
const event = mock<APIGatewayProxyEvent>({
88+
requestContext: {
89+
authorizer: { user: 'sub', clientId: 'nhs-notify-client-id' },
90+
},
91+
pathParameters: { routingConfigId: '1-2-3' },
92+
});
93+
94+
const result = await handler(event, mock<Context>(), jest.fn());
95+
96+
expect(result).toEqual({
97+
statusCode: 500,
98+
body: JSON.stringify({
99+
statusCode: 500,
100+
technicalMessage: 'Internal server error',
101+
}),
102+
});
103+
104+
expect(mocks.routingConfigClient.submitRoutingConfig).toHaveBeenCalledWith(
105+
'1-2-3',
106+
{
107+
userId: 'sub',
108+
clientId: 'nhs-notify-client-id',
109+
}
110+
);
111+
});
112+
113+
test('should return completed routing config', async () => {
114+
const { handler, mocks } = setup();
115+
116+
const completed: RoutingConfig = { ...routingConfig, status: 'COMPLETED' };
117+
118+
mocks.routingConfigClient.submitRoutingConfig.mockResolvedValueOnce({
119+
data: completed,
120+
});
121+
122+
const event = mock<APIGatewayProxyEvent>({
123+
requestContext: {
124+
authorizer: { user: 'sub', clientId: 'nhs-notify-client-id' },
125+
},
126+
pathParameters: { routingConfigId: '1-2-3' },
127+
});
128+
129+
const result = await handler(event, mock<Context>(), jest.fn());
130+
131+
expect(result).toEqual({
132+
statusCode: 200,
133+
body: JSON.stringify({ statusCode: 200, data: completed }),
134+
});
135+
136+
expect(mocks.routingConfigClient.submitRoutingConfig).toHaveBeenCalledWith(
137+
'1-2-3',
138+
{
139+
userId: 'sub',
140+
clientId: 'nhs-notify-client-id',
141+
}
142+
);
143+
});
144+
});
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
import type { APIGatewayProxyEvent, Context } from 'aws-lambda';
2+
import { mock } from 'jest-mock-extended';
3+
import type {
4+
CreateUpdateRoutingConfig,
5+
RoutingConfig,
6+
} from 'nhs-notify-backend-client';
7+
import { createHandler } from '@backend-api/templates/api/update-routing-config';
8+
import { RoutingConfigClient } from '@backend-api/templates/app/routing-config-client';
9+
import { routingConfig } from '../fixtures/routing-config';
10+
11+
const setup = () => {
12+
const routingConfigClient = mock<RoutingConfigClient>();
13+
const mocks = { routingConfigClient };
14+
const handler = createHandler(mocks);
15+
16+
return { handler, mocks };
17+
};
18+
19+
describe('Update Routing Config Handler', () => {
20+
beforeEach(jest.resetAllMocks);
21+
22+
test.each([
23+
['undefined', undefined],
24+
['missing user', { clientId: 'client-id', user: undefined }],
25+
['missing client', { clientId: undefined, user: 'user-id' }],
26+
])(
27+
'should return 400 - Invalid request when requestContext is %s',
28+
async (_, ctx) => {
29+
const { handler, mocks } = setup();
30+
31+
const event = mock<APIGatewayProxyEvent>({
32+
requestContext: { authorizer: ctx },
33+
pathParameters: { templateId: 'id' },
34+
});
35+
36+
const result = await handler(event, mock<Context>(), jest.fn());
37+
38+
expect(result).toEqual({
39+
statusCode: 400,
40+
body: JSON.stringify({
41+
statusCode: 400,
42+
technicalMessage: 'Invalid request',
43+
}),
44+
});
45+
46+
expect(
47+
mocks.routingConfigClient.updateRoutingConfig
48+
).not.toHaveBeenCalled();
49+
}
50+
);
51+
52+
test('should return 400 - Invalid request when, no routingConfigId', async () => {
53+
const { handler, mocks } = setup();
54+
55+
const event = mock<APIGatewayProxyEvent>({
56+
requestContext: {
57+
authorizer: { user: 'sub', clientId: 'nhs-notify-client-id' },
58+
},
59+
body: JSON.stringify({ name: 'test' }),
60+
pathParameters: { routingConfigId: undefined },
61+
});
62+
63+
const result = await handler(event, mock<Context>(), jest.fn());
64+
65+
expect(result).toEqual({
66+
statusCode: 400,
67+
body: JSON.stringify({
68+
statusCode: 400,
69+
technicalMessage: 'Invalid request',
70+
}),
71+
});
72+
73+
expect(
74+
mocks.routingConfigClient.updateRoutingConfig
75+
).not.toHaveBeenCalled();
76+
});
77+
78+
test('body defaults to empty object when absent', async () => {
79+
const { handler, mocks } = setup();
80+
81+
const event = mock<APIGatewayProxyEvent>({
82+
requestContext: {
83+
authorizer: { user: 'sub', clientId: 'nhs-notify-client-id' },
84+
},
85+
body: undefined,
86+
pathParameters: { routingConfigId: 'id' },
87+
});
88+
89+
mocks.routingConfigClient.updateRoutingConfig.mockResolvedValueOnce({
90+
error: {
91+
errorMeta: {
92+
code: 400,
93+
description: 'Invalid request',
94+
},
95+
},
96+
});
97+
98+
const result = await handler(event, mock<Context>(), jest.fn());
99+
100+
expect(result).toEqual({
101+
statusCode: 400,
102+
body: JSON.stringify({
103+
statusCode: 400,
104+
technicalMessage: 'Invalid request',
105+
}),
106+
});
107+
108+
expect(mocks.routingConfigClient.updateRoutingConfig).toHaveBeenCalledWith(
109+
'id',
110+
{},
111+
{
112+
userId: 'sub',
113+
clientId: 'nhs-notify-client-id',
114+
}
115+
);
116+
});
117+
118+
test('should return error when updating routing config fails', async () => {
119+
const { handler, mocks } = setup();
120+
121+
const update: CreateUpdateRoutingConfig = {
122+
cascade: [
123+
{
124+
defaultTemplateId: 'id',
125+
channel: 'EMAIL',
126+
cascadeGroups: ['standard'],
127+
channelType: 'primary',
128+
},
129+
],
130+
cascadeGroupOverrides: [{ name: 'standard' }],
131+
campaignId: 'campaign',
132+
name: 'new name',
133+
};
134+
135+
mocks.routingConfigClient.updateRoutingConfig.mockResolvedValueOnce({
136+
error: {
137+
errorMeta: {
138+
code: 500,
139+
description: 'Internal server error',
140+
},
141+
},
142+
});
143+
144+
const event = mock<APIGatewayProxyEvent>({
145+
requestContext: {
146+
authorizer: { user: 'sub', clientId: 'nhs-notify-client-id' },
147+
},
148+
body: JSON.stringify(update),
149+
pathParameters: { routingConfigId: '1-2-3' },
150+
});
151+
152+
const result = await handler(event, mock<Context>(), jest.fn());
153+
154+
expect(result).toEqual({
155+
statusCode: 500,
156+
body: JSON.stringify({
157+
statusCode: 500,
158+
technicalMessage: 'Internal server error',
159+
}),
160+
});
161+
162+
expect(mocks.routingConfigClient.updateRoutingConfig).toHaveBeenCalledWith(
163+
'1-2-3',
164+
update,
165+
{
166+
userId: 'sub',
167+
clientId: 'nhs-notify-client-id',
168+
}
169+
);
170+
});
171+
172+
test('should return updated routing config', async () => {
173+
const { handler, mocks } = setup();
174+
175+
const update: CreateUpdateRoutingConfig = {
176+
cascade: [
177+
{
178+
defaultTemplateId: 'id',
179+
channel: 'EMAIL',
180+
cascadeGroups: ['standard'],
181+
channelType: 'primary',
182+
},
183+
],
184+
cascadeGroupOverrides: [{ name: 'standard' }],
185+
campaignId: 'campaign',
186+
name: 'new name',
187+
};
188+
189+
const updated: RoutingConfig = { ...routingConfig, ...update };
190+
191+
mocks.routingConfigClient.updateRoutingConfig.mockResolvedValueOnce({
192+
data: updated,
193+
});
194+
195+
const event = mock<APIGatewayProxyEvent>({
196+
requestContext: {
197+
authorizer: { user: 'sub', clientId: 'nhs-notify-client-id' },
198+
},
199+
body: JSON.stringify(update),
200+
pathParameters: { routingConfigId: '1-2-3' },
201+
});
202+
203+
const result = await handler(event, mock<Context>(), jest.fn());
204+
205+
expect(result).toEqual({
206+
statusCode: 200,
207+
body: JSON.stringify({ statusCode: 200, data: updated }),
208+
});
209+
210+
expect(mocks.routingConfigClient.updateRoutingConfig).toHaveBeenCalledWith(
211+
'1-2-3',
212+
update,
213+
{
214+
userId: 'sub',
215+
clientId: 'nhs-notify-client-id',
216+
}
217+
);
218+
});
219+
});

0 commit comments

Comments
 (0)