@defra-fish/gafl-webapp-service 1.23.0 → 1.24.0-rc.2

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.
Files changed (25) hide show
  1. package/package.json +4 -4
  2. package/src/locales/cy.json +3 -3
  3. package/src/locales/en.json +1 -1
  4. package/src/pages/contact/digital-licence/check-confirmation-contact/__tests__/__snapshots__/check-confirmation-contact.spec.js.snap +2 -2
  5. package/src/pages/contact/digital-licence/check-confirmation-contact/__tests__/check-confirmation-contact.spec.js +45 -1
  6. package/src/pages/contact/digital-licence/check-confirmation-contact/check-confirmation-contact.njk +1 -4
  7. package/src/pages/contact/digital-licence/check-confirmation-contact/route.js +6 -2
  8. package/src/pages/licence-details/licence-length/__tests__/route.spec.js +32 -2
  9. package/src/pages/licence-details/licence-length/licence-length.njk +2 -2
  10. package/src/pages/licence-details/licence-length/route.js +1 -1
  11. package/src/pages/licence-details/licence-type/licence-type.njk +2 -2
  12. package/src/pages/macros/pricing-summary.njk +2 -6
  13. package/src/pages/order-complete/licence-details/__tests__/licence-details.spec.js +7 -1
  14. package/src/pages/order-complete/licence-details/__tests__/route.spec.js +89 -0
  15. package/src/pages/order-complete/licence-details/route.js +1 -1
  16. package/src/pages/summary/licence-summary/__tests__/route.spec.js +43 -1
  17. package/src/pages/summary/licence-summary/route.js +1 -1
  18. package/src/processors/__tests__/licence-type-display.spec.js +103 -0
  19. package/src/processors/__tests__/payment.spec.js +43 -0
  20. package/src/processors/__tests__/uri-helper.spec.js +27 -0
  21. package/src/processors/licence-type-display.js +15 -11
  22. package/src/processors/payment.js +4 -1
  23. package/src/processors/uri-helper.js +2 -1
  24. package/src/services/payment/__test__/govuk-pay-service.spec.js +55 -4
  25. package/src/pages/macros/licence-type-summary.njk +0 -19
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defra-fish/gafl-webapp-service",
3
- "version": "1.23.0",
3
+ "version": "1.24.0-rc.2",
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.23.0",
40
- "@defra-fish/connectors-lib": "1.23.0",
39
+ "@defra-fish/business-rules-lib": "1.24.0-rc.2",
40
+ "@defra-fish/connectors-lib": "1.24.0-rc.2",
41
41
  "@defra/hapi-gapi": "^1.1.0",
42
42
  "@hapi/boom": "^9.1.2",
43
43
  "@hapi/catbox-redis": "^6.0.2",
@@ -76,5 +76,5 @@
76
76
  "gulp-sourcemaps": "^3.0.0",
77
77
  "node-sass": "^6.0.1"
78
78
  },
79
- "gitHead": "17bfa0e0f8071495932dd25f05f70f936f42d676"
79
+ "gitHead": "e5369641c3f61b5bfcd5b378695122d6d90a1b38"
80
80
  }
@@ -302,7 +302,7 @@
302
302
  "licence_length_eight_day": "Mae trwyddedau wyth niwrnod yn ddilys am wyth niwrnod yn olynol o’r amser cychwyn a ddewiswch",
303
303
  "licence_length_error_choose": "Dewiswch hyd y drwydded",
304
304
  "licence_length_one_day": "Mae trwyddedau un diwrnod yn ddilys am 24 awr o’r amser cychwyn a ddewiswch",
305
- "licence_length_title_other": "How long do they want the licence for?",
305
+ "licence_length_title_other": "Am ba hyd y maent am gael y drwydded?",
306
306
  "licence_length_title_you": "Am ba hyd yr hoffech chi gael y drwydded?",
307
307
  "licence_num": "Licence number",
308
308
  "licence_start_days": " diwrnod nesaf",
@@ -358,7 +358,7 @@
358
358
  "licence_summary_type": "Type",
359
359
  "licence_type_12m": "12 mis",
360
360
  "licence_type_1d": "1 diwrnod",
361
- "licence_type_8d": "8 diwrnod",
361
+ "licence_type_8d": "8 niwrnod",
362
362
  "licence_type_attended_rods_note": "Mae’r gwialenni i’w defnyddio gan ddeiliad y drwydded yn unig ac mae’n rhaid eu goruchwylio ar bob adeg.",
363
363
  "licence_type_byelaws": "is-ddeddfau pysgota lleol (yn agor mewn tab newydd)",
364
364
  "licence_type_error_choose": "Dewiswch un o’r mathau o drwyddedau pysgota",
@@ -430,7 +430,7 @@
430
430
  "our_address_3": "Deanery Road",
431
431
  "our_address_4": "Bristol",
432
432
  "our_address_5": "BS1 5AH",
433
- "over_65": "Dros 65, ",
433
+ "over_65": "Dros 65",
434
434
  "payment_cancelled_title": "Your payment has been cancelled",
435
435
  "payment_failed_expired": "The payment was not completed within 90 minutes of being created",
436
436
  "payment_failed_not_taken": "No money has been taken from your account.",
@@ -430,7 +430,7 @@
430
430
  "our_address_3": "Deanery Road",
431
431
  "our_address_4": "Bristol",
432
432
  "our_address_5": "BS1 5AH",
