@defra/forms-engine-plugin 4.0.0 → 4.0.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 (108) hide show
  1. package/.public/stylesheets/application.min.css +2 -2
  2. package/.public/stylesheets/application.min.css.map +1 -1
  3. package/.server/client/stylesheets/shared.scss +15 -0
  4. package/.server/config/index.d.ts +1 -0
  5. package/.server/config/index.js +7 -0
  6. package/.server/config/index.js.map +1 -1
  7. package/.server/index.js +6 -2
  8. package/.server/index.js.map +1 -1
  9. package/.server/server/constants.d.ts +2 -0
  10. package/.server/server/constants.js +2 -0
  11. package/.server/server/constants.js.map +1 -1
  12. package/.server/server/forms/components.json +7 -0
  13. package/.server/server/forms/register-as-a-unicorn-breeder.yaml +18 -2
  14. package/.server/server/plugins/engine/components/UkAddressField.d.ts +15 -9
  15. package/.server/server/plugins/engine/components/UkAddressField.js +67 -6
  16. package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
  17. package/.server/server/plugins/engine/configureEnginePlugin.d.ts +1 -1
  18. package/.server/server/plugins/engine/configureEnginePlugin.js +6 -3
  19. package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -1
  20. package/.server/server/plugins/engine/models/FormModel.d.ts +2 -0
  21. package/.server/server/plugins/engine/models/FormModel.js +3 -1
  22. package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
  23. package/.server/server/plugins/engine/options.js +2 -1
  24. package/.server/server/plugins/engine/options.js.map +1 -1
  25. package/.server/server/plugins/engine/pageControllers/QuestionPageController.d.ts +1 -0
  26. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +46 -3
  27. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
  28. package/.server/server/plugins/engine/plugin.js +13 -1
  29. package/.server/server/plugins/engine/plugin.js.map +1 -1
  30. package/.server/server/plugins/engine/routes/index.js +41 -3
  31. package/.server/server/plugins/engine/routes/index.js.map +1 -1
  32. package/.server/server/plugins/engine/types.d.ts +19 -1
  33. package/.server/server/plugins/engine/types.js.map +1 -1
  34. package/.server/server/plugins/engine/validationHelpers.d.ts +15 -0
  35. package/.server/server/plugins/engine/validationHelpers.js +29 -0
  36. package/.server/server/plugins/engine/validationHelpers.js.map +1 -0
  37. package/.server/server/plugins/engine/views/components/ukaddressfield.html +50 -6
  38. package/.server/server/plugins/engine/vision.js +3 -1
  39. package/.server/server/plugins/engine/vision.js.map +1 -1
  40. package/.server/server/plugins/postcode-lookup/index.d.ts +8 -0
  41. package/.server/server/plugins/postcode-lookup/index.js +21 -0
  42. package/.server/server/plugins/postcode-lookup/index.js.map +1 -0
  43. package/.server/server/plugins/postcode-lookup/models/index.d.ts +255 -0
  44. package/.server/server/plugins/postcode-lookup/models/index.js +517 -0
  45. package/.server/server/plugins/postcode-lookup/models/index.js.map +1 -0
  46. package/.server/server/plugins/postcode-lookup/routes/index.d.ts +19 -0
  47. package/.server/server/plugins/postcode-lookup/routes/index.js +267 -0
  48. package/.server/server/plugins/postcode-lookup/routes/index.js.map +1 -0
  49. package/.server/server/plugins/postcode-lookup/service.d.ts +26 -0
  50. package/.server/server/plugins/postcode-lookup/service.js +148 -0
  51. package/.server/server/plugins/postcode-lookup/service.js.map +1 -0
  52. package/.server/server/plugins/postcode-lookup/service.test.js +144 -0
  53. package/.server/server/plugins/postcode-lookup/service.test.js.map +1 -0
  54. package/.server/server/plugins/postcode-lookup/test/__stubs__/postcode.d.ts +282 -0
  55. package/.server/server/plugins/postcode-lookup/test/__stubs__/postcode.js +370 -0
  56. package/.server/server/plugins/postcode-lookup/test/__stubs__/postcode.js.map +1 -0
  57. package/.server/server/plugins/postcode-lookup/test/__stubs__/query.d.ts +131 -0
  58. package/.server/server/plugins/postcode-lookup/test/__stubs__/query.js +195 -0
  59. package/.server/server/plugins/postcode-lookup/test/__stubs__/query.js.map +1 -0
  60. package/.server/server/plugins/postcode-lookup/test/__stubs__/uprn.d.ts +51 -0
  61. package/.server/server/plugins/postcode-lookup/test/__stubs__/uprn.js +52 -0
  62. package/.server/server/plugins/postcode-lookup/test/__stubs__/uprn.js.map +1 -0
  63. package/.server/server/plugins/postcode-lookup/types.d.ts +204 -0
  64. package/.server/server/plugins/postcode-lookup/types.js +144 -0
  65. package/.server/server/plugins/postcode-lookup/types.js.map +1 -0
  66. package/.server/server/plugins/postcode-lookup/views/postcode-lookup-details.html +83 -0
  67. package/.server/server/routes/types.d.ts +6 -1
  68. package/.server/server/routes/types.js +6 -0
  69. package/.server/server/routes/types.js.map +1 -1
  70. package/.server/server/schemas/index.js +1 -1
  71. package/.server/server/schemas/index.js.map +1 -1
  72. package/.server/server/types.d.ts +1 -0
  73. package/.server/server/types.js.map +1 -1
  74. package/package.json +2 -2
  75. package/src/client/stylesheets/shared.scss +15 -0
  76. package/src/config/index.ts +9 -1
  77. package/src/index.ts +5 -4
  78. package/src/server/constants.js +2 -0
  79. package/src/server/forms/components.json +7 -0
  80. package/src/server/forms/register-as-a-unicorn-breeder.yaml +18 -2
  81. package/src/server/plugins/engine/components/UkAddressField.test.ts +50 -27
  82. package/src/server/plugins/engine/components/UkAddressField.ts +91 -8
  83. package/src/server/plugins/engine/configureEnginePlugin.ts +5 -3
  84. package/src/server/plugins/engine/models/FormModel.ts +10 -2
  85. package/src/server/plugins/engine/options.js +2 -1
  86. package/src/server/plugins/engine/pageControllers/QuestionPageController.test.ts +1 -0
  87. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +69 -1
  88. package/src/server/plugins/engine/plugin.ts +13 -1
  89. package/src/server/plugins/engine/routes/index.test.ts +1 -0
  90. package/src/server/plugins/engine/routes/index.ts +71 -3
  91. package/src/server/plugins/engine/types.ts +21 -1
  92. package/src/server/plugins/engine/validationHelpers.ts +48 -0
  93. package/src/server/plugins/engine/views/components/ukaddressfield.html +50 -6
  94. package/src/server/plugins/engine/vision.ts +6 -0
  95. package/src/server/plugins/postcode-lookup/index.js +21 -0
  96. package/src/server/plugins/postcode-lookup/models/index.js +549 -0
  97. package/src/server/plugins/postcode-lookup/routes/index.js +258 -0
  98. package/src/server/plugins/postcode-lookup/service.js +188 -0
  99. package/src/server/plugins/postcode-lookup/service.test.js +177 -0
  100. package/src/server/plugins/postcode-lookup/test/__stubs__/postcode.js +382 -0
  101. package/src/server/plugins/postcode-lookup/test/__stubs__/query.js +200 -0
  102. package/src/server/plugins/postcode-lookup/test/__stubs__/uprn.js +53 -0
  103. package/src/server/plugins/postcode-lookup/types.js +143 -0
  104. package/src/server/plugins/postcode-lookup/views/postcode-lookup-details.html +83 -0
  105. package/src/server/postcode-lookup.test.ts +64 -0
  106. package/src/server/routes/types.ts +7 -1
  107. package/src/server/schemas/index.ts +5 -7
  108. package/src/server/types.ts +1 -0
