generated from ministryofjustice/hmpps-template-typescript
-
Notifications
You must be signed in to change notification settings - Fork 0
/
baseClientController.test.ts
397 lines (328 loc) · 16.7 KB
/
baseClientController.test.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
import type { DeepMocked } from '@golevelup/ts-jest'
import { createMock } from '@golevelup/ts-jest'
import type { NextFunction, Request, Response } from 'express'
import BaseClientController from './baseClientController'
import { BaseClientService } from '../services'
import { baseClientFactory, clientFactory, clientSecretsFactory } from '../testutils/factories'
import listBaseClientsPresenter from '../views/presenters/listBaseClientsPresenter'
import createUserToken from '../testutils/createUserToken'
import viewBaseClientPresenter from '../views/presenters/viewBaseClientPresenter'
import nunjucksUtils from '../views/helpers/nunjucksUtils'
import editBaseClientPresenter from '../views/presenters/editBaseClientPresenter'
describe('BaseClientController', () => {
const token = createUserToken(['ADMIN'])
let request: DeepMocked<Request>
let response: DeepMocked<Response>
const next: DeepMocked<NextFunction> = createMock<NextFunction>({})
let baseClientService = createMock<BaseClientService>({})
let baseClientController: BaseClientController
beforeEach(() => {
request = createMock<Request>()
response = createMock<Response>({
locals: {
clientToken: 'CLIENT_TOKEN',
user: {
token,
authSource: 'auth',
},
},
render: jest.fn(),
redirect: jest.fn(),
})
baseClientService = createMock<BaseClientService>({})
baseClientController = new BaseClientController(baseClientService)
})
describe('displayBaseClients', () => {
it('renders the list index template with a list of base clients', async () => {
// GIVEN a list of base clients
const baseClients = baseClientFactory.buildList(3)
baseClientService.listBaseClients.mockResolvedValue(baseClients)
// WHEN the index page is requested
await baseClientController.displayBaseClients()(request, response, next)
// THEN the list of base clients is rendered
const presenter = listBaseClientsPresenter(baseClients)
expect(response.render).toHaveBeenCalledWith('pages/base-clients.njk', {
presenter,
})
// AND the list of base clients is retrieved from the base client service
expect(baseClientService.listBaseClients).toHaveBeenCalledWith(token)
})
})
describe('view base client', () => {
it('renders the main view of a base clients', async () => {
// GIVEN a list of base clients
const baseClient = baseClientFactory.build()
const clients = clientFactory.buildList(3)
baseClientService.getBaseClient.mockResolvedValue(baseClient)
baseClientService.listClientInstances.mockResolvedValue(clients)
// WHEN the index page is requested
request = createMock<Request>({ params: { baseClientId: baseClient.baseClientId } })
await baseClientController.displayBaseClient()(request, response, next)
// THEN the view base client page is rendered
const presenter = viewBaseClientPresenter(baseClient, clients)
expect(response.render).toHaveBeenCalledWith('pages/base-client.njk', {
baseClient,
presenter,
...nunjucksUtils,
})
// AND the base client is retrieved from the base client service
expect(baseClientService.getBaseClient).toHaveBeenCalledWith(token, baseClient.baseClientId)
})
})
describe('create base client', () => {
describe('journey', () => {
it('if grant is not specified as parameter renders the select grant screen', async () => {
// GIVEN a request without grant parameter
request = createMock<Request>({ query: {} })
// WHEN the create base client page is requested
await baseClientController.displayNewBaseClient()(request, response, next)
// THEN the choose client type page is rendered
expect(response.render).toHaveBeenCalledWith('pages/new-base-client-grant.njk')
})
it('if grant is specified with client-credentials renders the details screen', async () => {
// GIVEN a request with grant="client-credentials" parameter
request = createMock<Request>({ query: { grant: 'client-credentials' } })
// WHEN the create base client page is requested
await baseClientController.displayNewBaseClient()(request, response, next)
// THEN the enter client details page is rendered with client credentials selected
expect(response.render).toHaveBeenCalledWith('pages/new-base-client-details.njk', {
grant: 'client-credentials',
...nunjucksUtils,
})
})
it('if grant is specified with authorization-code renders the details screen', async () => {
// GIVEN a request with grant="authorization-code" parameter
request = createMock<Request>({ query: { grant: 'authorization-code' } })
// WHEN the create base client page is requested
await baseClientController.displayNewBaseClient()(request, response, next)
// THEN the enter client details page is rendered with authorisation code selected
expect(response.render).toHaveBeenCalledWith('pages/new-base-client-details.njk', {
grant: 'authorization-code',
...nunjucksUtils,
})
})
it('if grant is specified as random parameter renders the select grant screen', async () => {
// GIVEN a request without grant parameter
request = createMock<Request>({ query: { grant: 'xxxyyy' } })
// WHEN the create base client page is requested
await baseClientController.displayNewBaseClient()(request, response, next)
// THEN the choose client type page is rendered
expect(response.render).toHaveBeenCalledWith('pages/new-base-client-grant.njk')
})
it('if validation fails because no id specified renders the details screen with error message', async () => {
// GIVEN no id is specified
request = createMock<Request>({ body: {} })
// WHEN it is posted
await baseClientController.createBaseClient()(request, response, next)
// THEN the new base client page is rendered with error message
const expectedError = 'This field is required'
expect(response.render).toHaveBeenCalledWith(
'pages/new-base-client-details.njk',
expect.objectContaining({ errorMessage: { text: expectedError } }),
)
})
it('if validation fails because id exists then render the details screen with error message', async () => {
// GIVEN base client with id already exists
baseClientService.getBaseClient.mockResolvedValue(baseClientFactory.build())
baseClientService.listClientInstances.mockResolvedValue(clientFactory.buildList(3))
request = createMock<Request>({ body: { baseClientId: 'abcd' } })
// WHEN it is posted
await baseClientController.createBaseClient()(request, response, next)
// THEN the new base client page is rendered with error message
const expectedError = 'A base client with this ID already exists'
expect(response.render).toHaveBeenCalledWith(
'pages/new-base-client-details.njk',
expect.objectContaining({ errorMessage: { text: expectedError } }),
)
})
it('if success renders the secrets screen', async () => {
// GIVEN the service returns success and a set of secrets
baseClientService.getBaseClient.mockRejectedValue({ status: 404 })
request = createMock<Request>({ body: { baseClientId: 'abcd' } })
const secrets = clientSecretsFactory.build()
baseClientService.addBaseClient.mockResolvedValue(secrets)
// WHEN it is posted
await baseClientController.createBaseClient()(request, response, next)
// THEN the new base client success page is rendered
expect(response.render).toHaveBeenCalledWith(
'pages/new-base-client-success.njk',
expect.objectContaining({ secrets }),
)
})
})
})
describe('update base client details', () => {
it('displays update base client details screen', async () => {
// GIVEN a request to edit a base client
const baseClient = baseClientFactory.build()
baseClientService.getBaseClient.mockResolvedValue(baseClient)
request = createMock<Request>({ params: { baseClientId: baseClient.baseClientId } })
// WHEN the edit base client details page is requested
await baseClientController.displayEditBaseClient()(request, response, next)
// THEN the base client is retrieved from the base client service
expect(baseClientService.getBaseClient).toHaveBeenCalledWith(token, baseClient.baseClientId)
// AND the page is rendered
const presenter = editBaseClientPresenter(baseClient)
expect(response.render).toHaveBeenCalledWith('pages/edit-base-client-details.njk', {
baseClient,
presenter,
...nunjucksUtils,
})
})
it('updates and redirects to view base client screen', async () => {
// GIVEN the service will return without an error
const baseClient = baseClientFactory.build()
request = createMock<Request>({
params: { baseClientId: baseClient.baseClientId },
body: { baseClientId: baseClient.baseClientId },
})
baseClientService.updateBaseClient.mockResolvedValue(new Response())
// WHEN it is posted
await baseClientController.updateBaseClientDetails()(request, response, next)
// THEN the base client service is updated
expect(baseClientService.updateBaseClient).toHaveBeenCalled()
// AND the user is redirected to the view base client page
expect(response.redirect).toHaveBeenCalledWith(`/base-clients/${baseClient.baseClientId}`)
})
})
describe('update base client deployment', () => {
it('displays update base client deployment screen', async () => {
// GIVEN a request to edit base client deployment
const baseClient = baseClientFactory.build()
baseClientService.getBaseClient.mockResolvedValue(baseClient)
request = createMock<Request>({ params: { baseClientId: baseClient.baseClientId } })
// WHEN the edit base client details page is requested
await baseClientController.displayEditBaseClientDeployment()(request, response, next)
// THEN the base client is retrieved from the base client service
expect(baseClientService.getBaseClient).toHaveBeenCalledWith(token, baseClient.baseClientId)
// AND the page is rendered
expect(response.render).toHaveBeenCalledWith('pages/edit-base-client-deployment.njk', {
baseClient,
})
})
it('updates and redirects to view base client screen', async () => {
// GIVEN the service will return without an error
const baseClient = baseClientFactory.build()
request = createMock<Request>({
params: { baseClientId: baseClient.baseClientId },
body: { baseClientId: baseClient.baseClientId },
})
baseClientService.updateBaseClientDeployment.mockResolvedValue(new Response())
// WHEN it is posted
await baseClientController.updateBaseClientDeployment()(request, response, next)
// THEN the base client service is updated
expect(baseClientService.updateBaseClientDeployment).toHaveBeenCalled()
// AND the user is redirected to the view base client page
expect(response.redirect).toHaveBeenCalledWith(`/base-clients/${baseClient.baseClientId}`)
})
})
describe('create client instance', () => {
it('if success renders the secrets screen', async () => {
// GIVEN the service returns success and a set of secrets
const baseClient = baseClientFactory.build()
baseClientService.getBaseClient.mockResolvedValue(baseClient)
request = createMock<Request>({ body: { baseClientId: baseClient.baseClientId } })
const secrets = clientSecretsFactory.build()
baseClientService.addClientInstance.mockResolvedValue(secrets)
// WHEN it is posted
await baseClientController.createClientInstance()(request, response, next)
// THEN the new base client success page is rendered
expect(response.render).toHaveBeenCalledWith(
'pages/new-base-client-success.njk',
expect.objectContaining({ secrets }),
)
})
})
describe('delete client instance', () => {
it.each([
['renders one client instance', 1, true],
['renders multiple client instances', 3, false],
])(`if %s renders the page with isLastClient %s`, async (_, clientCount, isLastClient) => {
// GIVEN a base client
const baseClient = baseClientFactory.build()
const clients = clientFactory.buildList(clientCount)
const client = clients[0]
baseClientService.getBaseClient.mockResolvedValue(baseClient)
baseClientService.listClientInstances.mockResolvedValue(clients)
// WHEN the index page is requested
request = createMock<Request>({ params: { baseClientId: baseClient.baseClientId, clientId: client.clientId } })
await baseClientController.displayDeleteClientInstance()(request, response, next)
// THEN the view base client page is rendered with isLastClient true
expect(response.render).toHaveBeenCalledWith('pages/delete-client-instance.njk', {
baseClient,
clientId: client.clientId,
isLastClient,
error: null,
})
// AND the base client is retrieved from the base client service
expect(baseClientService.getBaseClient).toHaveBeenCalledWith(token, baseClient.baseClientId)
// AND the clients are retrieved from the base client service
expect(baseClientService.listClientInstances).toHaveBeenCalledWith(token, baseClient)
})
it(`renders the page with error`, async () => {
// GIVEN a base client
const baseClient = baseClientFactory.build()
const clients = clientFactory.buildList(3)
const client = clients[0]
baseClientService.getBaseClient.mockResolvedValue(baseClient)
baseClientService.listClientInstances.mockResolvedValue(clients)
const errorCode = 'clientIdMismatch'
// WHEN the index page is requested
request = createMock<Request>({
params: { baseClientId: baseClient.baseClientId, clientId: client.clientId },
query: { error: errorCode },
})
await baseClientController.displayDeleteClientInstance()(request, response, next)
// THEN the view base client page is rendered with error
const expectedError = 'Client ID does not match'
expect(response.render).toHaveBeenCalledWith('pages/delete-client-instance.njk', {
baseClient,
clientId: client.clientId,
isLastClient: false,
error: expectedError,
})
})
describe(`delete the client instance`, () => {
it.each([
['one client instance exists', '/', 1],
['multiple client instances', '/base-clients/abcd', 3],
])(`if delete successful and %s, redirects to %s`, async (_, redirectURL, clientCount) => {
// GIVEN a base client
const baseClient = baseClientFactory.build({ baseClientId: 'abcd' })
const clients = clientFactory.buildList(clientCount)
const client = clients[0]
baseClientService.getBaseClient.mockResolvedValue(baseClient)
baseClientService.listClientInstances.mockResolvedValue(clients)
// WHEN a delete request is made
request = createMock<Request>({
params: { baseClientId: baseClient.baseClientId, clientId: client.clientId },
query: { error: null },
body: { confirm: client.clientId },
})
await baseClientController.deleteClientInstance()(request, response, next)
// THEN the client instance is deleted
expect(baseClientService.deleteClientInstance).toHaveBeenCalledWith(token, client)
// AND the user is redirected
expect(response.redirect).toHaveBeenCalledWith(redirectURL)
})
it(`if client does not match, redirects with error`, async () => {
// GIVEN a base client
const baseClient = baseClientFactory.build({ baseClientId: 'abcd' })
const clients = clientFactory.buildList(3)
const client = clients[0]
baseClientService.getBaseClient.mockResolvedValue(baseClient)
baseClientService.listClientInstances.mockResolvedValue(clients)
// WHEN a delete request is made
request = createMock<Request>({
params: { baseClientId: baseClient.baseClientId, clientId: client.clientId },
query: { error: null },
body: { confirm: 'something incorrect' },
})
await baseClientController.deleteClientInstance()(request, response, next)
// THEN the user is redirected with error
const expectedURL = `/base-clients/${baseClient.baseClientId}/clients/${client.clientId}/delete?error=clientIdMismatch`
expect(response.redirect).toHaveBeenCalledWith(expectedURL)
})
})
})
})