@defra-fish/gafl-webapp-service 1.57.0-rc.2 → 1.57.0-rc.4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defra-fish/gafl-webapp-service",
3
- "version": "1.57.0-rc.2",
3
+ "version": "1.57.0-rc.4",
4
4
  "description": "The websales frontend for the GAFL service",
5
5
  "type": "module",
6
6
  "engines": {
@@ -36,8 +36,8 @@
36
36
  "prepare": "gulp --gulpfile build/gulpfile.cjs"
37
37
  },
38
38
  "dependencies": {
39
- "@defra-fish/business-rules-lib": "1.57.0-rc.2",
40
- "@defra-fish/connectors-lib": "1.57.0-rc.2",
39
+ "@defra-fish/business-rules-lib": "1.57.0-rc.4",
40
+ "@defra-fish/connectors-lib": "1.57.0-rc.4",
41
41
  "@defra/hapi-gapi": "^2.0.0",
42
42
  "@hapi/boom": "^9.1.2",
43
43
  "@hapi/catbox-redis": "^6.0.2",
@@ -80,5 +80,5 @@
80
80
  "./gafl-jest-matchers.js"
81
81
  ]
82
82
  },
83
- "gitHead": "c4f5feb4e8bc1d4b6e413fb2344c3bee4fddd9ab"
83
+ "gitHead": "54475774a2f320e8ba0ed1e6baa624e23f14decc"
84
84
  }
@@ -272,9 +272,16 @@
272
272
  "disability_concession_title_you": "Ydych chi’n derbyn unrhyw un o’r canlynol?",
273
273
  "dob_day": "Diwrnod",
274
274
  "dob_entry_hint": "Er enghraifft, 23 11 1979",
275
- "dob_error_format_max": "Mae'n rhaid i’r dyddiad geni fod yn y gorffennol",
276
- "dob_error_format_min": "Nodwch eich dyddiad geni a chynnwys y diwrnod, y mis a’r flwyddyn",
277
- "dob_error_format": "Nodwch ddyddiad geni deiliad y drwydded a chynnwys diwrnod, mis a blwyddyn",
275
+ "dob_error_date_real": "Maen rhaid i’r dyddiad geni fod yn ddyddiad dilys",
276
+ "dob_error_missing_day_and_month": "Mae’n rhaid i’r dyddiad geni gynnwys diwrnod a mis",
277
+ "dob_error_missing_day_and_year": "Mae’n rhaid i’r dyddiad geni gynnwys diwrnod a blwyddyn",
278
+ "dob_error_missing_month_and_year": "Mae’n rhaid i’r dyddiad geni gynnwys mis a blwyddyn",
279
+ "dob_error_missing_day": "Mae’n rhaid i’r dyddiad geni gynnwys diwrnod",
280
+ "dob_error_missing_month": "Mae’n rhaid i’r dyddiad geni gynnwys mis",
281
+ "dob_error_missing_year": "Mae’n rhaid i’r dyddiad geni gynnwys blwyddyn",
282
+ "dob_error_non_numeric": "Rhowch rifau yn unig",
283
+ "dob_error_year_min": "Mae’r dyddiad geni yn rhy bell yn ôl",
284
+ "dob_error_year_max": "Mae'n rhaid i’r dyddiad geni fod yn y gorffennol",
278
285
  "dob_error": "Rhowch y dyddiad geni",
279
286
  "dob_month": "Mis",
280
287
  "dob_privacy_link_prefix": "Os nad ydych yn darparu dyddiad geni cywir, gallai hynny achosi oedi wrth adnewyddu trwydded, neu olygu nad yw’r drwydded yn ddilys. Darllenwch am ",
@@ -318,15 +325,19 @@
318
325
  "header_service_name_title": " - Cael trwydded bysgota â gwialen",
319
326
  "identification": "Rhif adnabod",
320
327
  "identify_body_protect_info": "Er mwyn dod o hyd i fanylion eich trwydded, bydd angen i ni wybod pwy ydych chi. Mae hyn yn ein helpu i ddiogelu eich gwybodaeth bersonol.",
328
+ "identify_error_date_real": "Mae’n rhaid i’r dyddiad geni fod yn ddyddiad dilys",
321
329
  "identify_error_empty_postcode": "Nid ydych wedi nodi cod post",
322
330
  "identify_error_empty": "Rhowch chwe nodyn olaf eich trwydded",