433
- "over_65": "Over 65, ",
433
+ "over_65": "Over 65",
434
434
  "payment_cancelled_title": "Your payment has been cancelled",
435
435
  "payment_failed_expired": "The payment was not completed within 90 minutes of being created",
436
436
  "payment_failed_not_taken": "No money has been taken from your account.",
@@ -8,8 +8,8 @@ Object {
8
8
  "preferredMethodOfConfirmation": "email",
9
9
  },
10
10
  "uri": Object {
11
- "contact": "/buy/contact",
12
- "licenceConfirmationMethod": "/buy/confirmation-method",
11
+ "change": "licence-confirmation-method.url?change=mobile",
12
+ "contact": "contact.url",
13
13
  },
14
14
  }
15
15
  `;
@@ -1,7 +1,22 @@
1
- import { CONTACT } from '../../../../../uri.js'
1
+ import { CONTACT, LICENCE_CONFIRMATION_METHOD } from '../../../../../uri.js'
2
2
  import { HOW_CONTACTED } from '../../../../../processors/mapping-constants.js'
3
3
  import { getData } from '../route.js'
4
4
  import GetDataRedirect from '../../../../../handlers/get-data-redirect.js'
5
+ import { addLanguageCodeToUri } from '../../../../../processors/uri-helper.js'
6
+
7
+ jest.mock('../../../../../processors/uri-helper.js')
8
+ jest.mock('../../../../../processors/mapping-constants.js', () => ({
9
+ HOW_CONTACTED: {
10
+ none: 'nada',
11
+ email: 'e-mail',
12
+ text: 'mobile-phone'
13
+ }
14
+ }))
15
+ jest.mock('../../../../../uri.js', () => ({
16
+ ...jest.requireActual('../../../../../uri.js'),
17
+ CONTACT: { uri: 'contact.url' },
18
+ LICENCE_CONFIRMATION_METHOD: { uri: 'licence-confirmation-method.url' }
19
+ }))
5
20
 
6
21
  describe('.getData', () => {
7
22
  const createRequestMock = (options = {}) => ({
@@ -20,13 +35,42 @@ describe('.getData', () => {
20
35
  }))
21
36
  })
22
37
 
38
+ beforeEach(jest.resetAllMocks)
39
+
23
40
  it('if preferred method of confirmation is none, redirects to contact page', async () => {
24
41
  const getDataRedirectError = new GetDataRedirect(CONTACT.uri)
25
42
  const func = async () => await getData(createRequestMock({ preferredMethodOfConfirmation: HOW_CONTACTED.none }))
26
43
  await expect(func).rejects.toThrow(getDataRedirectError)
27
44
  })
28
45
 
46
+ describe.each([
47
+ { urlName: 'change', url: `${LICENCE_CONFIRMATION_METHOD.uri}?change=email`, preferredMethodOfConfirmation: HOW_CONTACTED.email },
48
+ { urlName: 'change', url: `${LICENCE_CONFIRMATION_METHOD.uri}?change=mobile`, preferredMethodOfConfirmation: HOW_CONTACTED.text },
49
+ { urlName: 'contact', url: CONTACT.uri, preferredMethodOfConfirmation: HOW_CONTACTED.email }
50
+ ])('$urlName $confirmation is decorated by addLanguageCodeToUri', ({ urlName, url, preferredMethodOfConfirmation }) => {
51
+ it(`passes request and ${urlName} url to addLanguageCodeToUri`, async () => {
52
+ const request = createRequestMock({ preferredMethodOfConfirmation })
53
+ await getData(request)
54
+ expect(addLanguageCodeToUri).toHaveBeenCalledWith(request, url)
55
+ })
56
+
57
+ it(`returns decorated value for ${urlName} from addLanguageCodeToUri`, async () => {
58
+ const expectedUrl = Symbol(urlName)
59
+ addLanguageCodeToUri.mockReturnValue(expectedUrl)
60
+ const request = createRequestMock()
61
+ const data = await getData(request)
62
+ expect(data).toEqual(
63
+ expect.objectContaining({
64
+ uri: expect.objectContaining({
65
+ [urlName]: expectedUrl
66
+ })
67
+ })
68
+ )
69
+ })
70
+ })
71
+
29
72
  it('returns the expected data', async () => {
73
+ addLanguageCodeToUri.mockImplementation((_request, uri) => uri)
30
74
  expect(await getData(createRequestMock())).toMatchSnapshot()
31
75
  })
32
76
  })
@@ -1,15 +1,12 @@
1
1
  {% extends "standard-form.njk" %}
2
2
  {% from "back-link/macro.njk" import govukBackLink %}
3
3
 
4
-
5
4
  {% if data.licensee.preferredMethodOfConfirmation == 'Email' %}
6
5
  {% set contactType = mssgs.email_address %}
7
6
  {% set contactInfo = data.licensee.email %}
8
- {% set changeLinkUrl = data.uri.licenceConfirmationMethod + '?change=email' %}
9
7
  {% else %}
10
8
  {% set contactType = mssgs.phone_number %}
11
9
  {% set contactInfo = data.licensee.mobilePhone %}
12
- {% set changeLinkUrl = data.uri.licenceConfirmationMethod + '?change=mobile' %}
13
10
  {% endif %}
14
11
 
15
12
  {% set title = mssgs.check_conf_contact_title_1 + contactType + mssgs.check_conf_contact_title_2 %}
@@ -36,7 +33,7 @@
36
33
  </p>
37
34
 
38
35
  <p class="govuk-body govuk-!-margin-bottom-6">
39
- <a class="govuk-link" href="{{ changeLinkUrl }}">
36
+ <a class="govuk-link" href="{{ data.uri.change }}">
40
37
  {{ mssgs.licence_summary_change }} {{ contactType }}
41
38
  </a>
42
39
  </p>
@@ -3,6 +3,7 @@ import { HOW_CONTACTED } from '../../../../processors/mapping-constants.js'
3
3
  import GetDataRedirect from '../../../../handlers/get-data-redirect.js'
4
4
  import pageRoute from '../../../../routes/page-route.js'
5
5
  import { nextPage } from '../../../../routes/next-page.js'
6
+ import { addLanguageCodeToUri } from '../../../../processors/uri-helper.js'
6
7
 
7
8
  export const getData = async request => {
8
9
  const { licensee } = await request.cache().helpers.transaction.getCurrentPermission()
@@ -11,11 +12,14 @@ export const getData = async request => {
11
12
  throw new GetDataRedirect(CONTACT.uri)
12
13
  }
13
14
 
15
+ const whatToChange = licensee.preferredMethodOfConfirmation === HOW_CONTACTED.email ? '?change=email' : '?change=mobile'
16
+ const change = addLanguageCodeToUri(request, `${LICENCE_CONFIRMATION_METHOD.uri}${whatToChange}`)
17
+
14
18
  return {
15
19
  licensee,
16
20
  uri: {
17
- licenceConfirmationMethod: LICENCE_CONFIRMATION_METHOD.uri,
18
- contact: CONTACT.uri
21
+ contact: addLanguageCodeToUri(request, CONTACT.uri),
22
+ change
19
23
  }
20
24
  }
21
25
  }
@@ -1,6 +1,6 @@
1
1
  import { getData } from '../route'
2
2
  import '../../../../processors/pricing-summary.js'
3
- import '../../../../processors/licence-type-display.js'
3
+ import { licenceTypeDisplay } from '../../../../processors/licence-type-display.js'
4
4
 
5
5
  jest.mock('../../../../processors/pricing-summary.js')
6
6
  jest.mock('../../../../processors/licence-type-display.js')
@@ -15,7 +15,10 @@ describe('licence-length > route', () => {
15
15
  getCurrentPermission: mockTransactionCacheGet
16
16
  }
17
17
  }
18
- })
18
+ }),
19
+ i18n: {
20
+ getCatalog: () => ({})
21
+ }
19
22
  }
20
23
 
21
24
  describe('getData', () => {
@@ -30,5 +33,32 @@ describe('licence-length > route', () => {
30
33
  const result = await getData(mockRequest)
31
34
  expect(result.isLicenceForYou).toBeFalsy()
32
35
  })
36
+
37
+ it('licenceTypeDisplay is called with the expected arguments', async () => {
38
+ const catalog = Symbol('mock catalog')
39
+ const permission = Symbol('mock permission')
40
+ const sampleRequest = {
41
+ ...mockRequest,
42
+ i18n: {
43
+ getCatalog: () => catalog
44
+ }
45
+ }
46
+ mockTransactionCacheGet.mockImplementationOnce(() => permission)
47
+
48
+ await getData(sampleRequest)
49
+
50
+ expect(licenceTypeDisplay).toHaveBeenCalledWith(permission, catalog)
51
+ })
52
+
53
+ it('return value of licenceTypeDisplay is used for licenceTypeStr', async () => {
54
+ const returnValue = Symbol('return value')
55
+ licenceTypeDisplay.mockReturnValueOnce(returnValue)
56
+ mockTransactionCacheGet.mockImplementationOnce(() => ({ isLicenceForYou: false }))
57
+
58
+ const result = await getData(mockRequest)
59
+ const ret = result.licenceTypeStr
60
+
61
+ expect(ret).toEqual(returnValue)
62
+ })
33
63
  })
34
64
  })
@@ -56,8 +56,8 @@
56
56
  {% block pricingSummary %}
57
57
  {{ pricingSummary(data.pricing.byLength, {
58
58
  'total': { desc: mssgs.total }
59
- }, mssgs,
60
- data.licenceTypeStr
59
+ }, data.licenceTypeStr,
60
+ mssgs
61
61
  )}}
62
62
  {% endblock %}
63
63
 
@@ -18,7 +18,7 @@ export const getData = async request => {
18
18
  return {
19
19
  pricing,
20
20
  isLicenceForYou: permission.isLicenceForYou,
21
- licenceTypeStr: licenceTypeDisplay(permission)
21
+ licenceTypeStr: licenceTypeDisplay(permission, request.i18n.getCatalog())
22
22
  }
23
23
  }
24
24
 
@@ -81,8 +81,8 @@
81
81
  '8D': { desc: mssgs.licence_type_8d },
82
82
  '1D': { desc: mssgs.licence_type_1d },
83
83
  'no-short': mssgs.licence_type_na
84
- }, mssgs,
85
- null
84
+ }, null,
85
+ mssgs
86
86
  )}}
87
87
  {% endblock %}
88
88
 
@@ -1,13 +1,9 @@
1
- {% from "licence-type-summary.njk" import licenceTypeSummary %}
2
-
3
- {% macro pricingSummary(selectors, content, mssgs, licenceType) %}
1
+ {% macro pricingSummary(selectors, content, subHeader, mssgs) %}
4
2
  <aside class="govuk-grid-column-one-third payment-summary-wrap">
5
3
  {% for selector, load in selectors %}
6
4
  <div id="pricing-{{ selector }}" role="status" class="payment-summary initially-hidden">
7
5
  <h2 class="govuk-heading-m">{{ mssgs.no_licence_req_body }}</h2>
8
- {% block licenceTypeSummary %}
9
- {{ licenceTypeSummary(mssgs, licenceType) }}
10
- {% endblock %}
6
+ <p class="govuk-body-s">{{ subHeader }}</p>
11
7
  {% for k, v in load %}
12
8
  {% if content[k].desc %}
13
9
  <div class="govuk-body" id="pricing-summary-element-cost">
@@ -69,5 +69,11 @@ const createMockRequest = status => ({
69
69
  }))
70
70
  }
71
71
  }
72
- }))
72
+ })),
73
+ i18n: {
74
+ getCatalog: () => ({
75
+ over_65: 'Over 65',
76
+ licence_type_radio_trout_three_rod: 'Trout and coarse, up to 3 rods'
77
+ })
78
+ }
73
79
  })
@@ -0,0 +1,89 @@
1
+ import { getData } from '../route'
2
+ import { licenceTypeDisplay } from '../../../../processors/licence-type-display.js'
3
+ import { COMPLETION_STATUS, CommonResults, ShowDigitalLicencePages } from '../../../../constants.js'
4
+
5
+ jest.mock('../../../../processors/licence-type-display.js')
6
+ jest.mock('../../../../constants', () => ({
7
+ COMPLETION_STATUS: {
8
+ agreed: 'agreed',
9
+ posted: 'posted',
10
+ finalised: 'finalised'
11
+ },
12
+ CommonResults: {
13
+ ok: 'ok'
14
+ },
15
+ ShowDigitalLicencePages: {
16
+ YES: 'yes'
17
+ }
18
+ }))
19
+
20
+ describe('licence-length > route', () => {
21
+ const mockTransactionCacheGet = jest.fn()
22
+ const mockStatusCacheGet = jest.fn()
23
+
24
+ const mockRequest = {
25
+ cache: () => ({
26
+ helpers: {
27
+ transaction: {
28
+ getCurrentPermission: mockTransactionCacheGet
29
+ },
30
+ status: {
31
+ get: mockStatusCacheGet
32
+ }
33
+ }
34
+ }),
35
+ i18n: {
36
+ getCatalog: () => ({})
37
+ }
38
+ }
39
+
40
+ describe('getData', () => {
41
+ it('licenceTypeDisplay is called with the expected arguments', async () => {
42
+ const catalog = Symbol('mock catalog')
43
+ const permission = Symbol('mock permission')
44
+ const status = {
45
+ [COMPLETION_STATUS.agreed]: 'agreed',
46
+ [COMPLETION_STATUS.posted]: 'posted',
47
+ [COMPLETION_STATUS.finalised]: 'finalised',
48
+ [CommonResults.OK]: 'ok',
49
+ [ShowDigitalLicencePages.YES]: 'yes'
50
+ }
51
+ const sampleRequest = {
52
+ ...mockRequest,
53
+ i18n: {
54
+ getCatalog: () => catalog
55
+ }
56
+ }
57
+ mockTransactionCacheGet.mockImplementationOnce(() => permission)
58
+ mockStatusCacheGet.mockImplementationOnce(() => status)
59
+
60
+ await getData(sampleRequest)
61
+
62
+ expect(licenceTypeDisplay).toHaveBeenCalledWith(permission, catalog)
63
+ })
64
+
65
+ it('return value of licenceTypeDisplay is used for licenceTypeStr', async () => {
66
+ const returnValue = Symbol('return value')
67
+ licenceTypeDisplay.mockReturnValueOnce(returnValue)
68
+
69
+ const permission = {
70
+ startDate: '2021-01-01'
71
+ }
72
+
73
+ const status = {
74
+ [COMPLETION_STATUS.agreed]: 'agreed',
75
+ [COMPLETION_STATUS.posted]: 'posted',
76
+ [COMPLETION_STATUS.finalised]: 'finalised',
77
+ [CommonResults.OK]: 'ok',
78
+ [ShowDigitalLicencePages.YES]: 'yes'
79
+ }
80
+ mockTransactionCacheGet.mockImplementationOnce(() => permission)
81
+ mockStatusCacheGet.mockImplementationOnce(() => status)
82
+
83
+ const result = await getData(mockRequest)
84
+ const ret = result.licenceTypeStr
85
+
86
+ expect(ret).toEqual(returnValue)
87
+ })
88
+ })
89
+ })
@@ -34,7 +34,7 @@ export const getData = async request => {
34
34
  endTimeString,
35
35
  disabled: concessionHelper.hasDisabled(permission),
36
36
  ageConcession: concessionHelper.getAgeConcession(permission),
37
- licenceTypeStr: licenceTypeDisplay(permission)
37
+ licenceTypeStr: licenceTypeDisplay(permission, request.i18n.getCatalog())
38
38
  }
39
39
  }
40
40
 
@@ -3,8 +3,10 @@ import { LICENCE_SUMMARY_SEEN, CONTACT_SUMMARY_SEEN } from '../../../../constant
3
3
  import { NAME } from '../../../../uri.js'
4
4
  import GetDataRedirect from '../../../../handlers/get-data-redirect.js'
5
5
  import '../../find-permit.js'
6
+ import { licenceTypeDisplay } from '../../../../processors/licence-type-display.js'
6
7
 
7
8
  jest.mock('../../find-permit.js')
9
+ jest.mock('../../../../processors/licence-type-display.js')
8
10
 
9
11
  describe('licence-summary > route', () => {
10
12
  beforeEach(jest.clearAllMocks)
@@ -59,7 +61,12 @@ describe('licence-summary > route', () => {
59
61
  setCurrentPermission: mockTransactionCacheSet
60
62
  }
61
63
  }
62
- })
64
+ }),
65
+ i18n: {
66
+ getCatalog: () => ({
67
+ licence_type_radio_salmon: 'Salmon and sea trout'
68
+ })
69
+ }
63
70
  }
64
71
 
65
72
  it('should return the name page uri', async () => {
@@ -106,5 +113,40 @@ describe('licence-summary > route', () => {
106
113
  expect(error).toBeInstanceOf(GetDataRedirect)
107
114
  expect(error.redirectUrl).toBe(NAME.uri)
108
115
  })
116
+
117
+ it('licenceTypeDisplay is called with the expected arguments', async () => {
118
+ mockStatusCacheGet.mockImplementationOnce(() => ({ renewal: true }))
119
+ const catalog = Symbol('mock catalog')
120
+ const permission = {
121
+ permit: {
122
+ cost: 1
123
+ },
124
+ licensee: {
125
+ birthDate: '1996-01-01'
126
+ }
127
+ }
128
+ const sampleRequest = {
129
+ ...mockRequest,
130
+ i18n: {
131
+ getCatalog: () => catalog
132
+ }
133
+ }
134
+
135
+ mockTransactionCacheGet.mockImplementationOnce(() => permission)
136
+
137
+ await getData(sampleRequest)
138
+
139
+ expect(licenceTypeDisplay).toHaveBeenCalledWith(permission, catalog)
140
+ })
141
+
142
+ it('return value of licenceTypeDisplay is used for licenceTypeStr', async () => {
143
+ const returnValue = Symbol('return value')
144
+ licenceTypeDisplay.mockReturnValueOnce(returnValue)
145
+
146
+ const result = await getData(mockRequest)
147
+ const ret = result.licenceTypeStr
148
+
149
+ expect(ret).toEqual(returnValue)
150
+ })
109
151
  })
110
152
  })
@@ -67,7 +67,7 @@ export const getData = async request => {
67
67
  permission,
68
68
  startTimeString,
69
69
  startAfterPaymentMinutes: START_AFTER_PAYMENT_MINUTES,
70
- licenceTypeStr: licenceTypeDisplay(permission),
70
+ licenceTypeStr: licenceTypeDisplay(permission, request.i18n.getCatalog()),
71
71
  isRenewal: status.renewal,
72
72
  isContinuing: !!(permission.renewedEndDate && permission.renewedEndDate === permission.licenceStartDate),
73
73
  hasExpired: moment(moment().tz(SERVICE_LOCAL_TIME)).isAfter(moment(permission.renewedEndDate, cacheDateFormat)),
@@ -0,0 +1,103 @@
1
+ import { hasJunior, hasSenior } from '../concession-helper.js'
2
+ import { licenceTypeDisplay, licenceTypeAndLengthDisplay, isPhysical } from '../licence-type-display.js'
3
+
4
+ const permission = {}
5
+
6
+ const mssgs = {
7
+ over_65: 'Over 65',
8
+ age_junior: 'Junior',
9
+ licence_type_radio_salmon: 'Salmon and sea trout',
10
+ licence_type_radio_trout_two_rod: 'Trout and coarse, up to 2 rods',
11
+ licence_type_radio_trout_three_rod: 'Trout and coarse, up to 3 rods'
12
+ }
13
+
14
+ jest.mock('../concession-helper', () => ({
15
+ hasJunior: jest.fn(),
16
+ hasSenior: jest.fn()
17
+ }))
18
+
19
+ jest.mock('../mapping-constants', () => ({
20
+ LICENCE_TYPE: {
21
+ 'trout-and-coarse': 'Trout and coarse',
22
+ 'salmon-and-sea-trout': 'Salmon and sea trout'
23
+ }
24
+ }))
25
+
26
+ describe('licenceTypeDisplay', () => {
27
+ it('returns junior if person is junior', () => {
28
+ hasJunior.mockImplementationOnce(() => true)
29
+ permission.licenceType = 'Salmon and sea trout'
30
+ const result = licenceTypeDisplay(permission, mssgs)
31
+ expect(result).toEqual('Junior, Salmon and sea trout')
32
+ })
33
+
34
+ it('returns senior if person is senior', () => {
35
+ hasSenior.mockImplementationOnce(() => true)
36
+ permission.licenceType = 'Salmon and sea trout'
37
+ const result = licenceTypeDisplay(permission, mssgs)
38
+ expect(result).toEqual('Over 65, Salmon and sea trout')
39
+ })
40
+
41
+ it.each([
42
+ ['Salmon and sea trout', null, 'Salmon and sea trout'],
43
+ ['Trout and coarse', '2', 'Trout and coarse, up to 2 rods'],
44
+ ['Trout and coarse', '3', 'Trout and coarse, up to 3 rods']
45
+ ])('returns correct licence type', (licenceType, numberOfRods, expected) => {
46
+ permission.licenceType = licenceType
47
+ permission.numberOfRods = numberOfRods
48
+ const result = licenceTypeDisplay(permission, mssgs)
49
+ expect(result).toEqual(expected)
50
+ })
51
+ })
52
+
53
+ describe('licenceTypeAndLengthDisplay', () => {
54
+ it.each([
55
+ ['12M', 'Salmon and sea trout', null, 'Salmon and sea trout, 12 months'],
56
+ ['12M', 'Trout and coarse', '2', 'Trout and coarse, up to 2 rods, 12 months'],
57
+ ['12M', 'Trout and coarse', '3', 'Trout and coarse, up to 3 rods, 12 months'],
58
+ ['8D', 'Salmon and sea trout', null, 'Salmon and sea trout, 8 days'],
59
+ ['8D', 'Trout and coarse', '2', 'Trout and coarse, up to 2 rods, 8 days'],
60
+ ['8D', 'Trout and coarse', '3', 'Trout and coarse, up to 3 rods, 8 days'],
61
+ ['1D', 'Salmon and sea trout', null, 'Salmon and sea trout, 1 day'],
62
+ ['1D', 'Trout and coarse', '2', 'Trout and coarse, up to 2 rods, 1 day'],
63
+ ['1D', 'Trout and coarse', '3', 'Trout and coarse, up to 3 rods, 1 day']
64
+ ])('returns correct licence length', (licenceLength, licenceType, numberOfRods, expected) => {
65
+ permission.licenceLength = licenceLength
66
+ permission.licenceType = licenceType
67
+ permission.numberOfRods = numberOfRods
68
+ const result = licenceTypeAndLengthDisplay(permission, mssgs)
69
+ expect(result).toEqual(expected)
70
+ })
71
+
72
+ it('returns junior if licence length is junior', () => {
73
+ hasJunior.mockImplementationOnce(() => true)
74
+ permission.licenceLength = '12M'
75
+ permission.licenceType = 'Salmon and sea trout'
76
+ const result = licenceTypeAndLengthDisplay(permission, mssgs)
77
+ expect(result).toEqual('Junior, Salmon and sea trout, 12 months')
78
+ })
79
+
80
+ it('returns senior if licence length is senior', () => {
81
+ hasSenior.mockImplementationOnce(() => true)
82
+ permission.licenceLength = '12M'
83
+ permission.licenceType = 'Salmon and sea trout'
84
+ const result = licenceTypeAndLengthDisplay(permission, mssgs)
85
+ expect(result).toEqual('Over 65, Salmon and sea trout, 12 months')
86
+ })
87
+ })
88
+
89
+ describe('isPhysical', () => {
90
+ it('returns true if licence length is 12 months and is not a junior', () => {
91
+ hasJunior.mockImplementationOnce(() => false)
92
+ permission.licenceLength = '12M'
93
+ const result = isPhysical(permission)
94
+ expect(result).toEqual(true)
95
+ })
96
+
97
+ it('returns false if licence length is not 12 months and a junior', () => {
98
+ hasJunior.mockImplementationOnce(() => true)
99
+ permission.licenceLength = '8D'
100
+ const result = isPhysical(permission)
101
+ expect(result).toEqual(false)
102
+ })
103
+ })
@@ -5,6 +5,9 @@ jest.mock('../licence-type-display.js')
5
5
  licenceTypeAndLengthDisplay.mockReturnValue('Trout and coarse, up to 2 rods, 8 day')
6
6
 
7
7
  const createRequest = (opts = {}) => ({
8
+ i18n: {
9
+ getCatalog: () => ({})
10
+ },
8
11
  headers: opts.headers || { 'x-forwarded-proto': 'https' },
9
12
  info: { host: opts.host || 'localhost:1234' },
10
13
  server: { info: { protocol: opts.protocol || '' } }
@@ -64,6 +67,46 @@ describe('preparePayment', () => {
64
67
  expect(result.reference).toBe(transaction.id)
65
68
  })
66
69
 
70
+ it('licenceTypeAndLengthDisplay is called with the expected arguments', () => {
71
+ const catalog = Symbol('mock catalog')
72
+ const createMockRequest = (opts = {}) => ({
73
+ i18n: {
74
+ getCatalog: () => catalog
75
+ },
76
+ headers: opts.headers || { 'x-forwarded-proto': 'https' },
77
+ info: { host: opts.host || 'localhost:1234' },
78
+ server: { info: { protocol: opts.protocol || '' } }
79
+ })
80
+ const request = createMockRequest()
81
+ const permission = {
82
+ licensee: {
83
+ firstName: 'Lando',
84
+ lastName: 'Norris',
85
+ email: 'test@example.com',
86
+ premises: '4',
87
+ street: 'Buttercup lane',
88
+ locality: 'Clifton',
89
+ postcode: 'BS8 3TP',
90
+ town: 'Bristol',
91
+ country: 'GB-ENG'
92
+ }
93
+ }
94
+
95
+ preparePayment(request, transaction)
96
+
97
+ expect(licenceTypeAndLengthDisplay).toHaveBeenCalledWith(permission, catalog)
98
+ })
99
+
100
+ it('return value of licenceTypeDisplay', () => {
101
+ const returnValue = Symbol('return value')
102
+ licenceTypeAndLengthDisplay.mockReturnValueOnce(returnValue)
103
+
104
+ const result = preparePayment(request, transaction)
105
+ const ret = result.description
106
+
107
+ expect(ret).toEqual(returnValue)
108
+ })
109
+
67
110
  describe('provides the correct description', () => {
68
111
  it('when there is only 1 permission', () => {
69
112
  expect(result.description).toBe('Trout and coarse, up to 2 rods, 8 day')
@@ -18,4 +18,31 @@ describe('URI Helpers: addLanguageCodeToURI', () => {
18
18
  const result = addLanguageCodeToUri(mockRequest, uri)
19
19
  expect(result).toEqual(expect.stringMatching(new RegExp(expected)))
20
20
  })
21
+
22
+ describe.each([
23
+ ['https://my-url.com/path?data=true', 'https://my-url.com/path?data=true&lang=cy'],
24
+ ['https://my-url.com/path?data-1=false&data-2=9', 'https://my-url.com/path?data-1=false&data-2=9&lang=cy']
25
+ ])('', (urlToDecorate, decoratedUrl) => {
26
+ it('if the supplied url has a querystring already, the language parameter is added to the end with an ampersand', () => {
27
+ const mockRequest = {
28
+ path: '/any/page',
29
+ url: {
30
+ search: '?lang=cy'
31
+ }
32
+ }
33
+ const result = addLanguageCodeToUri(mockRequest, urlToDecorate)
34
+ expect(result).toEqual(decoratedUrl)
35
+ })
36
+
37
+ it('if the request.path is used instead of a url and has a querystring, the language parameter is added to the end with an ampersand', () => {
38
+ const mockRequest = {
39
+ path: urlToDecorate,
40
+ url: {
41
+ search: '?lang=cy'
42
+ }
43
+ }
44
+ const result = addLanguageCodeToUri(mockRequest, urlToDecorate)
45
+ expect(result).toEqual(decoratedUrl)
46
+ })
47
+ })
21
48
  })
@@ -1,33 +1,37 @@
1
1
  import * as concessionHelper from './concession-helper.js'
2
2
  import * as mappings from './mapping-constants.js'
3
3
 
4
- export const licenceTypeDisplay = permission => {
4
+ export const licenceTypeDisplay = (permission, mssgs) => {
5
5
  const typesStrArr = []
6
6
 
7
7
  // Build the display string for the licence type
8
8
  if (concessionHelper.hasJunior(permission)) {
9
- typesStrArr.push('Junior')
9
+ typesStrArr.push(mssgs.age_junior)
10
10
  } else if (concessionHelper.hasSenior(permission)) {
11
- typesStrArr.push('Over 65')
11
+ typesStrArr.push(mssgs.over_65)
12
12
  }
13
13
 
14
- typesStrArr.push(permission.licenceType)
15
-
16
- if (permission.licenceType === mappings.LICENCE_TYPE['trout-and-coarse']) {
17
- typesStrArr.push(permission.numberOfRods === '2' ? 'up to 2 rods' : 'up to 3 rods')
14
+ if (permission.licenceType === mappings.LICENCE_TYPE['salmon-and-sea-trout']) {
15
+ typesStrArr.push(mssgs.licence_type_radio_salmon)
16
+ } else if (permission.licenceType === mappings.LICENCE_TYPE['trout-and-coarse']) {
17
+ if (permission.numberOfRods === '2') {
18
+ typesStrArr.push(mssgs.licence_type_radio_trout_two_rod)
19
+ } else {
20
+ typesStrArr.push(mssgs.licence_type_radio_trout_three_rod)
21
+ }
18
22
  }
19
23
 
20
24
  return typesStrArr.join(', ')
21
25
  }
22
26
 
23
- export const licenceTypeAndLengthDisplay = permission => {
27
+ export const licenceTypeAndLengthDisplay = (permission, mssgs) => {
24
28
  switch (permission.licenceLength) {
25
29
  case '12M':
26
- return `${licenceTypeDisplay(permission)}, 12 months`
30
+ return `${licenceTypeDisplay(permission, mssgs)}, 12 months`
27
31
  case '8D':
28
- return `${licenceTypeDisplay(permission)}, 8 days`
32
+ return `${licenceTypeDisplay(permission, mssgs)}, 8 days`
29
33
  default:
30
- return `${licenceTypeDisplay(permission)}, 1 day`
34
+ return `${licenceTypeDisplay(permission, mssgs)}, 1 day`
31
35
  }
32
36
  }
33
37
 
@@ -23,7 +23,10 @@ export const preparePayment = (request, transaction) => {
23
23
  return_url: url.href,
24
24
  amount: transaction.cost * 100,
25
25
  reference: transaction.id,
26
- description: transaction.permissions.length === 1 ? licenceTypeAndLengthDisplay(transaction.permissions[0]) : 'Multiple permits',
26
+ description:
27
+ transaction.permissions.length === 1
28
+ ? licenceTypeAndLengthDisplay(transaction.permissions[0], request.i18n.getCatalog())
29
+ : 'Multiple permits',
27
30
  delayed_capture: false,
28
31
  moto: process.env.CHANNEL === 'telesales'
29
32
  }
@@ -1,4 +1,5 @@
1
1
  export const addLanguageCodeToUri = (request, uri) => {
2
2
  const path = uri || request.path
3
- return `${path}${/\?.*lang=cy.*$/.test(request.url.search) ? '?lang=cy' : ''}`
3
+ const languageSpecifier = /.*\?.*/.test(path) ? '&lang=cy' : '?lang=cy'
4
+ return `${path}${/\?.*lang=cy.*$/.test(request.url.search) ? languageSpecifier : ''}`
4
5
  }
@@ -5,19 +5,56 @@ import { AGREED } from '../../../uri.js'
5
5
  describe('The govuk-pay-service', () => {
6
6
  it('prepares a correct payment response endpoint for http', async () => {
7
7
  expect(
8
- preparePayment({ info: { host: '0.0.0.0:3000' }, headers: { 'x-forwarded-proto': 'http' } }, mockTransaction).return_url
8
+ preparePayment(
9
+ {
10
+ i18n: {
11
+ getCatalog: () => ({
12
+ over_65: 'Over 65',
13
+ licence_type_radio_trout_three_rod: 'Trout and coarse, up to 3 rods'
14
+ })
15
+ },
16
+ info: { host: '0.0.0.0:3000' },
17
+ headers: { 'x-forwarded-proto': 'http' }
18
+ },
19
+ mockTransaction
20
+ ).return_url
9
21
  ).toEqual('http://0.0.0.0:3000' + AGREED.uri)
10
22
  })
11
23
 
12
24
  it('prepares a correct payment response endpoint for https', async () => {
13
25
  expect(
14
- preparePayment({ info: { host: '0.0.0.0:3000' }, headers: { 'x-forwarded-proto': 'https' } }, mockTransaction).return_url
26
+ preparePayment(
27
+ {
28
+ i18n: {
29
+ getCatalog: () => ({
30
+ over_65: 'Over 65',
31
+ licence_type_radio_trout_three_rod: 'Trout and coarse, up to 3 rods'
32
+ })
33
+ },
34
+ info: { host: '0.0.0.0:3000' },
35
+ headers: { 'x-forwarded-proto': 'https' }
36
+ },
37
+ mockTransaction
38
+ ).return_url
15
39
  ).toEqual('https://0.0.0.0:3000' + AGREED.uri)
16
40
  })
17
41
 
18
42
  it('prepares a correct payment creation object', async () => {
19
43
  expect(
20
- preparePayment({ info: { host: '0.0.0.0:3000' }, headers: {}, server: { info: { protocol: 'https' } } }, mockTransaction)
44
+ preparePayment(
45
+ {
46
+ i18n: {
47
+ getCatalog: () => ({
48
+ over_65: 'Over 65',
49
+ licence_type_radio_salmon: 'Salmon and sea trout'
50
+ })
51
+ },
52
+ info: { host: '0.0.0.0:3000' },
53
+ headers: {},
54
+ server: { info: { protocol: 'https' } }
55
+ },
56
+ mockTransaction
57
+ )
21
58
  ).toEqual({
22
59
  amount: 5400,
23
60
  delayed_capture: false,
@@ -42,7 +79,21 @@ describe('The govuk-pay-service', () => {
42
79
  const mockTransaction2 = Object.assign({}, mockTransaction)
43
80
  mockTransaction2.permissions[0].licensee.locality = 'Stoke Bishop'
44
81
  mockTransaction2.permissions[0].licenceLength = '8D'
45
- expect(preparePayment({ info: { host: '0.0.0.0:3000' }, headers: { 'x-forwarded-proto': 'https' } }, mockTransaction2)).toEqual({
82
+ expect(
83
+ preparePayment(
84
+ {
85
+ i18n: {
86
+ getCatalog: () => ({
87
+ over_65: 'Over 65',
88
+ licence_type_radio_salmon: 'Salmon and sea trout'
89
+ })
90
+ },
91
+ info: { host: '0.0.0.0:3000' },
92
+ headers: { 'x-forwarded-proto': 'https' }
93
+ },
94
+ mockTransaction2
95
+ )
96
+ ).toEqual({
46
97
  amount: 5400,
47
98
  delayed_capture: false,
48
99
  description: 'Over 65, Salmon and sea trout, 8 days',
@@ -1,19 +0,0 @@
1
- {% macro licenceTypeSummary(mssgs, licenceTypeStr) %}
2
- {% set licenceTypeSubHeading %}
3
- {% if licenceTypeStr === 'Over 65, Trout and coarse, up to 2 rods' %}
4
- {{ mssgs.over_65 + mssgs.licence_type_radio_trout_two_rod }}
5
- {% elseif licenceTypeStr === 'Over 65, Trout and coarse, up to 3 rods' %}
6
- {{ mssgs.over_65 + mssgs.licence_type_radio_trout_three_rod }}
7
- {% elseif licenceTypeStr === 'Over 65, Salmon and sea trout' %}
8
- {{ mssgs.over_65 + mssgs.licence_type_radio_salmon }}
9
- {% elseif licenceTypeStr === 'Trout and coarse, up to 2 rods' %}
10
- {{ mssgs.licence_type_radio_trout_two_rod }}
11
- {% elseif licenceTypeStr === 'Trout and coarse, up to 3 rods' %}
12
- {{ mssgs.licence_type_radio_trout_three_rod }}
13
- {% elseif licenceTypeStr === 'Salmon and sea trout' %}
14
- {{ mssgs.licence_type_radio_salmon }}
15
- {% endif %}
16
- {% endset %}
17
- <p class="govuk-body-s">{{ licenceTypeSubHeading }}</p>
18
- {% endmacro %}
19
-