@planning-inspectorate/dynamic-forms 1.14.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierignore +2 -1
- package/README.md +9 -1
- package/package.json +7 -2
- package/src/components/address/question.js +1 -1
- package/src/components/address/question.test.js +3 -3
- package/src/components/multi-field-input/index.njk +2 -2
- package/src/components/multi-field-input/question.js +5 -1
- package/src/components/radio/index.njk +2 -2
- package/src/components/select/index.njk +2 -2
- package/src/components/text-entry-redact/question.test.js +9 -9
- package/src/controller.test.js +2 -1
- package/src/index.js +8 -2
- package/src/lib/session-answer-store.test.js +1 -1
- package/src/questions/question-props.d.ts +5 -24
- package/src/questions/question.test.js +1 -1
- package/src/section.js +3 -0
- package/src/validator/validator.js +4 -1
- package/test/check-your-answers.test.js +69 -0
- package/test/journey.js +41 -0
- package/test/journey.test.js +21 -0
- package/test/questions.js +189 -0
- package/test/questions.test.js +246 -0
- package/test/snapshots/add-insurance.html +44 -0
- package/test/snapshots/check-your-answers-not-started.html +201 -0
- package/test/snapshots/check-your-answers-with-answers.html +201 -0
- package/test/snapshots/companions.html +51 -0
- package/test/snapshots/departure-date.html +57 -0
- package/test/snapshots/holiday-activities.html +49 -0
- package/test/snapshots/holiday-arrival.html +101 -0
- package/test/snapshots/holiday-description.html +33 -0
- package/test/snapshots/holiday-destination.html +56 -0
- package/test/snapshots/holiday-period.html +102 -0
- package/test/snapshots/holiday-snack.html +33 -0
- package/test/snapshots/hotel-address.html +65 -0
- package/test/snapshots/luggage-weight-units.html +75 -0
- package/test/snapshots/nights.html +28 -0
- package/test/snapshots/secret-wish.html +173 -0
- package/test/snapshots/travel-class.html +52 -0
- package/test/snapshots/travel-insurance-type.html +56 -0
- package/test/utils/app.js +41 -0
- package/test/utils/nunjucks.js +20 -0
- package/test/utils/test-server.js +167 -0
- package/test/utils/test-server.test.js +75 -0
- package/{src/lib/test-utils.js → test/utils/utils.js} +15 -16
- package/test/views/layout-check-your-answers.njk +1 -0
- /package/{src/lib/test-layout.njk → test/views/layout-question.njk} +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<div class="govuk-grid-row">
|
|
2
|
+
<div class="govuk-grid-column-two-thirds">
|
|
3
|
+
</div>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
<div class="govuk-grid-row">
|
|
8
|
+
<div class="govuk-grid-column-two-thirds">
|
|
9
|
+
<form action="" method="post" novalidate>
|
|
10
|
+
<input type="hidden" name="_csrf" value="">
|
|
11
|
+
<h1 class="govuk-heading-l">
|
|
12
|
+
What is your favourite snack to eat on holiday?
|
|
13
|
+
</h1>
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
<div class="govuk-form-group">
|
|
18
|
+
<label class="govuk-label govuk-label" for="holidaySnack">
|
|
19
|
+
Snack
|
|
20
|
+
</label>
|
|
21
|
+
<div id="holidaySnack-hint" class="govuk-hint">
|
|
22
|
+
|
|
23
|
+
</div>
|
|
24
|
+
<input class="govuk-input" id="holidaySnack" name="holidaySnack" type="text" value="" aria-describedby="holidaySnack-hint">
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
<button type="submit" class="govuk-button" data-module="govuk-button" data-cy="button-save-and-continue">
|
|
29
|
+
Continue
|
|
30
|
+
</button>
|
|
31
|
+
</form>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<div class="govuk-grid-row">
|
|
2
|
+
<div class="govuk-grid-column-two-thirds">
|
|
3
|
+
</div>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
<div class="govuk-grid-row">
|
|
8
|
+
<div class="govuk-grid-column-two-thirds">
|
|
9
|
+
<form action="" method="post" novalidate>
|
|
10
|
+
<input type="hidden" name="_csrf" value="">
|
|
11
|
+
<fieldset class="govuk-fieldset">
|
|
12
|
+
<legend class="govuk-fieldset__legend govuk-fieldset__legend--l">
|
|
13
|
+
<h1 class="govuk-fieldset__heading">
|
|
14
|
+
What is the address of your hotel?
|
|
15
|
+
</h1>
|
|
16
|
+
</legend>
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
<div class="govuk-form-group">
|
|
20
|
+
<label class="govuk-label" for="address-line-1">
|
|
21
|
+
Address line 1 (optional)
|
|
22
|
+
</label>
|
|
23
|
+
<input class="govuk-input" id="address-line-1" name="hotelAddress_addressLine1" type="text" value="" autocomplete="address-line1">
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
<div class="govuk-form-group">
|
|
28
|
+
<label class="govuk-label" for="address-line-2">
|
|
29
|
+
Address line 2 (optional)
|
|
30
|
+
</label>
|
|
31
|
+
<input class="govuk-input" id="address-line-2" name="hotelAddress_addressLine2" type="text" value="" autocomplete="address-line2">
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
<div class="govuk-form-group">
|
|
36
|
+
<label class="govuk-label" for="address-town">
|
|
37
|
+
Town or city (optional)
|
|
38
|
+
</label>
|
|
39
|
+
<input class="govuk-input govuk-!-width-two-thirds" id="address-town" name="hotelAddress_townCity" type="text" value="" autocomplete="address-level2">
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
<div class="govuk-form-group">
|
|
44
|
+
<label class="govuk-label" for="address-county">
|
|
45
|
+
County (optional)
|
|
46
|
+
</label>
|
|
47
|
+
<input class="govuk-input govuk-!-width-two-thirds" id="address-county" name="hotelAddress_county" type="text" value="" autocomplete="address-level1">
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
<div class="govuk-form-group">
|
|
52
|
+
<label class="govuk-label" for="address-postcode">
|
|
53
|
+
Postcode (optional)
|
|
54
|
+
</label>
|
|
55
|
+
<input class="govuk-input govuk-input--width-10" id="address-postcode" name="hotelAddress_postcode" type="text" value="" autocomplete="postal-code">
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<button type="submit" class="govuk-button" data-module="govuk-button" data-cy="button-save-and-continue">
|
|
59
|
+
Continue
|
|
60
|
+
</button>
|
|
61
|
+
|
|
62
|
+
</fieldset>
|
|
63
|
+
</form>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<div class="govuk-grid-row">
|
|
2
|
+
<div class="govuk-grid-column-two-thirds">
|
|
3
|
+
</div>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
<div class="govuk-grid-row">
|
|
8
|
+
<div class="govuk-grid-column-two-thirds">
|
|
9
|
+
<form action="" method="post" novalidate>
|
|
10
|
+
<input type="hidden" name="_csrf" value="">
|
|
11
|
+
|
|
12
|
+
<fieldset class="govuk-fieldset">
|
|
13
|
+
<legend class="govuk-fieldset__legend govuk-fieldset__legend--l">
|
|
14
|
+
<h1 class="govuk-fieldset__heading">
|
|
15
|
+
Select your luggage weight and unit.
|
|
16
|
+
</h1>
|
|
17
|
+
</legend>
|
|
18
|
+
|
|
19
|
+
<p class="govuk-body"></p>
|
|
20
|
+
|
|
21
|
+
<div class="govuk-form-group">
|
|
22
|
+
<div class="govuk-radios govuk-radios" data-module="govuk-radios">
|
|
23
|
+
<div class="govuk-radios__item">
|
|
24
|
+
<input class="govuk-radios__input" id="luggageWeightUnits" name="luggageWeightUnits" type="radio" value="kg" data-aria-controls="conditional-luggageWeightUnits" data-cy="answer-kg">
|
|
25
|
+
<label class="govuk-label govuk-radios__label" for="luggageWeightUnits">
|
|
26
|
+
Kilograms
|
|
27
|
+
</label>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="govuk-radios__conditional govuk-radios__conditional--hidden" id="conditional-luggageWeightUnits">
|
|
30
|
+
<div class="govuk-form-group">
|
|
31
|
+
<label class="govuk-label" for="luggageWeightValue_kg">
|
|
32
|
+
Weight in kilograms
|
|
33
|
+
</label>
|
|
34
|
+
<div id="luggageWeightValue_kg-hint" class="govuk-hint">
|
|
35
|
+
|
|
36
|
+
</div>
|
|
37
|
+
<div class="govuk-input__wrapper">
|
|
38
|
+
<input class="govuk-input govuk-input--width-5" id="luggageWeightValue_kg" name="luggageWeightValue_kg" type="text" spellcheck="false" value="" aria-describedby="luggageWeightValue_kg-hint" inputmode="numeric">
|
|
39
|
+
<div class="govuk-input__suffix" aria-hidden="true">kg</div>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="govuk-radios__item">
|
|
44
|
+
<input class="govuk-radios__input" id="luggageWeightUnits-2" name="luggageWeightUnits" type="radio" value="lbs" data-aria-controls="conditional-luggageWeightUnits-2" data-cy="answer-lbs">
|
|
45
|
+
<label class="govuk-label govuk-radios__label" for="luggageWeightUnits-2">
|
|
46
|
+
Pounds
|
|
47
|
+
</label>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="govuk-radios__conditional govuk-radios__conditional--hidden" id="conditional-luggageWeightUnits-2">
|
|
50
|
+
<div class="govuk-form-group">
|
|
51
|
+
<label class="govuk-label" for="luggageWeightValue_lbs">
|
|
52
|
+
Weight in pounds
|
|
53
|
+
</label>
|
|
54
|
+
<div id="luggageWeightValue_lbs-hint" class="govuk-hint">
|
|
55
|
+
|
|
56
|
+
</div>
|
|
57
|
+
<div class="govuk-input__wrapper">
|
|
58
|
+
<input class="govuk-input govuk-input--width-5" id="luggageWeightValue_lbs" name="luggageWeightValue_lbs" type="text" spellcheck="false" value="" aria-describedby="luggageWeightValue_lbs-hint" inputmode="numeric">
|
|
59
|
+
<div class="govuk-input__suffix" aria-hidden="true">lbs</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
</fieldset>
|
|
69
|
+
|
|
70
|
+
<button type="submit" class="govuk-button" data-module="govuk-button" data-cy="button-save-and-continue">
|
|
71
|
+
Continue
|
|
72
|
+
</button>
|
|
73
|
+
</form>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<div class="govuk-grid-row">
|
|
2
|
+
<div class="govuk-grid-column-two-thirds">
|
|
3
|
+
</div>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
<div class="govuk-grid-row">
|
|
8
|
+
<div class="govuk-grid-column-two-thirds">
|
|
9
|
+
<h1 class="govuk-heading-l">How many nights will you stay on holiday?</h1>
|
|
10
|
+
<p class="govuk-body"></p>
|
|
11
|
+
<form action="" method="post" novalidate>
|
|
12
|
+
<input type="hidden" name="_csrf" value="">
|
|
13
|
+
<div class="govuk-form-group">
|
|
14
|
+
<label class="govuk-label" for="nights">
|
|
15
|
+
Nights
|
|
16
|
+
</label>
|
|
17
|
+
<div id="nights-hint" class="govuk-hint">
|
|
18
|
+
|
|
19
|
+
</div>
|
|
20
|
+
<input class="govuk-input govuk-input--width-5" id="nights" name="nights" type="text" spellcheck="false" value="" aria-describedby="nights-hint" inputmode="numeric">
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<button type="submit" class="govuk-button" data-module="govuk-button" data-cy="button-save-and-continue">
|
|
24
|
+
Continue
|
|
25
|
+
</button>
|
|
26
|
+
</form>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
<div class="govuk-grid-row">
|
|
2
|
+
<div class="govuk-grid-column-two-thirds">
|
|
3
|
+
</div>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
<div class="govuk-grid-row">
|
|
8
|
+
<div class="govuk-grid-column-two-thirds">
|
|
9
|
+
<form action="" method="post" novalidate>
|
|
10
|
+
<input type="hidden" name="_csrf" value="">
|
|
11
|
+
|
|
12
|
+
<h1 class="govuk-label-wrapper">
|
|
13
|
+
<label class="govuk-label govuk-label--l" for="secretWish">
|
|
14
|
+
Share a secret wish for your holiday (will be redacted).
|
|
15
|
+
</label>
|
|
16
|
+
</h1>
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
<h2 class="govuk-heading-m">Redaction preview</h2>
|
|
22
|
+
|
|
23
|
+
<details id="secretWish-unredacted" class="govuk-details" data-original="">
|
|
24
|
+
<summary class="govuk-details__summary">
|
|
25
|
+
<span class="govuk-details__summary-text">
|
|
26
|
+
Original
|
|
27
|
+
</span>
|
|
28
|
+
</summary>
|
|
29
|
+
<div class="govuk-details__text">
|
|
30
|
+
|
|
31
|
+
</div>
|
|
32
|
+
</details>
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
<div class="govuk-form-group">
|
|
36
|
+
<label class="govuk-label" for="secretWish">
|
|
37
|
+
Secret wish
|
|
38
|
+
</label>
|
|
39
|
+
<textarea class="govuk-textarea" id="secretWish" name="secretWish" rows="8" readonly="true"></textarea>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
<div class="govuk-button-group">
|
|
44
|
+
<button type="button" class="govuk-button govuk-button--secondary" data-module="govuk-button" id="redact-selected-text">
|
|
45
|
+
Redact selected text
|
|
46
|
+
</button>
|
|
47
|
+
|
|
48
|
+
<button type="button" class="govuk-button govuk-button--secondary" data-module="govuk-button" id="redact-undo">
|
|
49
|
+
Undo
|
|
50
|
+
</button>
|
|
51
|
+
|
|
52
|
+
<button type="button" class="govuk-button govuk-button--secondary" data-module="govuk-button" id="redact-undo-all">
|
|
53
|
+
Undo all changes
|
|
54
|
+
</button>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<button type="submit" class="govuk-button" data-module="govuk-button" data-cy="button-save-and-continue">
|
|
58
|
+
Continue
|
|
59
|
+
</button>
|
|
60
|
+
</form>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<script >
|
|
64
|
+
/**
|
|
65
|
+
* @param {HTMLTextAreaElement} textArea
|
|
66
|
+
* @param {HTMLButtonElement} redactSelectedText
|
|
67
|
+
* @param {HTMLButtonElement} redactUndo
|
|
68
|
+
* @param {HTMLButtonElement} redactUndoAll
|
|
69
|
+
* @param {HTMLDetailsElement} unredactedText
|
|
70
|
+
* @param {HTMLAnchorElement[]} rejectLinks
|
|
71
|
+
* @param {import('@azure/ai-text-analytics').PiiEntity[]} suggestions
|
|
72
|
+
*/
|
|
73
|
+
function registerEventListeners({textArea, redactSelectedText, redactUndo, redactUndoAll, unredactedText, rejectLinks, suggestions}) {
|
|
74
|
+
const formGroup = textArea.parentElement;
|
|
75
|
+
const errorMessage = document.createElement('p');
|
|
76
|
+
errorMessage.id = 'secretWish-error';
|
|
77
|
+
errorMessage.classList.add('govuk-error-message');
|
|
78
|
+
|
|
79
|
+
const history = [];
|
|
80
|
+
function showError(message) {
|
|
81
|
+
formGroup.classList.add('govuk-form-group--error');
|
|
82
|
+
errorMessage.textContent = message;
|
|
83
|
+
formGroup.prepend(errorMessage);
|
|
84
|
+
}
|
|
85
|
+
function hideError() {
|
|
86
|
+
textArea.parentElement.classList.remove('govuk-form-group--error');
|
|
87
|
+
errorMessage.remove();
|
|
88
|
+
}
|
|
89
|
+
redactSelectedText.addEventListener('click', () => {
|
|
90
|
+
const { selectionStart, selectionEnd } = textArea;
|
|
91
|
+
if (selectionStart === selectionEnd) {
|
|
92
|
+
// no selected text
|
|
93
|
+
showError('Select text to redact');
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
hideError();
|
|
97
|
+
// replace the text with the 'full block' █ character
|
|
98
|
+
const selectedText = textArea.value.substring(selectionStart, selectionEnd);
|
|
99
|
+
const redactedText = '█'.repeat(selectionEnd - selectionStart);
|
|
100
|
+
textArea.value = textArea.value.substring(0, selectionStart) + redactedText + textArea.value.substring(selectionEnd);
|
|
101
|
+
// add to history for undo functionality
|
|
102
|
+
history.push({
|
|
103
|
+
selectionStart,
|
|
104
|
+
selectionEnd,
|
|
105
|
+
selectedText
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
redactUndo.addEventListener('click', () => {
|
|
109
|
+
const { selectionStart, selectionEnd, selectedText } = history.pop() || {};
|
|
110
|
+
if (selectionStart !== undefined && selectionEnd !== undefined && selectedText) {
|
|
111
|
+
hideError();
|
|
112
|
+
textArea.value = textArea.value.substring(0, selectionStart) + selectedText + textArea.value.substring(selectionEnd);
|
|
113
|
+
} else {
|
|
114
|
+
showError('No changes to undo');
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
redactUndoAll.addEventListener('click', () => {
|
|
118
|
+
const unredated = unredactedText.dataset.original;
|
|
119
|
+
if (history.length === 0 && textArea.value === unredated) {
|
|
120
|
+
showError('No changes to undo');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
hideError();
|
|
124
|
+
textArea.value = unredated || '';
|
|
125
|
+
history.length = 0;
|
|
126
|
+
});
|
|
127
|
+
for (const rejectLink of rejectLinks) {
|
|
128
|
+
rejectLink.addEventListener('click', () => {
|
|
129
|
+
const index = parseInt(rejectLink.getAttribute('data-redact').replace('suggestion-reject-', ''));
|
|
130
|
+
const suggestion = suggestions[index];
|
|
131
|
+
if (rejectLink.text === 'Reject') {
|
|
132
|
+
textArea.value = textArea.value.substring(0, suggestion.offset) + suggestion.text + textArea.value.substring(suggestion.offset + suggestion.length);
|
|
133
|
+
rejectLink.text = 'Accept';
|
|
134
|
+
} else {
|
|
135
|
+
const redactedText = '█'.repeat(suggestion.length);
|
|
136
|
+
textArea.value = textArea.value.substring(0, suggestion.offset) + redactedText+ textArea.value.substring(suggestion.offset + suggestion.length);
|
|
137
|
+
rejectLink.text = 'Reject';
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function initRedact() {
|
|
144
|
+
const textArea = document.querySelector('#secretWish');
|
|
145
|
+
const redactSelectedText = document.querySelector('#redact-selected-text');
|
|
146
|
+
const redactUndo = document.querySelector('#redact-undo');
|
|
147
|
+
const redactUndoAll = document.querySelector('#redact-undo-all');
|
|
148
|
+
const unredactedText = document.querySelector('#secretWish-unredacted');
|
|
149
|
+
const rejectLinks = document.querySelectorAll('[data-redact]');
|
|
150
|
+
const suggestions = []
|
|
151
|
+
|
|
152
|
+
if (!textArea || !(textArea instanceof HTMLTextAreaElement)) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (!redactSelectedText || !(redactSelectedText instanceof HTMLButtonElement)) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (!redactUndo || !(redactUndo instanceof HTMLButtonElement)) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (!redactUndoAll || !(redactUndoAll instanceof HTMLButtonElement)) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (!unredactedText || !(unredactedText instanceof HTMLDetailsElement)) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
registerEventListeners({textArea, redactSelectedText, redactUndo, redactUndoAll, unredactedText, rejectLinks, suggestions});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
initRedact();
|
|
172
|
+
</script>
|
|
173
|
+
</div>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<div class="govuk-grid-row">
|
|
2
|
+
<div class="govuk-grid-column-two-thirds">
|
|
3
|
+
</div>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
<div class="govuk-grid-row">
|
|
8
|
+
<div class="govuk-grid-column-two-thirds">
|
|
9
|
+
<form action="" method="POST" novalidate>
|
|
10
|
+
<input type="hidden" name="_csrf" value="">
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
<div class="govuk-form-group">
|
|
14
|
+
<h1 class="govuk-label-wrapper">
|
|
15
|
+
<label class="govuk-label govuk-label--l" for="travelClass">
|
|
16
|
+
Which class do you want to travel in?
|
|
17
|
+
</label>
|
|
18
|
+
</h1>
|
|
19
|
+
<select class="govuk-select" id="travelClass" name="travelClass">
|
|
20
|
+
<option value="economy" data-cy="answer-economy">Economy</option>
|
|
21
|
+
<option value="business" data-cy="answer-business">Business</option>
|
|
22
|
+
<option value="first" data-cy="answer-first">First Class</option>
|
|
23
|
+
</select>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
<button type="submit" class="govuk-button" data-module="govuk-button" data-cy="button-save-and-continue">
|
|
28
|
+
Continue
|
|
29
|
+
</button>
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
</form>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
<script src="/assets/js/accessible-autocomplete.min.js"></script>
|
|
36
|
+
<script >
|
|
37
|
+
if (window.accessibleAutocomplete) {
|
|
38
|
+
accessibleAutocomplete.enhanceSelectElement({
|
|
39
|
+
selectElement: document.querySelector('#travelClass'),
|
|
40
|
+
onConfirm: () => {
|
|
41
|
+
let input = document.querySelector('#travelClass');
|
|
42
|
+
let select = document.querySelector('#travelClass-select');
|
|
43
|
+
let options = Array.from(select.options);
|
|
44
|
+
if (!input.value || !options.some(option => option.innerText === input.value)) {
|
|
45
|
+
select.options.selectedIndex = -1;
|
|
46
|
+
} else {
|
|
47
|
+
select.options.selectedIndex = options.findIndex(option => option.innerText === input.value);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
</script>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<div class="govuk-grid-row">
|
|
2
|
+
<div class="govuk-grid-column-two-thirds">
|
|
3
|
+
</div>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
<div class="govuk-grid-row">
|
|
8
|
+
<div class="govuk-grid-column-two-thirds">
|
|
9
|
+
<form action="" method="post" novalidate>
|
|
10
|
+
<input type="hidden" name="_csrf" value="">
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
<fieldset class="govuk-fieldset">
|
|
14
|
+
<legend class="govuk-fieldset__legend govuk-fieldset__legend--l">
|
|
15
|
+
<h1 class="govuk-fieldset__heading">
|
|
16
|
+
Which type of travel insurance would you like?
|
|
17
|
+
</h1>
|
|
18
|
+
</legend>
|
|
19
|
+
|
|
20
|
+
<p class="govuk-body"></p>
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
<div class="govuk-form-group">
|
|
24
|
+
<div class="govuk-radios govuk-radios" data-module="govuk-radios">
|
|
25
|
+
<div class="govuk-radios__item">
|
|
26
|
+
<input class="govuk-radios__input" id="travelInsuranceType" name="travelInsuranceType" type="radio" value="basic" data-cy="answer-basic">
|
|
27
|
+
<label class="govuk-label govuk-radios__label" for="travelInsuranceType">
|
|
28
|
+
Basic
|
|
29
|
+
</label>
|
|
30
|
+
</div>
|
|
31
|
+
<div class="govuk-radios__item">
|
|
32
|
+
<input class="govuk-radios__input" id="travelInsuranceType-2" name="travelInsuranceType" type="radio" value="comprehensive" data-cy="answer-comprehensive">
|
|
33
|
+
<label class="govuk-label govuk-radios__label" for="travelInsuranceType-2">
|
|
34
|
+
Comprehensive
|
|
35
|
+
</label>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="govuk-radios__item">
|
|
38
|
+
<input class="govuk-radios__input" id="travelInsuranceType-3" name="travelInsuranceType" type="radio" value="premium" data-cy="answer-premium">
|
|
39
|
+
<label class="govuk-label govuk-radios__label" for="travelInsuranceType-3">
|
|
40
|
+
Premium
|
|
41
|
+
</label>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
</fieldset>
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
<button type="submit" class="govuk-button" data-module="govuk-button" data-cy="button-save-and-continue">
|
|
52
|
+
Continue
|
|
53
|
+
</button>
|
|
54
|
+
</form>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import bodyParser from 'body-parser';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import session from 'express-session';
|
|
4
|
+
import crypto from 'node:crypto';
|
|
5
|
+
import { configureNunjucksTestEnv } from './nunjucks.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Create an Express app configured for testing with Nunjucks and session support.
|
|
9
|
+
* @returns {import('express').Express}
|
|
10
|
+
*/
|
|
11
|
+
export function createApp() {
|
|
12
|
+
const app = express();
|
|
13
|
+
|
|
14
|
+
// configure body-parser, to populate req.body
|
|
15
|
+
// see https://expressjs.com/en/resources/middleware/body-parser.html
|
|
16
|
+
app.use(bodyParser.urlencoded({ extended: true }));
|
|
17
|
+
app.use(bodyParser.json());
|
|
18
|
+
|
|
19
|
+
app.use(
|
|
20
|
+
session({
|
|
21
|
+
secret: crypto.randomUUID(),
|
|
22
|
+
resave: false,
|
|
23
|
+
saveUninitialized: false,
|
|
24
|
+
store: new session.MemoryStore(),
|
|
25
|
+
unset: 'destroy',
|
|
26
|
+
cookie: {
|
|
27
|
+
secure: false,
|
|
28
|
+
maxAge: 86_400_000 // 1 day in milliseconds
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const nunjucksEnvironment = configureNunjucksTestEnv();
|
|
34
|
+
// Set the express view engine to nunjucks
|
|
35
|
+
// calls to res.render will use nunjucks
|
|
36
|
+
nunjucksEnvironment.addGlobal('govukRebrand', true);
|
|
37
|
+
nunjucksEnvironment.express(app);
|
|
38
|
+
app.set('view engine', 'njk');
|
|
39
|
+
|
|
40
|
+
return app;
|
|
41
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import nunjucks from 'nunjucks';
|
|
2
|
+
import { createRequire } from 'module';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { testDir as getTestDir } from './utils.js';
|
|
5
|
+
|
|
6
|
+
export function configureNunjucksTestEnv() {
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const testDir = getTestDir();
|
|
9
|
+
const srcDir = path.resolve(testDir, '..', 'src');
|
|
10
|
+
const govukFrontendRoot = path.resolve(require.resolve('govuk-frontend'), '../..');
|
|
11
|
+
|
|
12
|
+
return nunjucks.configure([testDir, srcDir, govukFrontendRoot], {
|
|
13
|
+
// output with dangerous characters are escaped automatically
|
|
14
|
+
autoescape: true,
|
|
15
|
+
// automatically remove trailing newlines from a block/tag
|
|
16
|
+
trimBlocks: true,
|
|
17
|
+
// automatically remove leading whitespace from a block/tag
|
|
18
|
+
lstripBlocks: true
|
|
19
|
+
});
|
|
20
|
+
}
|