323
- "identify_error_enter_bday_max": "Mae’n rhaid i’ch dyddiad geni fod yn y gorffennol",
324
- "identify_error_enter_bday_min": "Mae eich dyddiad geni yn rhy bell yn ôl",
325
- "identify_error_enter_bday": "Nodwch eich dyddiad geni a chynnwys y diwrnod, y mis a’r flwyddyn",
326
331
  "identify_error_invalid_1": "Nid oes gennym gofnod o rif trwydded sy'n gorffen gyda ",
327
332
  "identify_error_invalid_2": " sy’n cyd-fynd â'r manylion hyn.",
333
+ "identify_error_missing_day": "Mae’n rhaid i’r dyddiad geni gynnwys diwrnod",
334
+ "identify_error_missing_month": "Mae’n rhaid i’r dyddiad geni gynnwys mis",
335
+ "identify_error_missing_year": "Mae’n rhaid i’r dyddiad geni gynnwys blwyddyn",
336
+ "identify_error_non_numeric": "Rhowch rifau yn unig",
328
337
  "identify_error_pattern_postcode": "Your postcode doesn’t look right. Check and enter again",
329
338
  "identify_error_pattern": "Nid yw chwe nodyn olaf eich trwydded yn edrych yn gywir. Gwiriwch a rhowch gynnig arall arni",
339
+ "identify_error_year_min": "Mae’r dyddiad geni yn rhy bell yn ôl",
340
+ "identify_error_year_max": "Mae'n rhaid i’r dyddiad geni fod yn y gorffennol",
330
341
  "identify_label_last_six_hint": "Er enghraifft F4A315",
331
342
  "identify_label_last_six": "Chwe nodyn olaf eich trwydded.",
332
343
  "identify_label_licence_ending": "Rhif trwydded yn gorffen gyda’r canlynol",
@@ -407,8 +418,16 @@
407
418
  "licence_num": "Rhif trwydded",
408
419
  "licence_start_days": " diwrnod nesaf",
409
420
  "licence_start_enter_todays_date": "Rhowch ddyddiad heddiw os ydych chi am i’r drwydded 1 diwrnod neu 8 diwrnod ddechrau yn hwyrach heddiw.",
421
+ "licence_start_error_date_real": "Mae’n rhaid i ddyddiad dechrau’r drwydded fod yn ddyddiad dilys",
422
+ "licence_start_error_missing_day_and_month": "Mae’n rhaid i ddyddiad dechrau’r drwydded gynnwys diwrnod a mis",
423
+ "licence_start_error_missing_day_and_year": "Mae’n rhaid i ddyddiad dechrau’r drwydded gynnwys diwrnod a blwyddyn",
424
+ "licence_start_error_missing_month_and_year": "Mae’n rhaid i ddyddiad dechrau’r drwydded gynnwys mis a blwyddyn",
425
+ "licence_start_error": "Rhowch ddyddiad dechrau’r drwydded",
426
+ "licence_start_error_missing_day": "Mae’n rhaid i ddyddiad dechrau’r drwydded gynnwys diwrnod",
427
+ "licence_start_error_missing_month": "Mae’n rhaid i ddyddiad dechrau’r drwydded gynnwys mis",
428
+ "licence_start_error_missing_year": "Mae’n rhaid i ddyddiad dechrau’r drwydded gynnwys blwyddyn",
429
+ "licence_start_error_non_numeric": "Rhowch rifau yn unig",
410
430
  "licence_start_error_choose_when": "Dewiswch pryd y dylai'r drwydded ddechrau",
411
- "licence_start_error_format": "Nodwch y dyddiad y mae angen i'r drwydded ddechrau a chynnwys diwrnod, mis a blwyddyn",
412
431
  "licence_start_error_within": "Nodwch ddyddiad o fewn y ",
413
432
  "licence_start_hint": "Rhowch ddyddiad hyd at a chan gynnwys ",
414
433
  "licence_start_later": "Yn hwyrach",
@@ -272,10 +272,19 @@
272
272
  "disability_concession_title_you": "Do you receive any of the following?",
273
273
  "dob_day": "day",
274
274
  "dob_entry_hint": "For example, 23 11 1979",
