@dwp/govuk-casa 7.0.8 → 8.0.0-beta2
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/README.md +22 -17
- package/dist/mjs/esm-wrapper.js +10 -0
- package/package.json +55 -80
- package/views/casa/components/checkboxes/template.njk +4 -1
- package/views/casa/components/date-input/template.njk +3 -3
- package/views/casa/components/journey-form/README.md +3 -1
- package/views/casa/components/journey-form/template.njk +1 -1
- package/views/casa/components/postal-address-object/template.njk +5 -5
- package/views/casa/components/radios/template.njk +1 -1
- package/views/casa/errors/static.njk +11 -0
- package/views/casa/layouts/journey.njk +26 -9
- package/views/casa/layouts/main.njk +7 -20
- package/views/casa/partials/scripts.njk +8 -3
- package/views/casa/partials/styles.njk +2 -2
- package/casa.js +0 -208
- package/definitions/review-page.js +0 -60
- package/dist/casa/css/casa-ie8.css +0 -1
- package/dist/casa/css/casa.css +0 -1
- package/dist/casa/js/casa.js +0 -1
- package/index.d.ts +0 -121
- package/lib/ConfigIngestor.js +0 -588
- package/lib/GatherModifier.js +0 -14
- package/lib/I18n.js +0 -160
- package/lib/JourneyContext.d.ts +0 -97
- package/lib/JourneyContext.js +0 -552
- package/lib/JourneyMap.js +0 -233
- package/lib/JourneyRoad.js +0 -330
- package/lib/Logger.js +0 -59
- package/lib/PageDictionary.d.ts +0 -11
- package/lib/PageDirectory.js +0 -77
- package/lib/Plan.js +0 -423
- package/lib/RoadConverter.js +0 -153
- package/lib/UserJourney.js +0 -8
- package/lib/Util.js +0 -227
- package/lib/Validation.js +0 -20
- package/lib/bootstrap/end-session.js +0 -44
- package/lib/bootstrap/load-definitions.js +0 -64
- package/lib/commonBodyParser.js +0 -15
- package/lib/enums.js +0 -6
- package/lib/gather-modifiers/index.js +0 -7
- package/lib/gather-modifiers/trimPostalAddressObject.js +0 -75
- package/lib/gather-modifiers/trimWhitespace.js +0 -16
- package/lib/utils/createGetRequest.d.ts +0 -5
- package/lib/utils/createGetRequest.js +0 -59
- package/lib/utils/index.js +0 -11
- package/lib/utils/parseRequest.d.ts +0 -5
- package/lib/utils/parseRequest.js +0 -72
- package/lib/utils/sanitise.js +0 -74
- package/lib/utils/validate.js +0 -32
- package/lib/validation/ArrayObjectField.js +0 -49
- package/lib/validation/ObjectField.js +0 -53
- package/lib/validation/SimpleField.d.ts +0 -12
- package/lib/validation/SimpleField.js +0 -46
- package/lib/validation/ValidationError.d.ts +0 -14
- package/lib/validation/ValidationError.js +0 -170
- package/lib/validation/ValidatorFactory.d.ts +0 -32
- package/lib/validation/ValidatorFactory.js +0 -91
- package/lib/validation/index.js +0 -22
- package/lib/validation/processor/flattenErrorArray.js +0 -24
- package/lib/validation/processor/queue.js +0 -214
- package/lib/validation/processor.js +0 -84
- package/lib/validation/rules/README.md +0 -3
- package/lib/validation/rules/ValidationRules.d.ts +0 -14
- package/lib/validation/rules/dateObject.js +0 -156
- package/lib/validation/rules/email.js +0 -44
- package/lib/validation/rules/inArray.js +0 -61
- package/lib/validation/rules/index.js +0 -23
- package/lib/validation/rules/nino.js +0 -48
- package/lib/validation/rules/optional.js +0 -14
- package/lib/validation/rules/postalAddressObject.js +0 -142
- package/lib/validation/rules/regex.js +0 -39
- package/lib/validation/rules/required.js +0 -57
- package/lib/validation/rules/strlen.js +0 -57
- package/lib/validation/rules/wordCount.js +0 -61
- package/lib/view-filters/formatDateObject.js +0 -35
- package/lib/view-filters/includes.js +0 -10
- package/lib/view-filters/index.js +0 -23
- package/lib/view-filters/mergeObjectsDeep.js +0 -21
- package/lib/view-filters/renderAsAttributes.js +0 -33
- package/middleware/errors/404.js +0 -12
- package/middleware/errors/catch-all.js +0 -27
- package/middleware/errors/index.js +0 -9
- package/middleware/headers/config-defaults.js +0 -57
- package/middleware/headers/headers.js +0 -40
- package/middleware/headers/index.js +0 -9
- package/middleware/i18n/i18n.js +0 -56
- package/middleware/i18n/index.js +0 -16
- package/middleware/index.js +0 -55
- package/middleware/mount/index.js +0 -9
- package/middleware/mount/mount.js +0 -10
- package/middleware/nunjucks/environment.js +0 -57
- package/middleware/nunjucks/index.js +0 -8
- package/middleware/page/csrf.js +0 -37
- package/middleware/page/edit-mode.js +0 -52
- package/middleware/page/gather.js +0 -75
- package/middleware/page/index.js +0 -103
- package/middleware/page/journey-continue.js +0 -157
- package/middleware/page/journey-rails.js +0 -102
- package/middleware/page/prepare-request.js +0 -77
- package/middleware/page/render.js +0 -75
- package/middleware/page/skip.js +0 -72
- package/middleware/page/utils.js +0 -206
- package/middleware/page/validate.js +0 -67
- package/middleware/session/expiry.js +0 -95
- package/middleware/session/genid.js +0 -18
- package/middleware/session/index.js +0 -18
- package/middleware/session/init.js +0 -25
- package/middleware/session/seed.js +0 -50
- package/middleware/session/timeout.js +0 -5
- package/middleware/static/asset-versions.js +0 -23
- package/middleware/static/index.js +0 -104
- package/middleware/static/prepare-assets.js +0 -51
- package/middleware/static/serve-assets.js +0 -58
- package/middleware/variables/index.js +0 -12
- package/middleware/variables/variables.js +0 -35
- package/src/browserconfig.xml +0 -5
- package/src/js/casa.js +0 -132
- package/src/scss/_casaElements.scss +0 -11
- package/src/scss/_casaGovukTemplateJinjaPolyfill.scss +0 -39
- package/src/scss/_casaMountUrl.scss +0 -8
- package/src/scss/casa-ie8.scss +0 -3
- package/src/scss/casa.scss +0 -14
- package/test/unit/templates/README.md +0 -5
- package/test/utils/BaseTestWaypoint.js +0 -106
- package/test/utils/concatWaypoints.js +0 -26
- package/test/utils/index.js +0 -6
- package/test/utils/testTraversal.js +0 -90
- package/views/casa/partials/cookie_message.njk +0 -3
- package/views/casa/partials/phase_banner_alpha.njk +0 -8
- package/views/casa/partials/phase_banner_beta.njk +0 -8
- package/views/casa/review/page-block.njk +0 -8
- package/views/casa/review/review.njk +0 -47
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
const { URL } = require('url');
|
|
2
|
-
|
|
3
|
-
class BaseTestWaypoint {
|
|
4
|
-
constructor({ mountUrl = '/', waypointId, dom }) {
|
|
5
|
-
this.mountUrl = mountUrl;
|
|
6
|
-
this.waypointId = waypointId; // must include origin, if applicable
|
|
7
|
-
this.dom = dom;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
findField(field) {
|
|
11
|
-
// Convert field to a canonical format - lowerCamelCase
|
|
12
|
-
const fieldKey = field
|
|
13
|
-
.replace(/ ([a-z])/ig, (_, m) => (m.toUpperCase()))
|
|
14
|
-
.replace(/^[A-Z]/, (m) => (m.toLowerCase()));
|
|
15
|
-
|
|
16
|
-
// Lookup field selector and use that to find the field in the DOM. Where
|
|
17
|
-
// there is no selector (null / undefined), we try to lookup the field by
|
|
18
|
-
// "name".
|
|
19
|
-
// Where the selector ends with `:eq()`, we can use that to pick 1 element
|
|
20
|
-
// from multiple matching elements
|
|
21
|
-
const fieldSelectors = this.constructor.fieldSelectors();
|
|
22
|
-
const fieldSelector = (fieldSelectors[fieldKey] || `[name="${fieldKey}"]`);
|
|
23
|
-
|
|
24
|
-
const eqRegex = /:eq\(([0-9]+)\)$/;
|
|
25
|
-
const eqMatch = fieldSelector.match(eqRegex);
|
|
26
|
-
const eqIndex = eqMatch ? eqMatch[1] : null;
|
|
27
|
-
|
|
28
|
-
let $field = this.dom(fieldSelector.replace(eqRegex, ''));
|
|
29
|
-
if (!$field.length) {
|
|
30
|
-
throw new ReferenceError(`Cannot find field with reference "${fieldKey}" on waypoint "${this.waypointId}". Do you need to define a custom class for this waypoint?`)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// For results that contain more than one element, check if there's a custom
|
|
34
|
-
// `:eq(...)` selector in place
|
|
35
|
-
if ($field.length > 1) {
|
|
36
|
-
if (eqIndex === null) {
|
|
37
|
-
throw new ReferenceError(`Found more than one element (${$field.length}) matching selector "${fieldSelectors[fieldKey]}". You could try using the custom :eq() selector to pinpoint a specific element.`);
|
|
38
|
-
}
|
|
39
|
-
$field = $field.eq(eqIndex);
|
|
40
|
-
} else {
|
|
41
|
-
$field = $field.eq(0);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return $field;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
static clickField($field) {
|
|
48
|
-
switch ($field.get(0).tagName) {
|
|
49
|
-
case 'input':
|
|
50
|
-
$field.attr('checked', !$field.attr('checked') === true);
|
|
51
|
-
break;
|
|
52
|
-
case 'a':
|
|
53
|
-
return $field.attr('href'); // TODO: need to make absolute somehow!
|
|
54
|
-
case 'option':
|
|
55
|
-
$field.attr('selected', !$field.attr('selected') === true);
|
|
56
|
-
break;
|
|
57
|
-
default:
|
|
58
|
-
}
|
|
59
|
-
return undefined;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/* ------------- the following should be implemented by the extending class */
|
|
63
|
-
|
|
64
|
-
static fieldSelectors() {
|
|
65
|
-
return Object.create(null);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// After interacting with a page, it _may_ result in the user being transferred
|
|
69
|
-
// away from the current page. In this case, the `nextUrl` result will contain
|
|
70
|
-
// that destination, otherwise it will remain undefined.
|
|
71
|
-
interact({ httpResponse, inputs = {} }) {
|
|
72
|
-
let nextUrl;
|
|
73
|
-
|
|
74
|
-
Object.keys(inputs || {}).forEach((field) => {
|
|
75
|
-
const value = inputs[field];
|
|
76
|
-
const $field = this.findField(field);
|
|
77
|
-
switch (value) {
|
|
78
|
-
case 'click()': nextUrl = this.constructor.clickField($field); break;
|
|
79
|
-
case 'select()': $field.attr('checked', true); break;
|
|
80
|
-
case 'deselect()': $field.attr('checked', false); break;
|
|
81
|
-
default:
|
|
82
|
-
$field.val(value);
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
// Convert URL to an absolute
|
|
87
|
-
if (nextUrl) {
|
|
88
|
-
const absUrl = new URL(nextUrl || '', httpResponse.request.url);
|
|
89
|
-
nextUrl = absUrl.href.replace(absUrl.origin, '');
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
nextUrl,
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/* eslint-disable-next-line no-unused-vars */
|
|
98
|
-
async progress({ httpResponse, httpAgent }) {
|
|
99
|
-
const formData = this.dom('.casa-journey-form').serialize();
|
|
100
|
-
return httpAgent.post(`${this.mountUrl}${this.waypointId}`).send(formData).then((response) => ({
|
|
101
|
-
nextUrl: (response.headers.location || `${this.mountUrl}${this.waypointId}`),
|
|
102
|
-
}));
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
module.exports = BaseTestWaypoint;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// Concatenate waypoint objects, making sure that duplicate keys are indexed
|
|
2
|
-
// with an incrementing integer
|
|
3
|
-
|
|
4
|
-
function getIndex(waypointId) {
|
|
5
|
-
const m = waypointId.match(/:([0-9]+)$/);
|
|
6
|
-
return m && m[1] ? parseInt(m[1]) : 0;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function bumpIndex(waypointId) {
|
|
10
|
-
const index = getIndex(waypointId);
|
|
11
|
-
return waypointId.replace(/:.*$/, '') + `:${index + 1}`;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
module.exports = function concactWaypoints(...sources) {
|
|
15
|
-
return sources.reduce((obj, source) => {
|
|
16
|
-
Object.keys(source).forEach((key) => {
|
|
17
|
-
const value = source[key];
|
|
18
|
-
while(obj.hasOwnProperty(key)) {
|
|
19
|
-
key = bumpIndex(key);
|
|
20
|
-
}
|
|
21
|
-
obj[key] = value;
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
return obj;
|
|
25
|
-
}, {});
|
|
26
|
-
};
|
package/test/utils/index.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
// IMPORTANT RATIONLE: we're using the DOM and full express application middleware
|
|
2
|
-
// because each project's app may be doing stuff with session data at any point,
|
|
3
|
-
// or using hooks, etc that manipulate data in very customised ways. So using
|
|
4
|
-
// the entire app stack gives us an accurate representation of how the app runs
|
|
5
|
-
// in the real world. We use to DOM as the primary interface to entering data,
|
|
6
|
-
// because this will again pick up any custom rendering logic that may mean we
|
|
7
|
-
// miss fields, or find fields where there shouldn't be any. It's a UI
|
|
8
|
-
// integration test suite that sits in the middle of the testing triangle/trophy.
|
|
9
|
-
|
|
10
|
-
const { strictEqual } = require('assert');
|
|
11
|
-
const { URL } = require('url');
|
|
12
|
-
const supertest = require('supertest');
|
|
13
|
-
const cheerio = require('cheerio');
|
|
14
|
-
const BaseTestWaypoint = require('./BaseTestWaypoint.js');
|
|
15
|
-
|
|
16
|
-
function defaultWaypointFactory(args) {
|
|
17
|
-
return new BaseTestWaypoint(args);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async function followUrlRedirects({ httpAgent, url }) {
|
|
21
|
-
const response = await httpAgent.get(url);
|
|
22
|
-
if (Object.prototype.hasOwnProperty.call(response.headers, 'location')) {
|
|
23
|
-
return followUrlRedirects({ httpAgent, url: response.headers.location });
|
|
24
|
-
}
|
|
25
|
-
return url;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function stripIndex(waypointId) {
|
|
29
|
-
return waypointId.replace(/:[0-9]+$/, '');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
module.exports = async function testTraversal({
|
|
33
|
-
app, mountUrl = '/', waypoints, waypointHandlerFactory = defaultWaypointFactory, agent = null, searchParams = ''
|
|
34
|
-
}) {
|
|
35
|
-
// Create an agent instance so we can share cookies across all requests
|
|
36
|
-
// TODO: See https://github.com/facebook/jest/issues/6907#issuecomment-416909039 for
|
|
37
|
-
// possible solution to clashing ephemeral ports.
|
|
38
|
-
const httpAgent = agent || supertest.agent(app);
|
|
39
|
-
|
|
40
|
-
// Get next waypoint in the expected sequence.
|
|
41
|
-
// Revisited waypoints include a `:<index>` suffix in the ID, which needs to
|
|
42
|
-
// be stripped.
|
|
43
|
-
const wpoints = Object.assign(Object.create(null), waypoints);
|
|
44
|
-
let waypointId = Object.keys(wpoints).shift();
|
|
45
|
-
const waypointData = wpoints[waypointId];
|
|
46
|
-
delete wpoints[waypointId];
|
|
47
|
-
waypointId = stripIndex(waypointId);
|
|
48
|
-
|
|
49
|
-
// Issue the initial GET request
|
|
50
|
-
const httpResponse = await httpAgent.get(`${mountUrl}${waypointId}`).query(searchParams.toString()).expect(200);
|
|
51
|
-
|
|
52
|
-
// Complete the form (if present) and progress to next waypoint.
|
|
53
|
-
// Each waypoint ID must have a corresponding "waypoint handler", provided by
|
|
54
|
-
// the `waypointHandlerFactory`. See `defaultWaypointFactory()` for an
|
|
55
|
-
// example of how this works.
|
|
56
|
-
// This handler's `progress()` method must return a result that includes the
|
|
57
|
-
// next URL to be navigated to (this must be an absolute URL)
|
|
58
|
-
const dom = cheerio.load(httpResponse.text);
|
|
59
|
-
const waypointHandler = waypointHandlerFactory({ mountUrl, waypointId, dom })
|
|
60
|
-
|| defaultWaypointFactory({ mountUrl, waypointId, dom });
|
|
61
|
-
let result;
|
|
62
|
-
result = waypointHandler.interact({ httpResponse, inputs: waypointData });
|
|
63
|
-
if (result.nextUrl === undefined) {
|
|
64
|
-
result = await waypointHandler.progress({ httpResponse, httpAgent });
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// GET next URL including all redirects, if applicable, and extract the
|
|
68
|
-
// actual waypoint from that response.
|
|
69
|
-
let nextWaypoint = (await followUrlRedirects({ httpAgent, url: result.nextUrl }));
|
|
70
|
-
const nextUrl = new URL(nextWaypoint, 'http://placeholder.test');
|
|
71
|
-
nextWaypoint = nextUrl.pathname.replace(mountUrl, '').replace(/^\/+/, '');
|
|
72
|
-
|
|
73
|
-
// Check we have reached the expected next waypoint in the sequence
|
|
74
|
-
strictEqual(nextWaypoint, stripIndex(Object.keys(wpoints)[0]));
|
|
75
|
-
|
|
76
|
-
// If there's more waypoints to traverse to, continue on our merry way,
|
|
77
|
-
// otherwise stop here.
|
|
78
|
-
if (Object.keys(wpoints).length < 2) {
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return testTraversal({
|
|
83
|
-
agent: httpAgent,
|
|
84
|
-
app,
|
|
85
|
-
mountUrl,
|
|
86
|
-
waypoints: wpoints,
|
|
87
|
-
waypointHandlerFactory,
|
|
88
|
-
searchParams: nextUrl.searchParams,
|
|
89
|
-
});
|
|
90
|
-
};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
{% from "govuk/components/phase-banner/macro.njk" import govukPhaseBanner %}
|
|
2
|
-
|
|
3
|
-
{{ govukPhaseBanner({
|
|
4
|
-
tag: {
|
|
5
|
-
text: "alpha"
|
|
6
|
-
},
|
|
7
|
-
html: 'This is a new service – your <a class="govuk-link" href="' + casa.mountUrl + 'feedback">feedback</a> will help us to improve it.'
|
|
8
|
-
}) }}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
{% from "govuk/components/phase-banner/macro.njk" import govukPhaseBanner %}
|
|
2
|
-
|
|
3
|
-
{{ govukPhaseBanner({
|
|
4
|
-
tag: {
|
|
5
|
-
text: "beta"
|
|
6
|
-
},
|
|
7
|
-
html: 'This is a new service – your <a class="govuk-link" href="' + casa.mountUrl + 'feedback">feedback</a> will help us to improve it.'
|
|
8
|
-
}) }}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
{% if reviewErrors[waypointId] %}
|
|
2
|
-
<span class="govuk-caption-m casa-review-page-error">{{ t('review:block.containsErrors') }}</span>
|
|
3
|
-
{% endif %}
|
|
4
|
-
<h2 class="govuk-heading-m">
|
|
5
|
-
{% block pageBlockTitle %}{% endblock %}
|
|
6
|
-
</h2>
|
|
7
|
-
|
|
8
|
-
{% block reviewBlock %}{% endblock %}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
{% extends "casa/layouts/main.njk" %}
|
|
2
|
-
|
|
3
|
-
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
4
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
5
|
-
{% from "casa/components/journey-form/macro.njk" import casaJourneyForm with context %}
|
|
6
|
-
|
|
7
|
-
{% block casaPageTitle %}
|
|
8
|
-
{{ t('review:pageTitle') }}
|
|
9
|
-
{% endblock %}
|
|
10
|
-
|
|
11
|
-
{% block content %}
|
|
12
|
-
<div class="govuk-grid-row">
|
|
13
|
-
<div class="govuk-grid-column-two-thirds-from-desktop">
|
|
14
|
-
{% if formErrorsGovukArray %}
|
|
15
|
-
{{ govukErrorSummary({
|
|
16
|
-
titleText: t("error:summary.h1"),
|
|
17
|
-
descriptionText: errorDescription or t('error:summary.defaultDescription'),
|
|
18
|
-
errorList: formErrorsGovukArray
|
|
19
|
-
}) }}
|
|
20
|
-
{% endif %}
|
|
21
|
-
|
|
22
|
-
{% call casaJourneyForm({
|
|
23
|
-
csrfToken: casa.csrfToken,
|
|
24
|
-
activeContextId: activeContextId,
|
|
25
|
-
buttonBarHidden: true
|
|
26
|
-
}) %}
|
|
27
|
-
<input type="hidden" name="reviewed" value="true" />
|
|
28
|
-
|
|
29
|
-
<h1 class="govuk-heading-xl">{{ t('review:h1') }}</h1>
|
|
30
|
-
|
|
31
|
-
<!-- Include blocks for all pages in the user's journey -->
|
|
32
|
-
{% for block in reviewBlocks %}
|
|
33
|
-
{% set waypointId = block.waypointId %}
|
|
34
|
-
{% set waypointEditUrl = block.waypointEditUrl %}
|
|
35
|
-
{% include block.reviewBlockView ignore missing %}
|
|
36
|
-
{% endfor %}
|
|
37
|
-
|
|
38
|
-
<p class="govuk-body">
|
|
39
|
-
{{ govukButton({
|
|
40
|
-
text: t('common:form.buttons.next.label'),
|
|
41
|
-
type: 'submit'
|
|
42
|
-
}) }}
|
|
43
|
-
</p>
|
|
44
|
-
{% endcall %}
|
|
45
|
-
</div>
|
|
46
|
-
</div>
|
|
47
|
-
{% endblock %}
|