@defra/lis-infra-ui-services 0.23.0-lreg-665.alpha.1 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -2
- package/src/errors/index.js +6 -1
- package/src/errors/index.test.js +38 -3
- package/src/nunjucks/context.js +3 -3
- package/src/nunjucks/context.test.js +0 -22
- package/src/nunjucks/plugin.js +0 -11
- package/src/nunjucks/plugin.test.js +1 -24
- package/src/nunjucks/routes/error/error-pages.test.js +31 -0
- package/src/nunjucks/routes/error/not-authorised.njk +3 -0
- package/src/nunjucks/routes/error/page-not-found.njk +3 -0
- package/src/nunjucks/routes/error/problem-with-service.njk +3 -0
- package/src/nunjucks/routes/error/service-unavailable.njk +3 -0
- package/src/navigation.js +0 -1
- package/src/nunjucks/build-navigation.js +0 -61
- package/src/nunjucks/build-navigation.test.js +0 -62
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defra/lis-infra-ui-services",
|
|
3
|
-
"version": "0.23.0
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "UI-Services shared definitions for the livestock taxonomy topology.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
"./duration": "./src/duration.js",
|
|
20
20
|
"./errors": "./src/errors/index.js",
|
|
21
21
|
"./maintenance": "./src/maintenance.js",
|
|
22
|
-
"./navigation": "./src/navigation.js",
|
|
23
22
|
"./nunjucks/build-navigation": "./src/nunjucks/build-navigation.js",
|
|
24
23
|
"./nunjucks/context": "./src/nunjucks/context.js",
|
|
25
24
|
"./nunjucks/filters": "./src/nunjucks/filters.js",
|
package/src/errors/index.js
CHANGED
|
@@ -58,5 +58,10 @@ export function catchAll(request, h) {
|
|
|
58
58
|
return h.continue
|
|
59
59
|
}
|
|
60
60
|
const { view, pageTitle } = errorPageFor(statusCode)
|
|
61
|
-
|
|
61
|
+
const developmentMessage =
|
|
62
|
+
process.env.NODE_ENV === 'development'
|
|
63
|
+
? (response?.message ?? response?.source?.message)
|
|
64
|
+
: undefined
|
|
65
|
+
|
|
66
|
+
return h.view(view, { pageTitle, developmentMessage }).code(statusCode)
|
|
62
67
|
}
|
package/src/errors/index.test.js
CHANGED
|
@@ -83,7 +83,10 @@ test.each([
|
|
|
83
83
|
catchAll(request, toolkit)
|
|
84
84
|
|
|
85
85
|
// Assert
|
|
86
|
-
assert.deepEqual(toolkit.view.mock.calls[0], [
|
|
86
|
+
assert.deepEqual(toolkit.view.mock.calls[0], [
|
|
87
|
+
view,
|
|
88
|
+
{ pageTitle, developmentMessage: undefined }
|
|
89
|
+
])
|
|
87
90
|
assert.deepEqual(toolkit.code.mock.calls[0], [statusCode])
|
|
88
91
|
}
|
|
89
92
|
)
|
|
@@ -100,7 +103,8 @@ test('catchAll logs server errors and renders the problem with the service page'
|
|
|
100
103
|
assert.deepEqual(toolkit.view.mock.calls[0], [
|
|
101
104
|
'error/problem-with-service',
|
|
102
105
|
{
|
|
103
|
-
pageTitle: 'Sorry, there is a problem with the service'
|
|
106
|
+
pageTitle: 'Sorry, there is a problem with the service',
|
|
107
|
+
developmentMessage: undefined
|
|
104
108
|
}
|
|
105
109
|
])
|
|
106
110
|
assert.deepEqual(toolkit.code.mock.calls[0], [
|
|
@@ -139,12 +143,43 @@ test('catchAll prefers a client-attached statusCode over a boomified 500', () =>
|
|
|
139
143
|
// Assert
|
|
140
144
|
assert.deepEqual(toolkit.view.mock.calls[0], [
|
|
141
145
|
'error/page-not-found',
|
|
142
|
-
{ pageTitle: 'Page not found' }
|
|
146
|
+
{ pageTitle: 'Page not found', developmentMessage: undefined }
|
|
143
147
|
])
|
|
144
148
|
assert.deepEqual(toolkit.code.mock.calls[0], [statusCodes.notFound])
|
|
145
149
|
assert.equal(logger.error.mock.calls.length, 0)
|
|
146
150
|
})
|
|
147
151
|
|
|
152
|
+
test("catchAll passes the error's own message to the page in development", () => {
|
|
153
|
+
// Arrange
|
|
154
|
+
vi.stubEnv('NODE_ENV', 'development')
|
|
155
|
+
const request = createBoomRequest(statusCodes.internalServerError)
|
|
156
|
+
request.response.message = 'Upstream timed out'
|
|
157
|
+
const toolkit = createToolkit()
|
|
158
|
+
|
|
159
|
+
// Act
|
|
160
|
+
catchAll(request, toolkit)
|
|
161
|
+
|
|
162
|
+
// Assert
|
|
163
|
+
assert.equal(
|
|
164
|
+
toolkit.view.mock.calls[0][1].developmentMessage,
|
|
165
|
+
'Upstream timed out'
|
|
166
|
+
)
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
test("catchAll leaves out the error's own message outside development", () => {
|
|
170
|
+
// Arrange
|
|
171
|
+
vi.stubEnv('NODE_ENV', 'production')
|
|
172
|
+
const request = createBoomRequest(statusCodes.internalServerError)
|
|
173
|
+
request.response.message = 'Upstream timed out'
|
|
174
|
+
const toolkit = createToolkit()
|
|
175
|
+
|
|
176
|
+
// Act
|
|
177
|
+
catchAll(request, toolkit)
|
|
178
|
+
|
|
179
|
+
// Assert
|
|
180
|
+
assert.equal(toolkit.view.mock.calls[0][1].developmentMessage, undefined)
|
|
181
|
+
})
|
|
182
|
+
|
|
148
183
|
test('catchAll does not log the 503 the maintenance plugin answered with', () => {
|
|
149
184
|
// Arrange
|
|
150
185
|
const toolkit = createToolkit()
|
package/src/nunjucks/context.js
CHANGED
|
@@ -57,12 +57,11 @@ function createPermissionCheck(request) {
|
|
|
57
57
|
*/
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
|
-
* @param {{ config: object,
|
|
60
|
+
* @param {{ config: object, getRequestBasePath: Function, logger: object, readFileSync: Function, moduleId?: string, errorPages?: ErrorPageLinks }} options
|
|
61
61
|
* @returns {Function}
|
|
62
62
|
*/
|
|
63
63
|
export function createNunjucksContextBuilder({
|
|
64
64
|
config,
|
|
65
|
-
buildNavigation,
|
|
66
65
|
getRequestBasePath,
|
|
67
66
|
logger,
|
|
68
67
|
readFileSync,
|
|
@@ -106,7 +105,8 @@ export function createNunjucksContextBuilder({
|
|
|
106
105
|
sectionName,
|
|
107
106
|
serviceUrl: '/',
|
|
108
107
|
breadcrumbs: [],
|
|
109
|
-
navigation:
|
|
108
|
+
// No primary navigation links for now: only the service name and Sign out.
|
|
109
|
+
navigation: [],
|
|
110
110
|
isSignedIn: Boolean(request?.auth?.credentials?.user),
|
|
111
111
|
isFrontOffice: requestHubId === 'front-office',
|
|
112
112
|
isBackOffice: requestHubId === 'back-office',
|
|
@@ -23,7 +23,6 @@ test('createNunjucksContextBuilder resolves built asset paths from the Vite mani
|
|
|
23
23
|
const loggerMessages = []
|
|
24
24
|
const contextBuilder = createNunjucksContextBuilder({
|
|
25
25
|
config: createConfig(),
|
|
26
|
-
buildNavigation: () => [],
|
|
27
26
|
getRequestBasePath: () => '',
|
|
28
27
|
logger: {
|
|
29
28
|
error(loggedError, message) {
|
|
@@ -52,7 +51,6 @@ test('createNunjucksContextBuilder falls back to the source asset path without l
|
|
|
52
51
|
const loggerMessages = []
|
|
53
52
|
const contextBuilder = createNunjucksContextBuilder({
|
|
54
53
|
config: createConfig(),
|
|
55
|
-
buildNavigation: () => [],
|
|
56
54
|
getRequestBasePath: () => '',
|
|
57
55
|
logger: {
|
|
58
56
|
error(loggedError, message) {
|
|
@@ -77,7 +75,6 @@ test('createNunjucksContextBuilder resolves sectionName from the module registry
|
|
|
77
75
|
const loggerMessages = []
|
|
78
76
|
const contextBuilder = createNunjucksContextBuilder({
|
|
79
77
|
config: createConfig(),
|
|
80
|
-
buildNavigation: () => [],
|
|
81
78
|
getRequestBasePath: () => '',
|
|
82
79
|
logger: {
|
|
83
80
|
error(loggedError, message) {
|
|
@@ -98,7 +95,6 @@ test('createNunjucksContextBuilder leaves sectionName null when no moduleId is g
|
|
|
98
95
|
const loggerMessages = []
|
|
99
96
|
const contextBuilder = createNunjucksContextBuilder({
|
|
100
97
|
config: createConfig(),
|
|
101
|
-
buildNavigation: () => [],
|
|
102
98
|
getRequestBasePath: () => '',
|
|
103
99
|
logger: {
|
|
104
100
|
error(loggedError, message) {
|
|
@@ -118,7 +114,6 @@ test('createNunjucksContextBuilder logs once when the Vite manifest is unavailab
|
|
|
118
114
|
const loggerMessages = []
|
|
119
115
|
const contextBuilder = createNunjucksContextBuilder({
|
|
120
116
|
config: createConfig({ isProduction: true }),
|
|
121
|
-
buildNavigation: () => [],
|
|
122
117
|
getRequestBasePath: () => '',
|
|
123
118
|
logger: {
|
|
124
119
|
error(loggedError, message) {
|
|
@@ -143,7 +138,6 @@ test('createNunjucksContextBuilder always sets serviceUrl to the hub root even w
|
|
|
143
138
|
const loggerMessages = []
|
|
144
139
|
const contextBuilder = createNunjucksContextBuilder({
|
|
145
140
|
config: createConfig(),
|
|
146
|
-
buildNavigation: () => [],
|
|
147
141
|
getRequestBasePath: () => '/cattle/register',
|
|
148
142
|
logger: {
|
|
149
143
|
error(loggedError, message) {
|
|
@@ -169,7 +163,6 @@ test('createNunjucksContextBuilder always sets serviceUrl to the hub root even w
|
|
|
169
163
|
function createSignedInContextBuilder() {
|
|
170
164
|
return createNunjucksContextBuilder({
|
|
171
165
|
config: createConfig(),
|
|
172
|
-
buildNavigation: () => [],
|
|
173
166
|
getRequestBasePath: () => '',
|
|
174
167
|
logger: { error: () => undefined },
|
|
175
168
|
readFileSync: () => '{}'
|
|
@@ -213,7 +206,6 @@ describe('createNunjucksContextBuilder() hub flags', () => {
|
|
|
213
206
|
// Arrange
|
|
214
207
|
const contextBuilder = createNunjucksContextBuilder({
|
|
215
208
|
config: createConfig(),
|
|
216
|
-
buildNavigation: () => [],
|
|
217
209
|
getRequestBasePath: () => '',
|
|
218
210
|
logger: {},
|
|
219
211
|
readFileSync: () => '{}',
|
|
@@ -237,7 +229,6 @@ describe('createNunjucksContextBuilder() hub flags', () => {
|
|
|
237
229
|
// Arrange
|
|
238
230
|
const contextBuilder = createNunjucksContextBuilder({
|
|
239
231
|
config: createConfig(),
|
|
240
|
-
buildNavigation: () => [],
|
|
241
232
|
getRequestBasePath: () => '',
|
|
242
233
|
logger: {},
|
|
243
234
|
readFileSync: () => '{}',
|
|
@@ -261,7 +252,6 @@ describe('createNunjucksContextBuilder() hub flags', () => {
|
|
|
261
252
|
// Arrange
|
|
262
253
|
const contextBuilder = createNunjucksContextBuilder({
|
|
263
254
|
config: createConfig(),
|
|
264
|
-
buildNavigation: () => [],
|
|
265
255
|
getRequestBasePath: () => '',
|
|
266
256
|
logger: {},
|
|
267
257
|
readFileSync: () => '{}',
|
|
@@ -281,7 +271,6 @@ describe('createNunjucksContextBuilder() hub flags', () => {
|
|
|
281
271
|
// Arrange
|
|
282
272
|
const contextBuilder = createNunjucksContextBuilder({
|
|
283
273
|
config: createConfig(),
|
|
284
|
-
buildNavigation: () => [],
|
|
285
274
|
getRequestBasePath: () => '',
|
|
286
275
|
logger: {},
|
|
287
276
|
readFileSync: () => '{}',
|
|
@@ -307,7 +296,6 @@ describe('createNunjucksContextBuilder() errorPages', () => {
|
|
|
307
296
|
// Arrange
|
|
308
297
|
const contextBuilder = createNunjucksContextBuilder({
|
|
309
298
|
config: createConfig(),
|
|
310
|
-
buildNavigation: () => [],
|
|
311
299
|
getRequestBasePath: () => '',
|
|
312
300
|
logger: {},
|
|
313
301
|
readFileSync: () => '{}'
|
|
@@ -330,7 +318,6 @@ describe('createNunjucksContextBuilder() errorPages', () => {
|
|
|
330
318
|
// Arrange
|
|
331
319
|
const contextBuilder = createNunjucksContextBuilder({
|
|
332
320
|
config: createConfig(),
|
|
333
|
-
buildNavigation: () => [],
|
|
334
321
|
getRequestBasePath: () => '',
|
|
335
322
|
logger: {},
|
|
336
323
|
readFileSync: () => '{}',
|
|
@@ -357,7 +344,6 @@ describe('createNunjucksContextBuilder() errorPages', () => {
|
|
|
357
344
|
// Arrange
|
|
358
345
|
const contextBuilder = createNunjucksContextBuilder({
|
|
359
346
|
config: createConfig(),
|
|
360
|
-
buildNavigation: () => [],
|
|
361
347
|
getRequestBasePath: () => '',
|
|
362
348
|
logger: {},
|
|
363
349
|
readFileSync: () => '{}',
|
|
@@ -383,7 +369,6 @@ describe('createNunjucksContextBuilder() hasPermission()', () => {
|
|
|
383
369
|
// Arrange
|
|
384
370
|
const contextBuilder = createNunjucksContextBuilder({
|
|
385
371
|
config: createConfig(),
|
|
386
|
-
buildNavigation: () => [],
|
|
387
372
|
getRequestBasePath: () => '',
|
|
388
373
|
logger: {},
|
|
389
374
|
readFileSync: () => '{}'
|
|
@@ -413,7 +398,6 @@ describe('createNunjucksContextBuilder() hasPermission()', () => {
|
|
|
413
398
|
// Arrange
|
|
414
399
|
const contextBuilder = createNunjucksContextBuilder({
|
|
415
400
|
config: createConfig(),
|
|
416
|
-
buildNavigation: () => [],
|
|
417
401
|
getRequestBasePath: () => '',
|
|
418
402
|
logger: {},
|
|
419
403
|
readFileSync: () => '{}'
|
|
@@ -443,7 +427,6 @@ describe('createNunjucksContextBuilder() hasPermission()', () => {
|
|
|
443
427
|
// Arrange
|
|
444
428
|
const contextBuilder = createNunjucksContextBuilder({
|
|
445
429
|
config: createConfig(),
|
|
446
|
-
buildNavigation: () => [],
|
|
447
430
|
getRequestBasePath: () => '',
|
|
448
431
|
logger: {},
|
|
449
432
|
readFileSync: () => '{}'
|
|
@@ -473,7 +456,6 @@ describe('createNunjucksContextBuilder() hasPermission()', () => {
|
|
|
473
456
|
// Arrange
|
|
474
457
|
const contextBuilder = createNunjucksContextBuilder({
|
|
475
458
|
config: createConfig(),
|
|
476
|
-
buildNavigation: () => [],
|
|
477
459
|
getRequestBasePath: () => '',
|
|
478
460
|
logger: {},
|
|
479
461
|
readFileSync: () => '{}'
|
|
@@ -503,7 +485,6 @@ describe('createNunjucksContextBuilder() hasPermission()', () => {
|
|
|
503
485
|
// Arrange
|
|
504
486
|
const contextBuilder = createNunjucksContextBuilder({
|
|
505
487
|
config: createConfig(),
|
|
506
|
-
buildNavigation: () => [],
|
|
507
488
|
getRequestBasePath: () => '',
|
|
508
489
|
logger: {},
|
|
509
490
|
readFileSync: () => '{}'
|
|
@@ -524,7 +505,6 @@ describe('createNunjucksContextBuilder() hasPermission()', () => {
|
|
|
524
505
|
// Arrange
|
|
525
506
|
const contextBuilder = createNunjucksContextBuilder({
|
|
526
507
|
config: createConfig(),
|
|
527
|
-
buildNavigation: () => [],
|
|
528
508
|
getRequestBasePath: () => '',
|
|
529
509
|
logger: {},
|
|
530
510
|
readFileSync: () => '{}'
|
|
@@ -553,7 +533,6 @@ describe('createNunjucksContextBuilder() hasPermission()', () => {
|
|
|
553
533
|
// Arrange
|
|
554
534
|
const contextBuilder = createNunjucksContextBuilder({
|
|
555
535
|
config: createConfig(),
|
|
556
|
-
buildNavigation: () => [],
|
|
557
536
|
getRequestBasePath: () => '',
|
|
558
537
|
logger: {},
|
|
559
538
|
readFileSync: () => '{}'
|
|
@@ -580,7 +559,6 @@ describe('createNunjucksContextBuilder() hasPermission()', () => {
|
|
|
580
559
|
// Arrange
|
|
581
560
|
const contextBuilder = createNunjucksContextBuilder({
|
|
582
561
|
config: createConfig(),
|
|
583
|
-
buildNavigation: () => [],
|
|
584
562
|
getRequestBasePath: () => '',
|
|
585
563
|
logger: {},
|
|
586
564
|
readFileSync: () => '{}'
|
package/src/nunjucks/plugin.js
CHANGED
|
@@ -5,10 +5,7 @@ import hapiVision from '@hapi/vision'
|
|
|
5
5
|
import { createRequire } from 'node:module'
|
|
6
6
|
import { fileURLToPath } from 'node:url'
|
|
7
7
|
|
|
8
|
-
import { getBasePathForModule } from '@defra/lis-hubs-infra-registry'
|
|
9
|
-
|
|
10
8
|
import { createNunjucksContextBuilder } from './context.js'
|
|
11
|
-
import { buildPrimaryNavigation } from './build-navigation.js'
|
|
12
9
|
import * as filters from './filters.js'
|
|
13
10
|
import * as globals from './globals.js'
|
|
14
11
|
|
|
@@ -168,7 +165,6 @@ export function createNunjucksConfig({
|
|
|
168
165
|
moduleId,
|
|
169
166
|
errorPages
|
|
170
167
|
}) {
|
|
171
|
-
const basePath = moduleId ? getBasePathForModule(moduleId) : ''
|
|
172
168
|
const projectRoot = config.get('root')
|
|
173
169
|
const infrastructureRoot = path.resolve(
|
|
174
170
|
path.dirname(fileURLToPath(import.meta.url)),
|
|
@@ -185,15 +181,8 @@ export function createNunjucksConfig({
|
|
|
185
181
|
govukFrontendRoot
|
|
186
182
|
})
|
|
187
183
|
|
|
188
|
-
const buildNavigation = (request) =>
|
|
189
|
-
buildPrimaryNavigation({
|
|
190
|
-
request,
|
|
191
|
-
basePath
|
|
192
|
-
})
|
|
193
|
-
|
|
194
184
|
const context = createNunjucksContextBuilder({
|
|
195
185
|
config,
|
|
196
|
-
buildNavigation,
|
|
197
186
|
getRequestBasePath,
|
|
198
187
|
logger,
|
|
199
188
|
readFileSync,
|
|
@@ -4,15 +4,12 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
|
|
4
4
|
import { tmpdir } from 'node:os'
|
|
5
5
|
import path from 'node:path'
|
|
6
6
|
import nunjucks from 'nunjucks'
|
|
7
|
-
import { getBasePathForModule } from '@defra/lis-hubs-infra-registry'
|
|
8
7
|
import { createNunjucksConfig } from './plugin.js'
|
|
9
8
|
|
|
10
9
|
vi.mock('nunjucks')
|
|
11
|
-
vi.mock('@defra/lis-hubs-infra-registry')
|
|
12
10
|
|
|
13
11
|
const mocks = {
|
|
14
|
-
nunjucksConfigure: vi.mocked(nunjucks.configure)
|
|
15
|
-
getBasePathForModule: vi.mocked(getBasePathForModule)
|
|
12
|
+
nunjucksConfigure: vi.mocked(nunjucks.configure)
|
|
16
13
|
}
|
|
17
14
|
|
|
18
15
|
function createProjectRoot() {
|
|
@@ -49,25 +46,6 @@ describe('createNunjucksConfig()', () => {
|
|
|
49
46
|
rmSync(projectRoot, { recursive: true, force: true })
|
|
50
47
|
})
|
|
51
48
|
|
|
52
|
-
test('resolves the base path from the module registry when moduleId is given', () => {
|
|
53
|
-
// Arrange
|
|
54
|
-
mocks.getBasePathForModule.mockReturnValue('/cattle/register')
|
|
55
|
-
const config = {
|
|
56
|
-
get: vi.fn((key) => (key === 'root' ? projectRoot : false))
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Act
|
|
60
|
-
createNunjucksConfig({
|
|
61
|
-
config,
|
|
62
|
-
logger: {},
|
|
63
|
-
getRequestBasePath: vi.fn(),
|
|
64
|
-
moduleId: 'cattle-register'
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
// Assert
|
|
68
|
-
expect(mocks.getBasePathForModule).toHaveBeenCalledWith('cattle-register')
|
|
69
|
-
})
|
|
70
|
-
|
|
71
49
|
test('defaults to an empty base path when no moduleId is given', () => {
|
|
72
50
|
// Arrange
|
|
73
51
|
const config = {
|
|
@@ -82,7 +60,6 @@ describe('createNunjucksConfig()', () => {
|
|
|
82
60
|
})
|
|
83
61
|
|
|
84
62
|
// Assert
|
|
85
|
-
expect(mocks.getBasePathForModule).not.toHaveBeenCalled()
|
|
86
63
|
expect(nunjucksConfig.plugin).toBeDefined()
|
|
87
64
|
})
|
|
88
65
|
|
|
@@ -160,4 +160,35 @@ describe('error pages', () => {
|
|
|
160
160
|
'<a class="govuk-link" href="https://example.com/contact">British Cattle Movement Service (BCMS)</a>'
|
|
161
161
|
)
|
|
162
162
|
})
|
|
163
|
+
|
|
164
|
+
test('service unavailable says later when no return time is given', () => {
|
|
165
|
+
// Arrange
|
|
166
|
+
const context = { pageTitle: 'Sorry, the service is unavailable' }
|
|
167
|
+
|
|
168
|
+
// Act
|
|
169
|
+
const html = render('error/service-unavailable.njk', context)
|
|
170
|
+
|
|
171
|
+
// Assert
|
|
172
|
+
expect(textOf(html)).toContain('You will be able to use the service later.')
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
test.each([
|
|
176
|
+
'error/page-not-found.njk',
|
|
177
|
+
'error/not-authorised.njk',
|
|
178
|
+
'error/problem-with-service.njk',
|
|
179
|
+
'error/service-unavailable.njk'
|
|
180
|
+
])('%s shows the development message only when one is given', (view) => {
|
|
181
|
+
// Arrange
|
|
182
|
+
const withMessage = { developmentMessage: 'Upstream timed out' }
|
|
183
|
+
|
|
184
|
+
// Act
|
|
185
|
+
const htmlWithMessage = render(view, withMessage)
|
|
186
|
+
const htmlWithoutMessage = render(view)
|
|
187
|
+
|
|
188
|
+
// Assert
|
|
189
|
+
expect(htmlWithMessage).toContain(
|
|
190
|
+
'<p class="govuk-body">Upstream timed out</p>'
|
|
191
|
+
)
|
|
192
|
+
expect(htmlWithoutMessage).not.toContain('Upstream timed out')
|
|
193
|
+
})
|
|
163
194
|
})
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
{% if signInHref %}
|
|
10
10
|
<a href="{{ signInHref }}" role="button" draggable="false" class="govuk-button" data-module="govuk-button">Sign in</a>
|
|
11
11
|
{% endif %}
|
|
12
|
+
{% if developmentMessage %}
|
|
13
|
+
<p class="govuk-body">{{ developmentMessage }}</p>
|
|
14
|
+
{% endif %}
|
|
12
15
|
</div>
|
|
13
16
|
</div>
|
|
14
17
|
{% endblock %}
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
<li><a class="govuk-link" href="https://www.gov.uk">GOV.UK</a></li>
|
|
13
13
|
</ul>
|
|
14
14
|
<p class="govuk-body">If you cannot find the information you need, <a class="govuk-link" href="{{ errorPages.contactHref }}">contact our support team</a>.</p>
|
|
15
|
+
{% if developmentMessage %}
|
|
16
|
+
<p class="govuk-body">{{ developmentMessage }}</p>
|
|
17
|
+
{% endif %}
|
|
15
18
|
</div>
|
|
16
19
|
</div>
|
|
17
20
|
{% endblock %}
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
<h1 class="govuk-heading-l">Sorry, there is a problem with the service</h1>
|
|
7
7
|
<p class="govuk-body">Try again later.</p>
|
|
8
8
|
<p class="govuk-body">Contact the <a class="govuk-link" href="{{ errorPages.contactHref }}">British Cattle Movement Service (BCMS)</a> if you need to speak to someone about your account.</p>
|
|
9
|
+
{% if developmentMessage %}
|
|
10
|
+
<p class="govuk-body">{{ developmentMessage }}</p>
|
|
11
|
+
{% endif %}
|
|
9
12
|
</div>
|
|
10
13
|
</div>
|
|
11
14
|
{% endblock %}
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
<p class="govuk-body">You will be able to use the service later.</p>
|
|
11
11
|
{% endif %}
|
|
12
12
|
<p class="govuk-body">Contact the <a class="govuk-link" href="{{ errorPages.contactHref }}">British Cattle Movement Service (BCMS)</a> if you need to speak to someone about your account.</p>
|
|
13
|
+
{% if developmentMessage %}
|
|
14
|
+
<p class="govuk-body">{{ developmentMessage }}</p>
|
|
15
|
+
{% endif %}
|
|
13
16
|
</div>
|
|
14
17
|
</div>
|
|
15
18
|
{% endblock %}
|
package/src/navigation.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { buildPrimaryNavigation } from './nunjucks/build-navigation.js'
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { MODULES } from '@defra/lis-hubs-infra-registry'
|
|
2
|
-
import { SUPPORTED_SPECIES, SUPPORTED_TAXONOMIES } from '../index.js'
|
|
3
|
-
|
|
4
|
-
/** @import { Request } from '@hapi/hapi' */
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @param {{ request: Request, basePath?: string }} options
|
|
8
|
-
* @returns {object[]}
|
|
9
|
-
*/
|
|
10
|
-
export function buildPrimaryNavigation({ request, basePath = '' }) {
|
|
11
|
-
const currentSpecies = getCurrentSpecies({ request, basePath })
|
|
12
|
-
const profileItem = {
|
|
13
|
-
text: 'Profile',
|
|
14
|
-
href: '/profile',
|
|
15
|
-
current: request?.path === '/profile' && !currentSpecies?.id
|
|
16
|
-
}
|
|
17
|
-
const permittedSpecies = request?.auth?.credentials?.authorizedSpecies
|
|
18
|
-
|
|
19
|
-
if (!Array.isArray(permittedSpecies) || permittedSpecies.length === 0) {
|
|
20
|
-
return []
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return [
|
|
24
|
-
...permittedSpecies.map((species) => ({
|
|
25
|
-
text: species.label,
|
|
26
|
-
href: getSpeciesHomePath(species),
|
|
27
|
-
current: species.id === currentSpecies?.id
|
|
28
|
-
})),
|
|
29
|
-
profileItem
|
|
30
|
-
]
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function getSpeciesHomePath(species) {
|
|
34
|
-
const homeModule = MODULES.find(
|
|
35
|
-
(module) => module.id === `${species.id}-home`
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
return homeModule?.path ?? `/${species.id}`
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function getCurrentSpecies({ request, basePath }) {
|
|
42
|
-
for (const path of [request?.path, basePath]) {
|
|
43
|
-
if (typeof path !== 'string' || path.length === 0) {
|
|
44
|
-
continue
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const [speciesSlug, taxonomySlug] = path.split('/').filter(Boolean)
|
|
48
|
-
|
|
49
|
-
const matchingTaxonomy = SUPPORTED_TAXONOMIES.find(
|
|
50
|
-
(taxonomy) => taxonomy.slug === taxonomySlug
|
|
51
|
-
)
|
|
52
|
-
const matchingSpecies = SUPPORTED_SPECIES.find(
|
|
53
|
-
(species) => species.slug === speciesSlug
|
|
54
|
-
)
|
|
55
|
-
if (matchingTaxonomy && matchingSpecies) {
|
|
56
|
-
return matchingSpecies
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return null
|
|
61
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict'
|
|
2
|
-
import { test } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import { buildPrimaryNavigation } from './build-navigation.js'
|
|
5
|
-
|
|
6
|
-
test('buildPrimaryNavigation renders species already authorized by the host', () => {
|
|
7
|
-
const navigation = buildPrimaryNavigation({
|
|
8
|
-
request: {
|
|
9
|
-
path: '/',
|
|
10
|
-
auth: {
|
|
11
|
-
credentials: {
|
|
12
|
-
authorizedSpecies: [
|
|
13
|
-
{ id: 'cattle', label: 'Cattle' },
|
|
14
|
-
{ id: 'sheep', label: 'Sheep' }
|
|
15
|
-
]
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
assert.deepEqual(
|
|
22
|
-
navigation.map((item) => item.text),
|
|
23
|
-
['Cattle', 'Sheep', 'Profile']
|
|
24
|
-
)
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
test('buildPrimaryNavigation renders no items when the user has no authorized species', () => {
|
|
28
|
-
const navigation = buildPrimaryNavigation({
|
|
29
|
-
request: { path: '/', app: {} }
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
assert.deepEqual(navigation, [])
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('buildPrimaryNavigation marks the profile item as current on the profile route', () => {
|
|
36
|
-
const navigation = buildPrimaryNavigation({
|
|
37
|
-
request: {
|
|
38
|
-
path: '/profile',
|
|
39
|
-
auth: {
|
|
40
|
-
credentials: {
|
|
41
|
-
authorizedSpecies: [{ id: 'cattle', label: 'Cattle' }]
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
assert.equal(navigation.at(-1)?.text, 'Profile')
|
|
48
|
-
assert.equal(navigation.at(-1)?.current, true)
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
test('buildPrimaryNavigation ignores the legacy request.app.authorizedSpecies', () => {
|
|
52
|
-
const navigation = buildPrimaryNavigation({
|
|
53
|
-
request: {
|
|
54
|
-
path: '/',
|
|
55
|
-
app: {
|
|
56
|
-
authorizedSpecies: [{ id: 'cattle', label: 'Cattle' }]
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
assert.deepEqual(navigation, [])
|
|
62
|
-
})
|