275
- "dob_error_format_max": "The date of birth must be in the past",
276
- "dob_error_format_min": "Enter the date of birth and include a day, month and year",
277
- "dob_error_format": "Enter the licence holder’s date of birth and include a day, month and year",
278
- "dob_error": "Enter the date of birth",
275
+
276
+ "dob_error_date_real": "Date of birth must be a real date",
277
+ "dob_error_missing_day_and_month": "Date of birth must include a day and month",
278
+ "dob_error_missing_day_and_year": "Date of birth must include a day and year",
279
+ "dob_error_missing_month_and_year": "Date of birth must include a month and year",
280
+ "dob_error_missing_day": "Date of birth must include a day",
281
+ "dob_error_missing_month": "Date of birth must include a month",
282
+ "dob_error_missing_year": "Date of birth must include a year",
283
+ "dob_error_non_numeric": "Enter only numbers",
284
+ "dob_error_year_min": "Date of birth is too long ago",
285
+ "dob_error_year_max": "The date of birth must be in the past",
286
+ "dob_error": "Enter a date of birth",
287
+
279
288
  "dob_month": "month",
280
289
  "dob_privacy_link_prefix": "If you do not provide a correct date of birth, this may cause delays when a licence is renewed or mean that a licence is not valid. Read about ",
281
290
  "dob_privacy_link": "how we use personal information (opens in new tab)",
@@ -318,15 +327,19 @@
318
327
  "header_service_name_title": " - Get a rod fishing licence",
319
328
  "identification": "Identification",
320
329
  "identify_body_protect_info": "To find your licence details we first need to identify you. This helps us protect your personal information.",
330
+ "identify_error_date_real": "Date of birth must be a real date",
321
331
  "identify_error_empty_postcode": "You did not enter a postcode",
322
332
  "identify_error_empty": "Enter the last six characters of your licence number",
323
- "identify_error_enter_bday_max": "Your date of birth must be in the past",
324
- "identify_error_enter_bday_min": "Your date of birth is too long ago",
325
- "identify_error_enter_bday": "Enter your date of birth and include a day, month and year",
326
333
  "identify_error_invalid_1": "We do not have any record of a licence number ending ",
327
334
  "identify_error_invalid_2": " matching these details.",
335
+ "identify_error_missing_day": "Date of birth must include a day",
336
+ "identify_error_missing_month": "Date of birth must include a month",
337
+ "identify_error_missing_year": "Date of birth must include a year",
338
+ "identify_error_non_numeric": "Enter only numbers",
328
339
  "identify_error_pattern_postcode": "Your postcode doesn’t look right. Check and enter again",
329
340
  "identify_error_pattern": "The last six characters of your licence number don’t look right. Check and enter again",
341
+ "identify_error_year_min": "Date of birth is too long ago",
342
+ "identify_error_year_max": "The date of birth must be in the past",
330
343
  "identify_label_last_six_hint": "For example F4A315",
331
344
  "identify_label_last_six": "The last six characters of your licence number",
332
345
  "identify_label_licence_ending": "The licence number ending",
@@ -407,8 +420,16 @@
407
420
  "licence_num": "Licence number",
408
421
  "licence_start_days": " days",
409
422
  "licence_start_enter_todays_date": "Enter today’s date if you want the 1-day or 8-day licence to start later today.",
423
+ "licence_start_error_date_real": "Licence start date must be a real date",
424
+ "licence_start_error_missing_day_and_month": "Licence start date must include a day and month",
425
+ "licence_start_error_missing_day_and_year": "Licence start date must include a day and year",
426
+ "licence_start_error_missing_month_and_year": "Licence start date must include a month and year",
427
+ "licence_start_error_missing_day": "Licence start date must include a day",
428
+ "licence_start_error_missing_month": "Licence start date must include a month",
429
+ "licence_start_error_missing_year": "Licence start date must include a year",
430
+ "licence_start_error_non_numeric": "Enter only numbers",
431
+ "licence_start_error": "Enter a licence start date",
410
432
  "licence_start_error_choose_when": "Choose when the licence should start",
411
- "licence_start_error_format": "Enter the date the licence needs to start, include a day, month and year",
412
433
  "licence_start_error_within": "Enter a date within the next ",
413
434
  "licence_start_hint": "Enter a date up to and including ",
414
435
  "licence_start_later": "Later",
@@ -1,15 +1,30 @@
1
- import { getData, validator } from '../route'
1
+ import { getData } from '../route'
2
2
  import pageRoute from '../../../../routes/page-route.js'