@@ -0,0 +1,143 @@
1
+ /**
2
+ * @typedef {{
3
+ * ordnanceSurveyApiKey: string
4
+ * }} PostcodeLookupConfiguration
5
+ */
6
+
7
+ /**
8
+ * @typedef {{
9
+ * name: string
10
+ * step?: string
11
+ * }} PostcodeLookupDispatchArgs
12
+ */
13
+
14
+ /**
15
+ * @typedef {{
16
+ * sourceUrl: string,
17
+ * formName: string
18
+ * componentName: string
19
+ * componentTitle: string,
20
+ * componentHint?: string
21
+ * step?: string
22
+ * }} PostcodeLookupDispatchData
23
+ */
24
+
25
+ /**
26
+ * @typedef {{
27
+ * initial: PostcodeLookupDispatchData
28
+ * details: PostcodeLookupDetailsData
29
+ * }} PostcodeLookupSessionData
30
+ */
31
+
32
+ //
33
+ // Model types
34
+ //
35
+
36
+ /**
37
+ * The postcode lookup details form view model data
38
+ * @typedef {object} PostcodeLookupDetailsData
39
+ * @property {string} postcodeQuery - postcode query
40
+ * @property {string} buildingNameQuery - Building name or number query
41
+ */
42
+
43
+ //
44
+ // Route types
45
+ //
46
+
47
+ /**
48
+ * Postcode lookup query params
49
+ * @typedef {object} PostcodeLookupQuery
50
+ * @property {string} [step] - step
51
+ */
52
+
53
+ /**
54
+ * @typedef {object} PostcodeLookupDetailsPayloadProperties
55
+ * @property {string} step - step
56
+ */
57
+
58
+ /**
59
+ * @typedef {PostcodeLookupDetailsData & PostcodeLookupDetailsPayloadProperties} PostcodeLookupDetailsPayload
60
+ */
61
+
62
+ /**
63
+ * @typedef {object} PostcodeLookupSelectPayload
64
+ * @property {string} step - step
65
+ * @property {string} uprn - postcode
66
+ */
67
+
68
+ /**
69
+ * Postcode lookup get request
70
+ * @typedef {object} PostcodeLookupGetRequestRefs
71
+ * @property {PostcodeLookupQuery} Query - Request query
72
+ */
73
+
74
+ /**
75
+ * Postcode lookup post request
76
+ * @typedef {object} PostcodeLookupPostRequestRefs
77
+ * @property {PostcodeLookupDetailsPayload | PostcodeLookupSelectPayload} Payload - Request payload
78
+ */
79
+
80
+ /**
81
+ * @typedef {PostcodeLookupGetRequestRefs | PostcodeLookupPostRequestRefs} PostcodeLookupRequestRefs
82
+ * @typedef {Request<PostcodeLookupGetRequestRefs>} PostcodeLookupGetRequest
83
+ * @typedef {Request<PostcodeLookupPostRequestRefs>} PostcodeLookupPostRequest
84
+ * @typedef {PostcodeLookupGetRequest | PostcodeLookupPostRequest} PostcodeLookupRequest
85
+ */
86
+
87
+ /**
88
+ * @typedef {object} PostcodeLookupManualPayload
89
+ * @property {string} addressLine1 - The address line 1
90
+ * @property {string} addressLine2 - The address line 2
91
+ * @property {string} town - The address town or city
92
+ * @property {string} county - The address county
93
+ * @property {string} postcode - The address postcode
94
+ */
95
+
96
+ //
97
+ // Service types
98
+ //
99
+
100
+ /**
101
+ * @typedef {object} Address
102
+ * @property {string} uprn - The unique property reference
103
+ * @property {string} address - The full address
104
+ * @property {string} addressLine1 - Address line 1
105
+ * @property {string} addressLine2 - Address line 2
106
+ * @property {string} town - Address town
107
+ * @property {string} county - Address county
108
+ * @property {string} postcode - Address postcode
109
+ * @property {string} formatted - The full formatted address
110
+ */
111
+
112
+ /**
113
+ * OS places address response
114
+ * @typedef {object} DeliveryPointAddress
115
+ * @property {string} UPRN - Unique property reference number
116
+ * @property {string} UDPRN - Unique delivery point Reference Number
117
+ * @property {string} ADDRESS - Address
118
+ * @property {string} ORGANISATION_NAME - Organisation name
119
+ * @property {string} SUB_BUILDING_NAME - Sub building name
120
+ * @property {string} BUILDING_NAME - Building name
121
+ * @property {string} BUILDING_NUMBER - Building number
122
+ * @property {string} THOROUGHFARE_NAME - Throughfare name
123
+ * @property {string} DEPENDENT_LOCALITY - Dependent locality
124
+ * @property {string} POST_TOWN - Post town
125
+ * @property {string} POSTCODE - Postcode
126
+ */
127
+
128
+ /**
129
+ * OS places DPA response
130
+ * @typedef {object} DeliveryPointAddressItem
131
+ * @property {DeliveryPointAddress} DPA - Delivery point address
132
+ */
133
+
134
+ /**
135
+ * OS places DPA response
136
+ * @typedef {object} DeliveryPointAddressResult
137
+ * @property {DeliveryPointAddressItem[]} [results] - Delivery point address results
138
+ */
139
+
140
+ /**
141
+ * @import { Request } from '@hapi/hapi'
142
+ * @import { FormPayload } from '~/src/server/plugins/engine/types.js'
143
+ */
@@ -0,0 +1,83 @@
1
+ {% extends baseLayoutPath %}
2
+
3
+ {% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
4
+ {% from "govuk/components/input/macro.njk" import govukInput %}
5
+ {% from "govuk/components/select/macro.njk" import govukSelect %}
6
+ {% from "govuk/components/button/macro.njk" import govukButton %}
7
+ {% from "govuk/components/inset-text/macro.njk" import govukInsetText %}
8
+ {% from "govuk/components/hint/macro.njk" import govukHint %}
9
+ {% from "govuk/components/fieldset/macro.njk" import govukFieldset %}
10
+
11
+ {% block content %}
12
+ <div class="govuk-grid-row">
13
+ <div class="govuk-grid-column-two-thirds">
14
+ {% if errors %}
15
+ {{ govukErrorSummary({
16
+ titleText: "There is a problem",
17
+ errorList: errors
18
+ }) }}
19
+ {% endif %}
20
+
21
+ {% include "partials/heading.html" %}
22
+
23
+ <form method="post">
24
+ <input type="hidden" name="crumb" value="{{ crumb }}">
25
+ <input type="hidden" name="step" value="{{ step }}">
26
+
27
+ {% switch step %}
28
+ {% case "details" %}
29
+ <!-- Postcode lookup details -->
30
+ {{ govukInput(fields.postcodeQuery) }}
31
+ {{ govukInput(fields.buildingNameQuery) }}
32
+ {% case "select" %}
33
+ <!-- Postcode lookup select -->
34
+ <!-- Postcode lookup details display -->
35
+ {%- set detailsHtml -%}
36
+ <strong>{{ details.postcodeQuery }}</strong>{% if details.buildingNameQuery %} and <strong>{{ details.buildingNameQuery }}</strong>{% endif %}
37
+ {%- endset -%}
38
+
39
+ {% if hasAddresses %}
40
+ <p class="govuk-body">
41
+ {{addressCount}} address{{ "es" if hasMultipleAddresses }} found for {{ detailsHtml | safe }}. <a href="{{ searchAgainLink.href }}" class="govuk-link govuk-link--no-visited-state">{{ searchAgainLink.text }}</a>
42
+ </p>
43
+ {% endif %}
44
+
45
+ {% if hasMultipleAddresses %}
46
+ <!-- Multiple address found - show drop down select -->
47
+ {{ govukSelect(fields.uprn) }}
48
+ {% elif singleAddress %}
49
+ <!-- Single address found - show single item -->
50
+ {{ govukInput(fields.uprn) }}
51
+ {{ govukInsetText({
52
+ text: singleAddress.formatted
53
+ }) }}
54
+ {% else %}
55
+ <!-- No addresses found - show try again -->
56
+ <p class="govuk-body">We could not find an address that matches {{ detailsHtml | safe }}.</p>
57
+ {% endif %}
58
+ {% case "manual" %}
59
+ <!-- Postcode lookup manual entry -->
60
+ {% if hint %}
61
+ {{ govukHint(hint) }}
62
+ {% endif %}
63
+
64
+ {{ govukInput(fields.addressLine1) }}
65
+ {{ govukInput(fields.addressLine2) }}
66
+ {{ govukInput(fields.town) }}
67
+ {{ govukInput(fields.county) }}
68
+ {{ govukInput(fields.postcode) }}
69
+ {% endswitch %}
70
+
71
+ <div class="govuk-button-group">
72
+ {{ govukButton(buttons.continueButton) }}
73
+
74
+ {% if buttons.manualLink %}
75
+ <p class="govuk-body">or <a class="govuk-link govuk-link--no-visited-state" href="{{ buttons.manualLink.href }}">{{buttons.manualLink.text}}</a></p>
76
+ {% elif buttons.detailsLink %}
77
+ <p class="govuk-body">or <a class="govuk-link govuk-link--no-visited-state" href="{{ buttons.detailsLink.href }}">{{buttons.detailsLink.text}}</a></p>
78
+ {% endif %}
79
+ </div>
80
+ </form>
81
+ </div>
82
+ </div>
83
+ {% endblock %}
@@ -0,0 +1,64 @@
1
+ import { type Server } from '@hapi/hapi'
2
+
3
+ import { createServer } from '~/src/server/index.js'
4
+ import { getFormMetadata } from '~/src/server/plugins/engine/services/formsService.js'
5
+ import * as defaultServices from '~/src/server/plugins/engine/services/index.js'
6
+ import * as fixtures from '~/test/fixtures/index.js'
7
+
8
+ jest.mock('~/src/server/plugins/engine/services/formsService.js')
9
+ jest.mock('~/src/server/plugins/engine/services/uploadService.js')
10
+
11
+ describe('Postcode lookup plugin', () => {
12
+ let server: Server
13
+
14
+ beforeEach(() => {
15
+ jest.mocked(getFormMetadata).mockResolvedValue(fixtures.form.metadata)
16
+ })
17
+
18
+ afterAll(async () => {
19
+ await server.stop()
20
+ })
21
+
22
+ describe('Plugin registration', () => {
23
+ test('Registers plugin with ordnance survey key', async () => {
24
+ server = await createServer({
25
+ services: defaultServices,
26
+ ordnanceSurveyApiKey: 'dummy'
27
+ })
28
+ await server.initialize()
29
+
30
+ expect(server.registrations).toHaveProperty(
31
+ '@defra/forms-engine-plugin/postcode-lookup',
32
+ {
33
+ name: '@defra/forms-engine-plugin/postcode-lookup',
34
+ options: { ordnanceSurveyApiKey: 'dummy' },
35
+ version: undefined
36
+ }
37
+ )
38
+
39
+ expect(
40
+ server.table().find((route) => route.path === '/postcode-lookup')
41
+ ).toBeDefined()
42
+ })
43
+
44
+ test('Does not register plugin when no ordnance survey key is provided', async () => {
45
+ server = await createServer({
46
+ services: defaultServices
47
+ })
48
+ await server.initialize()
49
+
50
+ expect(server.registrations).not.toHaveProperty(
51
+ '@defra/forms-engine-plugin/postcode-lookup',
52
+ {
53
+ name: '@defra/forms-engine-plugin/postcode-lookup',
54
+ options: { ordnanceSurveyApiKey: 'dummy' },
55
+ version: undefined
56
+ }
57
+ )
58
+
59
+ expect(
60
+ server.table().find((route) => route.path === '/postcode-lookup')
61
+ ).toBeUndefined()
62
+ })
63
+ })
64
+ })
@@ -48,10 +48,16 @@ export enum FormAction {
48
48
  Delete = 'delete',
49
49
  AddAnother = 'add-another',
50
50
  Send = 'send',
51
- SaveAndExit = 'save-and-exit'
51
+ SaveAndExit = 'save-and-exit',
52
+ External = 'external'
52
53
  }
53
54
 
54
55
  export enum FormStatus {
55
56
  Draft = 'draft',
56
57
  Live = 'live'
57
58
  }
59
+
60
+ export enum ExternalActions {
61
+ PostcodeLookup = 'postcode-lookup',
62
+ AnotherExternalAction = 'another-external-action'
63
+ }
@@ -8,13 +8,11 @@ export const stateSchema = Joi.string<FormStatus>()
8
8
  .required()
9
9
 
10
10
  export const actionSchema = Joi.string<FormAction>()
11
- .valid(
12
- FormAction.Continue,
13
- FormAction.Validate,
14
- FormAction.Delete,
15
- FormAction.AddAnother,
16
- FormAction.Send,
17
- FormAction.SaveAndExit
11
+ .pattern(new RegExp(`^${FormAction.External}-[a-zA-Z-:]*$`))
12
+ .allow(
13
+ ...Object.values(FormAction).filter(
14
+ (value) => value !== FormAction.External
15
+ )
18
16
  )
19
17
  .default(FormAction.Validate)
20
18
  .optional()
@@ -53,6 +53,7 @@ export interface RouteConfig {
53
53
  onRequest?: OnRequestCallback
54
54
  saveAndExit?: PluginOptions['saveAndExit']
55
55
  cacheServiceCreator?: (server: Server) => CacheService
56
+ ordnanceSurveyApiKey?: string
56
57
  }
57
58
 
58
59
  export interface OutputService {