3
3
  import { nextPage } from '../../../../routes/next-page.js'
4
- import { LICENCE_FOR } from '../../../../uri.js'
4
+ import { DATE_OF_BIRTH, LICENCE_FOR } from '../../../../uri.js'
5
+ import { dateOfBirthValidator, getDateErrorFlags } from '../../../../schema/validators/validators.js'
5
6
 
6
- jest.mock('../../../../routes/next-page.js', () => ({
7
- nextPage: jest.fn()
8
- }))
7
+ jest.mock('../../../../routes/next-page.js')
9
8
  jest.mock('../../../../routes/page-route.js')
9
+ jest.mock('../../../../schema/validators/validators.js')
10
+ jest.mock('../../../../uri.js', () => ({
11
+ ...jest.requireActual('../../../../uri.js'),
12
+ DATE_OF_BIRTH: {
13
+ page: Symbol('date-of-birth-page'),
14
+ uri: Symbol('/date-of-birth')
15
+ },
16
+ LICENCE_TO_START: {
17
+ page: Symbol('licence-to-start-page'),
18
+ uri: Symbol('/licence-to-start')
19
+ }
20
+ }))
10
21
 
11
22
  describe('name > route', () => {
12
- const mockRequest = (statusGet = () => {}, transactionGet = () => {}) => ({
23
+ const mockRequest = ({
24
+ pageGet = async () => {},
25
+ statusGet = async () => ({ [LICENCE_FOR.page]: true }),
26
+ transactionGet = async () => ({ isLicenceForYou: null })
27
+ } = {}) => ({
13
28
  cache: () => ({
14
29
  helpers: {
15
30
  transaction: {
@@ -17,6 +32,9 @@ describe('name > route', () => {
17
32
  },
18
33
  status: {
19
34
  getCurrentPermission: statusGet
35
+ },
36
+ page: {
37
+ getCurrentPermission: pageGet
20
38
  }
21
39
  }
22
40
  })
@@ -24,52 +42,89 @@ describe('name > route', () => {
24
42
 
25
43
  describe('getData', () => {
26
44
  it('should return isLicenceForYou as true, if isLicenceForYou is true on the transaction cache', async () => {
27
- const transaction = () => ({
45
+ const transactionGet = async () => ({
28
46
  isLicenceForYou: true
29
47
  })
30
- const status = () => ({
48
+ const statusGet = async () => ({
31
49
  [LICENCE_FOR.page]: true
32
50
  })
33
- const result = await getData(mockRequest(status, transaction))
51
+
52
+ const result = await getData(mockRequest({ statusGet, transactionGet }))
34
53
  expect(result.isLicenceForYou).toBeTruthy()
35
54
  })
36
55
 
37
56
  it('should return isLicenceForYou as false, if isLicenceForYou is false on the transaction cache', async () => {
38
- const transaction = () => ({
57
+ const transactionGet = async () => ({
39
58
  isLicenceForYou: false
40
59
  })
41
- const status = () => ({
60
+ const statusGet = async () => ({
42
61
  [LICENCE_FOR.page]: true
43
62
  })
44
- const result = await getData(mockRequest(status, transaction))
63
+ const result = await getData(mockRequest({ statusGet, transactionGet }))
45
64
  expect(result.isLicenceForYou).toBeFalsy()
46
65
  })
66
+
67
+ it.each([
68
+ ['full-date', 'object.missing'],
69
+ ['day', 'any.required']
70
+ ])('should add error details ({%s: %s}) to the page data', async (errorKey, errorValue) => {
71
+ const pageGet = async () => ({
72
+ error: { [errorKey]: errorValue }
73
+ })
74
+
75
+ const result = await getData(mockRequest({ pageGet }))
76
+ expect(result.error).toEqual({ errorKey, errorValue })
77
+ })
78
+
79
+ it('omits error if there is no error', async () => {
80
+ const result = await getData(mockRequest())
81
+ expect(result.error).toBeUndefined()
82
+ })
83
+
84
+ it('adds return value of getErrorFlags to the page data', async () => {
85
+ const errorFlags = { unique: Symbol('error-flags') }
86
+ getDateErrorFlags.mockReturnValueOnce(errorFlags)
87
+ const result = await getData(mockRequest())
88
+ expect(result).toEqual(expect.objectContaining(errorFlags))
89
+ })
90
+
91
+ it('passes error to getErrorFlags', async () => {
92
+ const error = Symbol('error')
93
+ await getData(mockRequest({ pageGet: async () => ({ error }) }))
94
+ expect(getDateErrorFlags).toHaveBeenCalledWith(error)
95
+ })
96
+
97
+ it('passes correct page name when getting page cache', async () => {
98
+ const pageGet = jest.fn(() => ({}))
99
+ await getData(mockRequest({ pageGet }))
100
+ expect(pageGet).toHaveBeenCalledWith(DATE_OF_BIRTH.page)
101
+ })
47
102
  })
48
103
 
49
104
  describe('redirectToStartOfJourney', () => {
50
105
  it('should throw a redirect if not been to LICENCE_FOR page', async () => {
51
- const transaction = () => ({
106
+ const transactionGet = async () => ({
52
107
  isLicenceForYou: true
53
108
  })
54
- const status = () => ({
109
+ const statusGet = async () => ({
55
110
  [LICENCE_FOR.page]: false
56
111
  })
57
- const func = () => getData(mockRequest(status, transaction))
112
+ const func = () => getData(mockRequest({ statusGet, transactionGet }))
58
113
  await expect(func).rejects.toThrowRedirectTo(LICENCE_FOR.uri)
59
114
  })
60
115
 
61
116
  it('should not throw a redirect if not been to LICENCE_FOR page', async () => {
62
- const transaction = () => ({
117
+ const transactionGet = async () => ({
63
118
  isLicenceForYou: true
64
119
  })
65
- const status = () => ({
120
+ const statusGet = async () => ({
66
121
  [LICENCE_FOR.page]: true
67
122
  })
68
123
 
69
124
  let error
70
125
 
71
126
  try {
72
- await getData(mockRequest(status, transaction))
127
+ await getData(mockRequest({ statusGet, transactionGet }))
73
128
  } catch (e) {
74
129
  error = e
75
130
  }
@@ -79,8 +134,8 @@ describe('name > route', () => {
79
134
  })
80
135
 
81
136
  describe('default', () => {
82
- it('should call the pageRoute with date-of-birth, /buy/date-of-birth, validator and nextPage', async () => {
83
- expect(pageRoute).toBeCalledWith('date-of-birth', '/buy/date-of-birth', validator, nextPage, getData)
137
+ it('should call the pageRoute with date-of-birth, /buy/date-of-birth, dateOfBirthValidator and nextPage', async () => {
138
+ expect(pageRoute).toBeCalledWith(DATE_OF_BIRTH.page, DATE_OF_BIRTH.uri, dateOfBirthValidator, nextPage, getData)
84
139
  })
85
140
  })
86
141
  })
@@ -9,11 +9,37 @@
9
9
 
10
10
  {%
11
11
  set errorMap = {
12
- 'date-of-birth': {
13
- 'date.format': { ref: '#date-of-birth-day', text: mssgs.dob_error_format },
14
- 'date.max': { ref: '#date-of-birth-day', text: mssgs.dob_error_format_max },
15
- 'date.min': { ref: '#date-of-birth-day', text: mssgs.dob_error_format_min }
16
- }
12
+ 'full-date': {
13
+ 'object.missing': { ref: '#date-of-birth-day', text: mssgs.dob_error }
14
+ },
15
+ 'day-and-month': {
16
+ 'object.missing': { ref: '#date-of-birth-day', text: mssgs.dob_error_missing_day_and_month }
17
+ },
18
+ 'day-and-year': {
19
+ 'object.missing': { ref: '#date-of-birth-day', text: mssgs.dob_error_missing_day_and_year }
20
+ },
21
+ 'month-and-year': {
22
+ 'object.missing': { ref: '#date-of-birth-month', text: mssgs.dob_error_missing_month_and_year }
23
+ },
24
+ 'day': {
25
+ 'any.required': { ref: '#date-of-birth-day', text: mssgs.dob_error_missing_day }
26
+ },
27
+ 'month': {
28
+ 'any.required': { ref: '#date-of-birth-month', text: mssgs.dob_error_missing_month }
29
+ },
30
+ 'year': {
31
+ 'any.required': { ref: '#date-of-birth-year', text: mssgs.dob_error_missing_year }
32
+ },
33
+ 'non-numeric': {
34
+ 'number.base': { ref: '#date-of-birth-day', text: mssgs.dob_error_non_numeric }
35
+ },
36
+ 'invalid-date': {
37
+ 'any.custom': { ref: '#date-of-birth-day', text: mssgs.dob_error_date_real }
38
+ },
39
+ 'date-range': {
40
+ 'date.min': { ref: '#date-of-birth-day', text: mssgs.dob_error_year_min },
41
+ 'date.max': { ref: '#date-of-birth-day', text: mssgs.dob_error_year_max }
42
+ }
17
43
  }
18
44
  %}
19
45
 
@@ -21,21 +47,21 @@
21
47
  {
22
48
  label: mssgs.dob_day,
23
49
  name: 'day',
24
- classes: "govuk-input--width-2",
50
+ classes: "govuk-input--width-2 govuk-input--error" if data.isDayError else "govuk-input--width-2",
25
51
  value: payload['date-of-birth-day'],
26
52
  attributes: { maxlength : 2 }
27
53
  },
28
54
  {
29
55
  label: mssgs.dob_month,
30
56
  name: 'month',
31
- classes: "govuk-input--width-2",
57
+ classes: "govuk-input--width-2 govuk-input--error" if data.isMonthError else "govuk-input--width-2",
32
58
  value: payload['date-of-birth-month'],
33
59
  attributes: { maxlength : 2 }
34
60
  },
35
61
  {
36
62
  label: mssgs.dob_year,
37
63
  name: 'year',
38
- classes: "govuk-input--width-4",
64
+ classes: "govuk-input--width-4 govuk-input--error" if data.isYearError else "govuk-input--width-4",
39
65
  value: payload['date-of-birth-year'],
40
66
  attributes: { maxlength : 4 }
41
67
  }
@@ -56,6 +82,6 @@
56
82
  id: "date-of-birth",
57
83
  namePrefix: "date-of-birth",
58
84
  items: dateInputItems,
59
- errorMessage: { text: mssgs.dob_error } if error
85
+ errorMessage: { text: errorMap[data.error.errorKey][data.error.errorValue].text } if data.error
60
86
  }) }}
61
87
  {% endblock %}
@@ -1,19 +1,8 @@
1
1
  import { DATE_OF_BIRTH, LICENCE_FOR } from '../../../uri.js'
2
- import Joi from 'joi'
3
2
  import pageRoute from '../../../routes/page-route.js'
4
- import { validation } from '@defra-fish/business-rules-lib'
5
3
  import { nextPage } from '../../../routes/next-page.js'
6
4
  import GetDataRedirect from '../../../handlers/get-data-redirect.js'
7
-
8
- export const validator = payload => {
9
- const dateOfBirth = `${payload['date-of-birth-year']}-${payload['date-of-birth-month']}-${payload['date-of-birth-day']}`
10
- Joi.assert(
11
- { 'date-of-birth': dateOfBirth },
12
- Joi.object({
13
- 'date-of-birth': validation.contact.createBirthDateValidator(Joi)
14
- })
15
- )
16
- }
5
+ import { dateOfBirthValidator, getDateErrorFlags } from '../../../schema/validators/validators.js'
17
6
 
18
7
  const redirectToStartOfJourney = status => {
19
8
  if (!status[LICENCE_FOR.page]) {
@@ -24,10 +13,17 @@ const redirectToStartOfJourney = status => {
24
13
  export const getData = async request => {
25
14
  const { isLicenceForYou } = await request.cache().helpers.transaction.getCurrentPermission()
26
15
  const status = await request.cache().helpers.status.getCurrentPermission()
16
+ const page = await request.cache().helpers.page.getCurrentPermission(DATE_OF_BIRTH.page)
17
+ const pageData = { isLicenceForYou, ...getDateErrorFlags(page?.error) }
27
18
 
28
19
  redirectToStartOfJourney(status)
29
20
 
30
- return { isLicenceForYou }
21
+ if (page?.error) {
22
+ const [errorKey] = Object.keys(page.error)
23
+ const errorValue = page.error[errorKey]
24
+ pageData.error = { errorKey, errorValue }
25
+ }
26
+ return pageData
31
27
  }
32
28
 
33
- export default pageRoute(DATE_OF_BIRTH.page, DATE_OF_BIRTH.uri, validator, nextPage, getData)
29
+ export default pageRoute(DATE_OF_BIRTH.page, DATE_OF_BIRTH.uri, dateOfBirthValidator, nextPage, getData)
@@ -1,21 +1,42 @@
1
+ import pageRoute from '../../../../routes/page-route.js'
2
+ import { nextPage } from '../../../../routes/next-page.js'
1
3
  import { getData } from '../route'
4
+ import { LICENCE_TO_START } from '../../../../uri.js'
5
+ import { startDateValidator, getDateErrorFlags } from '../../../../schema/validators/validators.js'
2
6
 
3
- jest.mock('../../../../processors/uri-helper.js')
7
+ jest.mock('../../../../routes/next-page.js')
8
+ jest.mock('../../../../routes/page-route.js')
9
+ jest.mock('../../../../schema/validators/validators.js')
10
+ jest.mock('../../../../uri.js', () => ({
11
+ ...jest.requireActual('../../../../uri.js'),
12
+ LICENCE_TO_START: {
13
+ page: Symbol('licence-to-start-page'),
14
+ uri: Symbol('/licence-to-start')
15
+ }
16
+ }))
17
+ jest.mock('../../../../schema/validators/validators.js')
4
18
 
5
19
  describe('licence-to-start > route', () => {
6
- const getMockRequest = (isLicenceForYou = true) => ({
20
+ const getMockRequest = (isLicenceForYou = true, pageGet = () => {}) => ({
7
21
  cache: () => ({
8
22
  helpers: {
9
23
  transaction: {
10
24
  getCurrentPermission: () => ({
11
25
  isLicenceForYou
12
26
  })
27
+ },
28
+ page: {
29
+ getCurrentPermission: pageGet
13
30
  }
14
31
  }
15
32
  })
16
33
  })
17
34
 
18
35
  describe('getData', () => {
36
+ beforeEach(() => {
37
+ getDateErrorFlags.mockClear()
38
+ })
39
+
19
40
  it('should return isLicenceForYou as true, if isLicenceForYou is true on the transaction cache', async () => {
20
41
  const request = getMockRequest()
21
42
  const result = await getData(request)
@@ -27,5 +48,47 @@ describe('licence-to-start > route', () => {
27
48
  const result = await getData(request)
28
49
  expect(result.isLicenceForYou).toBeFalsy()
29
50
  })
51
+
52
+ it.each([
53
+ ['full-date', 'object.missing'],
54
+ ['day', 'any.required']
55
+ ])('should add error details ({%s: %s}) to the page data', async (errorKey, errorValue) => {
56
+ const pageGet = async () => ({
57
+ error: { [errorKey]: errorValue }
58
+ })
59
+
60
+ const result = await getData(getMockRequest(undefined, pageGet))
61
+ expect(result.error).toEqual({ errorKey, errorValue })
62
+ })
63
+
64
+ it('omits error if there is no error', async () => {
65
+ const result = await getData(getMockRequest())
66
+ expect(result.error).toBeUndefined()
67
+ })
68
+
69
+ it('passes correct page name when getting page cache', async () => {
70
+ const pageGet = jest.fn(() => {})
71
+ await getData(getMockRequest(undefined, pageGet))
72
+ expect(pageGet).toHaveBeenCalledWith(LICENCE_TO_START.page)
73
+ })
74
+
75
+ it('adds return value of getErrorFlags to the page data', async () => {
76
+ const errorFlags = { unique: Symbol('error-flags') }
77
+ getDateErrorFlags.mockReturnValueOnce(errorFlags)
78
+ const result = await getData(getMockRequest())
79
+ expect(result).toEqual(expect.objectContaining(errorFlags))
80
+ })
81
+
82
+ it('passes error to getErrorFlags', async () => {
83
+ const error = Symbol('error')
84
+ await getData(getMockRequest(undefined, async () => ({ error })))
85
+ expect(getDateErrorFlags).toHaveBeenCalledWith(error)
86
+ })
87
+ })
88
+
89
+ describe('default', () => {
90
+ it('should call the pageRoute with date-of-birth, /buy/date-of-birth, dateOfBirthValidator and nextPage', async () => {
91
+ expect(pageRoute).toBeCalledWith(LICENCE_TO_START.page, LICENCE_TO_START.uri, startDateValidator, nextPage, getData)
92
+ })
30
93
  })
31
94
  })
@@ -8,14 +8,37 @@
8
8
 
9
9
  {%
10
10
  set errorMap = {
11
- 'licence-to-start': {
12
- 'any.required': { ref: '#licence-to-start', text: mssgs.licence_start_error_choose_when }
13
- },
14
- 'licence-start-date': {
15
- 'date.format': { ref: '#licence-start-date-day', text: mssgs.licence_start_error_format },
16
- 'date.max': { ref: '#licence-start-date-day', text: mssgs.licence_start_error_within + data.advancedPurchaseMaxDays + mssgs.licence_start_days },
17
- 'date.min': { ref: '#licence-start-date-day', text: mssgs.licence_start_error_within + data.advancedPurchaseMaxDays + mssgs.licence_start_days }
18
- }
11
+ 'full-date': {
12
+ 'object.missing': { ref: '#licence-start-date-day', text: mssgs.licence_start_error }
13
+ },
14
+ 'day-and-month': {
15
+ 'object.missing': { ref: '#licence-start-date-day', text: mssgs.licence_start_error_missing_day_and_month }
16
+ },
17
+ 'day-and-year': {
18
+ 'object.missing': { ref: '#licence-start-date-day', text: mssgs.licence_start_error_missing_day_and_year }
19
+ },
20
+ 'month-and-year': {
21
+ 'object.missing': { ref: '#licence-start-date-month', text: mssgs.licence_start_error_missing_month_and_year }
22
+ },
23
+ 'day': {
24
+ 'any.required': { ref: '#licence-start-date-day', text: mssgs.licence_start_error_missing_day }
25
+ },
26
+ 'month': {
27
+ 'any.required': { ref: '#licence-start-date-month', text: mssgs.licence_start_error_missing_month }
28
+ },
29
+ 'year': {
30
+ 'any.required': { ref: '#licence-start-date-year', text: mssgs.licence_start_error_missing_year }
31
+ },
32
+ 'non-numeric': {
33
+ 'number.base': { ref: '#licence-start-date-day', text: mssgs.licence_start_error_non_numeric }
34
+ },
35
+ 'invalid-date': {
36
+ 'any.custom': { ref: '#licence-start-date-day', text: mssgs.licence_start_error_date_real }
37
+ },
38
+ 'date-range': {
39
+ 'date.min': { ref: '#licence-start-date-day', text: mssgs.licence_start_error_within + data.advancedPurchaseMaxDays + mssgs.licence_start_days },
40
+ 'date.max': { ref: '#licence-start-date-day', text: mssgs.licence_start_error_within + data.advancedPurchaseMaxDays + mssgs.licence_start_days }
41
+ }
19
42
  }
20
43
  %}
21
44
 
@@ -23,21 +46,21 @@
23
46
  {
24
47
  name: "day",
25
48
  label: mssgs.dob_day,
26
- classes: "govuk-input--width-2",
49
+ classes: "govuk-input--width-2 govuk-input--error" if data.isDayError else "govuk-input--width-2",
27
50
  value: payload['licence-start-date-day'],
28
51
  attributes: { maxlength : 2 }
29
52
  },
30
53
  {
31
54
  name: "month",
32
55
  label: mssgs.dob_month,
33
- classes: "govuk-input--width-2",
56
+ classes: "govuk-input--width-2 govuk-input--error" if data.isMonthError else "govuk-input--width-2",
34
57
  value: payload['licence-start-date-month'],
35
58
  attributes: { maxlength : 2 }
36
59
  },
37
60
  {
38
61
  name: "year",
39
62
  label: mssgs.dob_year,
40
- classes: "govuk-input--width-4",
63
+ classes: "govuk-input--width-4 govuk-input--error" if data.isYearError else "govuk-input--width-4",
41
64
  value: payload['licence-start-date-year'],
42
65
  attributes: { maxlength : 4 }
43
66
  }
@@ -53,7 +76,7 @@
53
76
  id: "licence-start-date",
54
77
  namePrefix: "licence-start-date",
55
78
  items: dateInputItems,
56
- errorMessage: { text: mssgs.licence_start_error_within + data.advancedPurchaseMaxDays + mssgs.licence_start_days } if error['licence-start-date'],
79
+ errorMessage: { text: errorMap[data.error.errorKey][data.error.errorValue].text } if data.error,
57
80
  hint: {
58
81
  text: mssgs.licence_start_hint + data.maxStartDate
59
82
  }