@planning-inspectorate/dynamic-forms 3.3.3 → 3.4.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/.azure/pipelines/azure-pipelines-pr.yml +4 -0
- package/.azure/pipelines/release.yml +4 -0
- package/.gitattributes +2 -0
- package/README.md +20 -9
- package/package.json +13 -5
- package/src/components/address/question.js +1 -10
- package/src/components/boolean/question.js +1 -1
- package/src/components/checkbox/question.js +2 -6
- package/src/components/date/question.js +1 -8
- package/src/components/date-period/question.js +1 -8
- package/src/components/email/question.js +4 -4
- package/src/components/manage-list/question.test.js +4 -19
- package/src/components/multi-field-input/question.js +3 -3
- package/src/components/multi-field-input/question.test.js +1 -1
- package/src/components/number-entry/question.js +1 -5
- package/src/components/radio/question.js +1 -1
- package/src/components/select/question.js +1 -1
- package/src/components/single-line-input/question.js +0 -8
- package/src/components/text-entry/question.js +4 -4
- package/src/components/text-entry-redact/index.njk +15 -11
- package/src/components/text-entry-redact/question.js +6 -16
- package/src/components/unit-option-entry/question.js +4 -11
- package/src/components/utils/component-types.js +18 -0
- package/src/index.js +72 -25
- package/src/middleware/redirect-to-unanswered-question.test.js +1 -1
- package/src/questions/options-question.js +5 -12
- package/src/questions/question-types.d.ts +3 -3
- package/src/questions/question.js +6 -6
- package/src/questions/questions.js +1 -1
- package/test/check-your-answers.test.js +3 -8
- package/test/conditional-journey.test.js +431 -0
- package/test/questions.test.js +15 -28
- package/test/snapshots/secret-wish.html +15 -11
- package/test/utils/question-test-utils.js +52 -4
- package/test/utils/test-server.js +1 -0
- package/test/utils/utils.js +16 -1
- package/tsconfig.json +9 -1
- package/types/commitlint.config.d.ts +7 -0
- package/types/commitlint.config.d.ts.map +1 -0
- package/types/eslint.config.d.ts +95 -0
- package/types/eslint.config.d.ts.map +1 -0
- package/types/src/components/address/question.d.ts +31 -0
- package/types/src/components/address/question.d.ts.map +1 -0
- package/types/src/components/address/question.test.d.ts +2 -0
- package/types/src/components/address/question.test.d.ts.map +1 -0
- package/types/src/components/boolean/question.d.ts +47 -0
- package/types/src/components/boolean/question.d.ts.map +1 -0
- package/types/src/components/boolean/question.test.d.ts +2 -0
- package/types/src/components/boolean/question.test.d.ts.map +1 -0
- package/types/src/components/checkbox/question.d.ts +49 -0
- package/types/src/components/checkbox/question.d.ts.map +1 -0
- package/types/src/components/checkbox/question.test.d.ts +2 -0
- package/types/src/components/checkbox/question.test.d.ts.map +1 -0
- package/types/src/components/date/question.d.ts +22 -0
- package/types/src/components/date/question.d.ts.map +1 -0
- package/types/src/components/date/question.test.d.ts +2 -0
- package/types/src/components/date/question.test.d.ts.map +1 -0
- package/types/src/components/date-period/question.d.ts +29 -0
- package/types/src/components/date-period/question.d.ts.map +1 -0
- package/types/src/components/date-period/question.test.d.ts +2 -0
- package/types/src/components/date-period/question.test.d.ts.map +1 -0
- package/types/src/components/date-time/question.d.ts +24 -0
- package/types/src/components/date-time/question.d.ts.map +1 -0
- package/types/src/components/date-time/question.test.d.ts +2 -0
- package/types/src/components/date-time/question.test.d.ts.map +1 -0
- package/types/src/components/email/question.d.ts +30 -0
- package/types/src/components/email/question.d.ts.map +1 -0
- package/types/src/components/email/question.test.d.ts +2 -0
- package/types/src/components/email/question.test.d.ts.map +1 -0
- package/types/src/components/identifier/question.d.ts +15 -0
- package/types/src/components/identifier/question.d.ts.map +1 -0
- package/types/src/components/identifier/question.test.d.ts +2 -0
- package/types/src/components/identifier/question.test.d.ts.map +1 -0
- package/types/src/components/manage-list/manage-list-section.d.ts +16 -0
- package/types/src/components/manage-list/manage-list-section.d.ts.map +1 -0
- package/types/src/components/manage-list/manage-list-section.test.d.ts +2 -0
- package/types/src/components/manage-list/manage-list-section.test.d.ts.map +1 -0
- package/types/src/components/manage-list/question.d.ts +41 -0
- package/types/src/components/manage-list/question.d.ts.map +1 -0
- package/types/src/components/manage-list/question.test.d.ts +2 -0
- package/types/src/components/manage-list/question.test.d.ts.map +1 -0
- package/types/src/components/manage-list/utils.d.ts +18 -0
- package/types/src/components/manage-list/utils.d.ts.map +1 -0
- package/types/src/components/manage-list/utils.test.d.ts +2 -0
- package/types/src/components/manage-list/utils.test.d.ts.map +1 -0
- package/types/src/components/multi-field-input/question.d.ts +106 -0
- package/types/src/components/multi-field-input/question.d.ts.map +1 -0
- package/types/src/components/multi-field-input/question.test.d.ts +2 -0
- package/types/src/components/multi-field-input/question.test.d.ts.map +1 -0
- package/types/src/components/number-entry/question.d.ts +37 -0
- package/types/src/components/number-entry/question.d.ts.map +1 -0
- package/types/src/components/radio/question.d.ts +53 -0
- package/types/src/components/radio/question.d.ts.map +1 -0
- package/types/src/components/radio/question.test.d.ts +2 -0
- package/types/src/components/radio/question.test.d.ts.map +1 -0
- package/types/src/components/select/question.d.ts +51 -0
- package/types/src/components/select/question.d.ts.map +1 -0
- package/types/src/components/select/question.test.d.ts +2 -0
- package/types/src/components/select/question.test.d.ts.map +1 -0
- package/types/src/components/single-line-input/question.d.ts +18 -0
- package/types/src/components/single-line-input/question.d.ts.map +1 -0
- package/types/src/components/single-line-input/question.test.d.ts +2 -0
- package/types/src/components/single-line-input/question.test.d.ts.map +1 -0
- package/types/src/components/text-entry/question.d.ts +34 -0
- package/types/src/components/text-entry/question.d.ts.map +1 -0
- package/types/src/components/text-entry/question.test.d.ts +2 -0
- package/types/src/components/text-entry/question.test.d.ts.map +1 -0
- package/types/src/components/text-entry-redact/question.d.ts +42 -0
- package/types/src/components/text-entry-redact/question.d.ts.map +1 -0
- package/types/src/components/text-entry-redact/question.test.d.ts +2 -0
- package/types/src/components/text-entry-redact/question.test.d.ts.map +1 -0
- package/types/src/components/unit-option-entry/question.d.ts +83 -0
- package/types/src/components/unit-option-entry/question.d.ts.map +1 -0
- package/types/src/components/unit-option-entry/question.test.d.ts +2 -0
- package/types/src/components/unit-option-entry/question.test.d.ts.map +1 -0
- package/types/src/components/utils/component-types.d.ts +19 -0
- package/types/src/components/utils/component-types.d.ts.map +1 -0
- package/types/src/components/utils/persisted-number-answer.d.ts +2 -0
- package/types/src/components/utils/persisted-number-answer.d.ts.map +1 -0
- package/types/src/components/utils/question-has-answer.d.ts +17 -0
- package/types/src/components/utils/question-has-answer.d.ts.map +1 -0
- package/types/src/components/utils/question-has-answer.test.d.ts +2 -0
- package/types/src/components/utils/question-has-answer.test.d.ts.map +1 -0
- package/types/src/components/utils/question-utils.d.ts +15 -0
- package/types/src/components/utils/question-utils.d.ts.map +1 -0
- package/types/src/components/utils/question-utils.test.d.ts +2 -0
- package/types/src/components/utils/question-utils.test.d.ts.map +1 -0
- package/types/src/controller.d.ts +78 -0
- package/types/src/controller.d.ts.map +1 -0
- package/types/src/controller.test.d.ts +2 -0
- package/types/src/controller.test.d.ts.map +1 -0
- package/types/src/index.d.ts +54 -0
- package/types/src/index.d.ts.map +1 -0
- package/types/src/journey/journey-response.d.ts +32 -0
- package/types/src/journey/journey-response.d.ts.map +1 -0
- package/types/src/journey/journey-response.test.d.ts +2 -0
- package/types/src/journey/journey-response.test.d.ts.map +1 -0
- package/types/src/journey/journey.d.ts +144 -0
- package/types/src/journey/journey.d.ts.map +1 -0
- package/types/src/journey/journey.test.d.ts +2 -0
- package/types/src/journey/journey.test.d.ts.map +1 -0
- package/types/src/lib/address-utils.d.ts +6 -0
- package/types/src/lib/address-utils.d.ts.map +1 -0
- package/types/src/lib/address-utils.test.d.ts +2 -0
- package/types/src/lib/address-utils.test.d.ts.map +1 -0
- package/types/src/lib/address.d.ts +43 -0
- package/types/src/lib/address.d.ts.map +1 -0
- package/types/src/lib/address.test.d.ts +2 -0
- package/types/src/lib/address.test.d.ts.map +1 -0
- package/types/src/lib/date-utils.d.ts +60 -0
- package/types/src/lib/date-utils.d.ts.map +1 -0
- package/types/src/lib/date-utils.test.d.ts +2 -0
- package/types/src/lib/date-utils.test.d.ts.map +1 -0
- package/types/src/lib/session-answer-store.d.ts +84 -0
- package/types/src/lib/session-answer-store.d.ts.map +1 -0
- package/types/src/lib/session-answer-store.test.d.ts +2 -0
- package/types/src/lib/session-answer-store.test.d.ts.map +1 -0
- package/types/src/lib/utils.d.ts +19 -0
- package/types/src/lib/utils.d.ts.map +1 -0
- package/types/src/lib/utils.test.d.ts +2 -0
- package/types/src/lib/utils.test.d.ts.map +1 -0
- package/types/src/lib/uuid.d.ts +7 -0
- package/types/src/lib/uuid.d.ts.map +1 -0
- package/types/src/lib/uuid.test.d.ts +2 -0
- package/types/src/lib/uuid.test.d.ts.map +1 -0
- package/types/src/middleware/build-get-journey.d.ts +6 -0
- package/types/src/middleware/build-get-journey.d.ts.map +1 -0
- package/types/src/middleware/redirect-to-unanswered-question.d.ts +12 -0
- package/types/src/middleware/redirect-to-unanswered-question.d.ts.map +1 -0
- package/types/src/middleware/redirect-to-unanswered-question.test.d.ts +2 -0
- package/types/src/middleware/redirect-to-unanswered-question.test.d.ts.map +1 -0
- package/types/src/questions/create-questions.d.ts +21 -0
- package/types/src/questions/create-questions.d.ts.map +1 -0
- package/types/src/questions/options-question.d.ts +74 -0
- package/types/src/questions/options-question.d.ts.map +1 -0
- package/types/src/questions/options-question.test.d.ts +2 -0
- package/types/src/questions/options-question.test.d.ts.map +1 -0
- package/types/src/questions/question.d.ts +274 -0
- package/types/src/questions/question.d.ts.map +1 -0
- package/types/src/questions/question.test.d.ts +2 -0
- package/types/src/questions/question.test.d.ts.map +1 -0
- package/types/src/questions/questions.d.ts +3 -0
- package/types/src/questions/questions.d.ts.map +1 -0
- package/types/src/section.d.ts +107 -0
- package/types/src/section.d.ts.map +1 -0
- package/types/src/section.test.d.ts +2 -0
- package/types/src/section.test.d.ts.map +1 -0
- package/types/src/validator/address-validator.d.ts +41 -0
- package/types/src/validator/address-validator.d.ts.map +1 -0
- package/types/src/validator/address-validator.test.d.ts +2 -0
- package/types/src/validator/address-validator.test.d.ts.map +1 -0
- package/types/src/validator/base-validator.d.ts +11 -0
- package/types/src/validator/base-validator.d.ts.map +1 -0
- package/types/src/validator/base-validator.test.d.ts +2 -0
- package/types/src/validator/base-validator.test.d.ts.map +1 -0
- package/types/src/validator/conditional-required-validator.d.ts +24 -0
- package/types/src/validator/conditional-required-validator.d.ts.map +1 -0
- package/types/src/validator/conditional-required-validator.test.d.ts +2 -0
- package/types/src/validator/conditional-required-validator.test.d.ts.map +1 -0
- package/types/src/validator/confirmation-checkbox-validator.d.ts +27 -0
- package/types/src/validator/confirmation-checkbox-validator.d.ts.map +1 -0
- package/types/src/validator/confirmation-checkbox-validator.test.d.ts +2 -0
- package/types/src/validator/confirmation-checkbox-validator.test.d.ts.map +1 -0
- package/types/src/validator/coordinates-validator.d.ts +22 -0
- package/types/src/validator/coordinates-validator.d.ts.map +1 -0
- package/types/src/validator/coordinates-validator.test.d.ts +2 -0
- package/types/src/validator/coordinates-validator.test.d.ts.map +1 -0
- package/types/src/validator/date-period-validator.d.ts +63 -0
- package/types/src/validator/date-period-validator.d.ts.map +1 -0
- package/types/src/validator/date-period-validator.test.d.ts +2 -0
- package/types/src/validator/date-period-validator.test.d.ts.map +1 -0
- package/types/src/validator/date-time-validator.d.ts +26 -0
- package/types/src/validator/date-time-validator.d.ts.map +1 -0
- package/types/src/validator/date-time-validator.test.d.ts +2 -0
- package/types/src/validator/date-time-validator.test.d.ts.map +1 -0
- package/types/src/validator/date-validator.d.ts +48 -0
- package/types/src/validator/date-validator.d.ts.map +1 -0
- package/types/src/validator/date-validator.test.d.ts +2 -0
- package/types/src/validator/date-validator.test.d.ts.map +1 -0
- package/types/src/validator/document-upload-validator.d.ts +10 -0
- package/types/src/validator/document-upload-validator.d.ts.map +1 -0
- package/types/src/validator/document-upload-validator.test.d.ts +2 -0
- package/types/src/validator/document-upload-validator.test.d.ts.map +1 -0
- package/types/src/validator/email-validator.d.ts +73 -0
- package/types/src/validator/email-validator.d.ts.map +1 -0
- package/types/src/validator/email-validator.test.d.ts +2 -0
- package/types/src/validator/email-validator.test.d.ts.map +1 -0
- package/types/src/validator/multi-field-input-validator.d.ts +70 -0
- package/types/src/validator/multi-field-input-validator.d.ts.map +1 -0
- package/types/src/validator/multi-field-input-validator.test.d.ts +2 -0
- package/types/src/validator/multi-field-input-validator.test.d.ts.map +1 -0
- package/types/src/validator/numeric-validator.d.ts +49 -0
- package/types/src/validator/numeric-validator.d.ts.map +1 -0
- package/types/src/validator/numeric-validator.test.d.ts +2 -0
- package/types/src/validator/numeric-validator.test.d.ts.map +1 -0
- package/types/src/validator/required-validator.d.ts +22 -0
- package/types/src/validator/required-validator.d.ts.map +1 -0
- package/types/src/validator/required-validator.test.d.ts +2 -0
- package/types/src/validator/required-validator.test.d.ts.map +1 -0
- package/types/src/validator/same-answer-validator.d.ts +18 -0
- package/types/src/validator/same-answer-validator.d.ts.map +1 -0
- package/types/src/validator/same-answer-validator.test.d.ts +2 -0
- package/types/src/validator/same-answer-validator.test.d.ts.map +1 -0
- package/types/src/validator/string-validator.d.ts +58 -0
- package/types/src/validator/string-validator.d.ts.map +1 -0
- package/types/src/validator/string-validator.test.d.ts +2 -0
- package/types/src/validator/string-validator.test.d.ts.map +1 -0
- package/types/src/validator/unit-option-entry-validator.d.ts +40 -0
- package/types/src/validator/unit-option-entry-validator.d.ts.map +1 -0
- package/types/src/validator/unit-option-entry-validator.test.d.ts +2 -0
- package/types/src/validator/unit-option-entry-validator.test.d.ts.map +1 -0
- package/types/src/validator/valid-option-validator.d.ts +22 -0
- package/types/src/validator/valid-option-validator.d.ts.map +1 -0
- package/types/src/validator/valid-option-validator.test.d.ts +2 -0
- package/types/src/validator/valid-option-validator.test.d.ts.map +1 -0
- package/types/src/validator/validation-error-handler.d.ts +20 -0
- package/types/src/validator/validation-error-handler.d.ts.map +1 -0
- package/types/src/validator/validation-error-handler.test.d.ts +2 -0
- package/types/src/validator/validation-error-handler.test.d.ts.map +1 -0
- package/types/src/validator/validator.d.ts +5 -0
- package/types/src/validator/validator.d.ts.map +1 -0
- package/types/src/validator/validator.test.d.ts +2 -0
- package/types/src/validator/validator.test.d.ts.map +1 -0
- package/types/test/mock/journey.d.ts +3 -0
- package/types/test/mock/journey.d.ts.map +1 -0
- package/types/test/mock/uuid.d.ts +7 -0
- package/types/test/mock/uuid.d.ts.map +1 -0
- package/types/test/utils/nunjucks.d.ts +2 -0
- package/types/test/utils/nunjucks.d.ts.map +1 -0
- package/types/test/utils/utils.d.ts +32 -0
- package/types/test/utils/utils.d.ts.map +1 -0
- package/src/lib/address.d.ts +0 -7
package/src/index.js
CHANGED
|
@@ -1,25 +1,72 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
1
|
+
// Components
|
|
2
|
+
import AddressQuestion from './components/address/question.js';
|
|
3
|
+
import DateValidator from './validator/date-validator.js';
|
|
4
|
+
import EmailValidator from './validator/email-validator.js';
|
|
5
|
+
import StringValidator from './validator/string-validator.js';
|
|
6
|
+
|
|
7
|
+
export { AddressQuestion };
|
|
8
|
+
export * from './components/boolean/question.js';
|
|
9
|
+
export * from './components/checkbox/question.js';
|
|
10
|
+
export * from './components/date/question.js';
|
|
11
|
+
export * from './components/date-period/question.js';
|
|
12
|
+
export * from './components/multi-field-input/question.js';
|
|
13
|
+
export * from './components/number-entry/question.js';
|
|
14
|
+
export * from './components/radio/question.js';
|
|
15
|
+
export * from './components/select/question.js';
|
|
16
|
+
export * from './components/single-line-input/question.js';
|
|
17
|
+
export * from './components/text-entry/question.js';
|
|
18
|
+
export * from './components/text-entry-redact/question.js';
|
|
19
|
+
export * from './components/unit-option-entry/question.js';
|
|
20
|
+
export * from './components/utils/persisted-number-answer.js';
|
|
21
|
+
export * from './components/utils/question-has-answer.js';
|
|
22
|
+
export * from './components/utils/question-utils.js';
|
|
23
|
+
export * from './components/utils/component-types.js';
|
|
24
|
+
|
|
25
|
+
// Controller
|
|
26
|
+
export * from './controller.js';
|
|
27
|
+
|
|
28
|
+
// Journey
|
|
29
|
+
export { Journey } from './journey/journey.js';
|
|
30
|
+
export { JourneyResponse } from './journey/journey-response.js';
|
|
31
|
+
|
|
32
|
+
// lib
|
|
33
|
+
export * from './lib/address.js';
|
|
34
|
+
export * from './lib/address-utils.js';
|
|
35
|
+
export * from './lib/date-utils.js';
|
|
36
|
+
export * from './lib/session-answer-store.js';
|
|
37
|
+
export * from './lib/utils.js';
|
|
38
|
+
|
|
39
|
+
// middleware
|
|
40
|
+
export * from './middleware/build-get-journey.js';
|
|
41
|
+
export * from './middleware/redirect-to-unanswered-question.js';
|
|
42
|
+
|
|
43
|
+
// Questions
|
|
44
|
+
export { Question } from './questions/question.js';
|
|
45
|
+
export { createQuestions } from './questions/create-questions.js';
|
|
46
|
+
export * from './questions/options-question.js';
|
|
47
|
+
export { questionClasses } from './questions/questions.js';
|
|
48
|
+
|
|
49
|
+
// Section
|
|
50
|
+
export { Section } from './section.js';
|
|
51
|
+
|
|
52
|
+
// validators
|
|
53
|
+
export * from './validator/address-validator.js';
|
|
54
|
+
export * from './validator/base-validator.js';
|
|
55
|
+
export * from './validator/conditional-required-validator.js';
|
|
56
|
+
export * from './validator/confirmation-checkbox-validator.js';
|
|
57
|
+
export * from './validator/coordinates-validator.js';
|
|
58
|
+
export * from './validator/date-period-validator.js';
|
|
59
|
+
export * from './validator/date-time-validator.js';
|
|
60
|
+
export { DateValidator };
|
|
61
|
+
export { EmailValidator };
|
|
62
|
+
export * from './validator/document-upload-validator.js';
|
|
63
|
+
export * from './validator/multi-field-input-validator.js';
|
|
64
|
+
export * from './validator/numeric-validator.js';
|
|
65
|
+
export { default as RequiredValidator } from './validator/required-validator.js';
|
|
66
|
+
export * from './validator/same-answer-validator.js';
|
|
67
|
+
export { StringValidator };
|
|
68
|
+
export * from './validator/unit-option-entry-validator.js';
|
|
69
|
+
export * from './validator/valid-option-validator.js';
|
|
70
|
+
export * from './validator/validation-error-handler.js';
|
|
71
|
+
export { default as validate } from './validator/validator.js';
|
|
72
|
+
export * from './validator/validator.js';
|
|
@@ -5,7 +5,7 @@ import { redirectToUnansweredQuestion } from './redirect-to-unanswered-question.
|
|
|
5
5
|
import { JourneyResponse } from '../journey/journey-response.js';
|
|
6
6
|
import { Journey } from '../journey/journey.js';
|
|
7
7
|
import { Section } from '../section.js';
|
|
8
|
-
import { COMPONENT_TYPES } from '../
|
|
8
|
+
import { COMPONENT_TYPES } from '../components/utils/component-types.js';
|
|
9
9
|
import { questionHasAnswer } from '../components/utils/question-has-answer.js';
|
|
10
10
|
|
|
11
11
|
describe('redirectToUnansweredQuestion Middleware', () => {
|
|
@@ -5,13 +5,6 @@ import { getConditionalFieldName } from '../components/utils/question-utils.js';
|
|
|
5
5
|
|
|
6
6
|
const defaultOptionJoinString = ',';
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* @typedef {import('./question').QuestionViewModel} QuestionViewModel
|
|
10
|
-
* @typedef {import('../journey/journey.js').Journey} Journey
|
|
11
|
-
* @typedef {import('../journey/journey-response.js').JourneyResponse} JourneyResponse
|
|
12
|
-
* @typedef {import('../section.js').Section} Section
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
8
|
/**
|
|
16
9
|
* @typedef {{
|
|
17
10
|
* text: string;
|
|
@@ -37,7 +30,7 @@ const defaultOptionJoinString = ',';
|
|
|
37
30
|
*/
|
|
38
31
|
|
|
39
32
|
/**
|
|
40
|
-
* @typedef {QuestionViewModel & { question: { options: Option[] } }} OptionsViewModel
|
|
33
|
+
* @typedef {import('./question').QuestionViewModel & { question: { options: Option[] } }} OptionsViewModel
|
|
41
34
|
*/
|
|
42
35
|
|
|
43
36
|
export default class OptionsQuestion extends Question {
|
|
@@ -65,12 +58,12 @@ export default class OptionsQuestion extends Question {
|
|
|
65
58
|
|
|
66
59
|
/**
|
|
67
60
|
* gets the view model for this question
|
|
68
|
-
* @param {Section} section - the current section
|
|
69
|
-
* @param {Journey} journey - the journey we are in
|
|
61
|
+
* @param {import('#section').Section} section - the current section
|
|
62
|
+
* @param {import('#journey').Journey} journey - the journey we are in
|
|
70
63
|
* @param {Record<string, unknown>} [customViewData] additional data to send to view
|
|
71
64
|
* @param {Record<string, unknown>} [payload]
|
|
72
65
|
* @param {import('#src/questions/question-types.d.ts').PrepQuestionForRenderingOptions} options
|
|
73
|
-
* @returns {QuestionViewModel}
|
|
66
|
+
* @returns {import('./question').QuestionViewModel} QuestionViewModel
|
|
74
67
|
*/
|
|
75
68
|
prepQuestionForRendering(section, journey, customViewData, payload, options) {
|
|
76
69
|
const viewModel = super.prepQuestionForRendering(section, journey, customViewData, payload, options);
|
|
@@ -125,7 +118,7 @@ export default class OptionsQuestion extends Question {
|
|
|
125
118
|
/**
|
|
126
119
|
* Get the data to save from the request, returns an object of answers
|
|
127
120
|
* @param {import('express').Request} req
|
|
128
|
-
* @param {JourneyResponse} journeyResponse - current journey response, modified with the new answers
|
|
121
|
+
* @param {import('../journey/journey-response.js').JourneyResponse} journeyResponse - current journey response, modified with the new answers
|
|
129
122
|
* @returns {Promise<{ answers: Record<string, unknown> }>}
|
|
130
123
|
*/ //eslint-disable-next-line no-unused-vars -- journeyResponse kept for other questions to use
|
|
131
124
|
async getDataToSave(req, journeyResponse) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import BaseValidator from '../validator/base-validator';
|
|
2
|
-
import { JourneyResponse } from '../journey/journey-response';
|
|
3
1
|
import { RouteParams } from '#src/journey/journey-types.d.ts';
|
|
4
2
|
import ManageListQuestion from '#src/components/manage-list/question.js';
|
|
3
|
+
import BaseValidator from '../validator/base-validator.js';
|
|
4
|
+
import { JourneyResponse } from '../journey/journey-response.js';
|
|
5
5
|
|
|
6
6
|
export interface QuestionParameters {
|
|
7
7
|
title: string;
|
|
@@ -22,7 +22,7 @@ export interface QuestionParameters {
|
|
|
22
22
|
// override the action link for this question
|
|
23
23
|
actionLink?: ActionLink;
|
|
24
24
|
// static view data for this question
|
|
25
|
-
viewData?:
|
|
25
|
+
viewData?: Record<string, any>;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export interface ActionLink {
|
|
@@ -6,12 +6,12 @@ import MultiFieldInputValidator from '../validator/multi-field-input-validator.j
|
|
|
6
6
|
import { answerObjectForManageList } from '#src/components/manage-list/utils.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* @
|
|
10
|
-
* @
|
|
11
|
-
* @
|
|
12
|
-
* @
|
|
13
|
-
* @
|
|
14
|
-
* @
|
|
9
|
+
* @import {BaseValidator} from "#base-validator"
|
|
10
|
+
* @import {Journey} from "#journey"
|
|
11
|
+
* @import {JourneyResponse} from "#journey-response"
|
|
12
|
+
* @import {Section} from "#section"
|
|
13
|
+
* @import {ActionView} from "../controller.js"
|
|
14
|
+
* @import {ActionLink} from "./question-types.js"
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -12,7 +12,7 @@ import NumberEntryQuestion from '../components/number-entry/question.js';
|
|
|
12
12
|
import UnitOptionEntryQuestion from '../components/unit-option-entry/question.js';
|
|
13
13
|
import EmailQuestion from '../components/email/question.js';
|
|
14
14
|
|
|
15
|
-
import { COMPONENT_TYPES } from '../
|
|
15
|
+
import { COMPONENT_TYPES } from '../components/utils/component-types.js';
|
|
16
16
|
import TextEntryRedactQuestion from '../components/text-entry-redact/question.js';
|
|
17
17
|
import DateTimeQuestion from '../components/date-time/question.js';
|
|
18
18
|
import ManageListQuestion from '../components/manage-list/question.js';
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { describe, it } from 'node:test';
|
|
2
2
|
import assert from 'assert';
|
|
3
3
|
import { manageListQuestions, questionsInOrder } from './questions.js';
|
|
4
|
-
import
|
|
5
|
-
import { escapeForRegExp, snapshotsDir } from './utils/utils.js';
|
|
4
|
+
import { assertSnapshot, escapeForRegExp } from './utils/utils.js';
|
|
6
5
|
import { createAppWithQuestions, mockAnswer, mockAnswerBody } from './utils/question-test-utils.js';
|
|
7
6
|
import { COMPONENT_TYPES } from '#src/index.js';
|
|
8
7
|
|
|
@@ -30,9 +29,7 @@ describe('check-your-answers', () => {
|
|
|
30
29
|
new RegExp(`<a[^>]* href="questions/${q.url}">\\s*Answer\\s*<span[^>]*>\\s*${escapedQ}\\s*</span></a>`, 'i')
|
|
31
30
|
);
|
|
32
31
|
}
|
|
33
|
-
ctx
|
|
34
|
-
serializers: [(v) => v]
|
|
35
|
-
});
|
|
32
|
+
assertSnapshot(ctx, text, 'check-your-answers-not-started.html');
|
|
36
33
|
});
|
|
37
34
|
|
|
38
35
|
it(`should render all question answers`, async (ctx) => {
|
|
@@ -80,8 +77,6 @@ describe('check-your-answers', () => {
|
|
|
80
77
|
new RegExp(`<a[^>]* href="questions/${q.url}">\\s*Change\\s*<span[^>]*>\\s*${escapedQ}\\s*</span></a>`, 'i')
|
|
81
78
|
);
|
|
82
79
|
}
|
|
83
|
-
ctx
|
|
84
|
-
serializers: [(v) => v]
|
|
85
|
-
});
|
|
80
|
+
assertSnapshot(ctx, text, 'check-your-answers-with-answers.html');
|
|
86
81
|
});
|
|
87
82
|
});
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'assert';
|
|
3
|
+
import { Section } from '#src/section.js';
|
|
4
|
+
import { Journey } from '#src/journey/journey.js';
|
|
5
|
+
import { COMPONENT_TYPES } from '#src/index.js';
|
|
6
|
+
import { createQuestions } from '#src/questions/create-questions.js';
|
|
7
|
+
import { questionClasses } from '#src/questions/questions.js';
|
|
8
|
+
import { whenQuestionHasAnswer } from '#src/components/utils/question-has-answer.js';
|
|
9
|
+
import { BOOLEAN_OPTIONS } from '#src/components/boolean/question.js';
|
|
10
|
+
import { createAppWithQuestions, renderQuestionCheck, postAnswer } from '#test/utils/question-test-utils.js';
|
|
11
|
+
|
|
12
|
+
const JOURNEY_ID = 'conditional-journey';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Question props for conditional journey tests
|
|
16
|
+
* @type {Record<string, import('#src/questions/question-props.js').QuestionProps>}
|
|
17
|
+
*/
|
|
18
|
+
const conditionalQuestionProps = {
|
|
19
|
+
// Section 1: Insurance (simple + chained conditions)
|
|
20
|
+
wantsInsurance: {
|
|
21
|
+
type: COMPONENT_TYPES.BOOLEAN,
|
|
22
|
+
title: 'Want Insurance',
|
|
23
|
+
question: 'Do you want to add travel insurance?',
|
|
24
|
+
fieldName: 'wantsInsurance',
|
|
25
|
+
url: 'wants-insurance',
|
|
26
|
+
label: 'Add insurance?'
|
|
27
|
+
},
|
|
28
|
+
insuranceLevel: {
|
|
29
|
+
type: COMPONENT_TYPES.RADIO,
|
|
30
|
+
title: 'Insurance Level',
|
|
31
|
+
question: 'What level of insurance do you want?',
|
|
32
|
+
fieldName: 'insuranceLevel',
|
|
33
|
+
url: 'insurance-level',
|
|
34
|
+
label: 'Select an insurance level',
|
|
35
|
+
options: [
|
|
36
|
+
{ value: 'basic', text: 'Basic' },
|
|
37
|
+
{ value: 'premium', text: 'Premium' }
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
premiumBenefits: {
|
|
41
|
+
type: COMPONENT_TYPES.CHECKBOX,
|
|
42
|
+
title: 'Premium Benefits',
|
|
43
|
+
question: 'Which premium benefits do you want?',
|
|
44
|
+
fieldName: 'premiumBenefits',
|
|
45
|
+
url: 'premium-benefits',
|
|
46
|
+
label: 'Select all that apply',
|
|
47
|
+
options: [
|
|
48
|
+
{ value: 'cancellation', text: 'Cancellation cover' },
|
|
49
|
+
{ value: 'medical', text: 'Medical cover' },
|
|
50
|
+
{ value: 'luggage', text: 'Luggage cover' }
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
// Section 2: Trip (leads to section condition)
|
|
54
|
+
tripType: {
|
|
55
|
+
type: COMPONENT_TYPES.RADIO,
|
|
56
|
+
title: 'Trip Type',
|
|
57
|
+
question: 'What type of trip are you planning?',
|
|
58
|
+
fieldName: 'tripType',
|
|
59
|
+
url: 'trip-type',
|
|
60
|
+
label: 'Select a trip type',
|
|
61
|
+
options: [
|
|
62
|
+
{ value: 'domestic', text: 'Domestic' },
|
|
63
|
+
{ value: 'international', text: 'International' }
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
// Section 3: Visa (section-wide condition based on tripType)
|
|
67
|
+
visaRequired: {
|
|
68
|
+
type: COMPONENT_TYPES.BOOLEAN,
|
|
69
|
+
title: 'Visa Required',
|
|
70
|
+
question: 'Do you need a visa for your destination?',
|
|
71
|
+
fieldName: 'visaRequired',
|
|
72
|
+
url: 'visa-required',
|
|
73
|
+
label: 'Visa required?'
|
|
74
|
+
},
|
|
75
|
+
visaType: {
|
|
76
|
+
type: COMPONENT_TYPES.RADIO,
|
|
77
|
+
title: 'Visa Type',
|
|
78
|
+
question: 'What type of visa do you need?',
|
|
79
|
+
fieldName: 'visaType',
|
|
80
|
+
url: 'visa-type',
|
|
81
|
+
label: 'Select a visa type',
|
|
82
|
+
options: [
|
|
83
|
+
{ value: 'tourist', text: 'Tourist' },
|
|
84
|
+
{ value: 'business', text: 'Business' }
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
// Section 4: Accommodation (multi-question condition)
|
|
88
|
+
accommodation: {
|
|
89
|
+
type: COMPONENT_TYPES.RADIO,
|
|
90
|
+
title: 'Accommodation',
|
|
91
|
+
question: 'Where will you stay?',
|
|
92
|
+
fieldName: 'accommodation',
|
|
93
|
+
url: 'accommodation',
|
|
94
|
+
label: 'Select accommodation type',
|
|
95
|
+
options: [
|
|
96
|
+
{ value: 'hotel', text: 'Hotel' },
|
|
97
|
+
{ value: 'hostel', text: 'Hostel' },
|
|
98
|
+
{ value: 'apartment', text: 'Apartment' }
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
hotelStars: {
|
|
102
|
+
type: COMPONENT_TYPES.RADIO,
|
|
103
|
+
title: 'Hotel Stars',
|
|
104
|
+
question: 'How many stars for your hotel?',
|
|
105
|
+
fieldName: 'hotelStars',
|
|
106
|
+
url: 'hotel-stars',
|
|
107
|
+
label: 'Select star rating',
|
|
108
|
+
options: [
|
|
109
|
+
{ value: '3', text: '3 stars' },
|
|
110
|
+
{ value: '4', text: '4 stars' },
|
|
111
|
+
{ value: '5', text: '5 stars' }
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
hotelBreakfast: {
|
|
115
|
+
type: COMPONENT_TYPES.BOOLEAN,
|
|
116
|
+
title: 'Hotel Breakfast',
|
|
117
|
+
question: 'Do you want breakfast included?',
|
|
118
|
+
fieldName: 'hotelBreakfast',
|
|
119
|
+
url: 'hotel-breakfast',
|
|
120
|
+
label: 'Include breakfast?'
|
|
121
|
+
},
|
|
122
|
+
// Section 5: Contact (always shown)
|
|
123
|
+
contactEmail: {
|
|
124
|
+
type: COMPONENT_TYPES.EMAIL,
|
|
125
|
+
title: 'Contact Email',
|
|
126
|
+
question: 'What is your email address?',
|
|
127
|
+
fieldName: 'contactEmail',
|
|
128
|
+
url: 'contact-email',
|
|
129
|
+
label: 'Email address'
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Create the questions for conditional tests
|
|
135
|
+
*/
|
|
136
|
+
const conditionalQuestions = createQuestions(conditionalQuestionProps, questionClasses, {});
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Create a single journey with various conditional logic scenarios:
|
|
140
|
+
*
|
|
141
|
+
* Section 1 - Insurance (simple + chained conditions):
|
|
142
|
+
* - wantsInsurance: always shown
|
|
143
|
+
* - insuranceLevel: shown if wantsInsurance = 'yes' (simple condition)
|
|
144
|
+
* - premiumBenefits: shown if insuranceLevel = 'premium' (chained condition)
|
|
145
|
+
*
|
|
146
|
+
* Section 2 - Trip:
|
|
147
|
+
* - tripType: always shown
|
|
148
|
+
*
|
|
149
|
+
* Section 3 - Visa (section-wide condition):
|
|
150
|
+
* - Entire section shown only if tripType = 'international'
|
|
151
|
+
* - visaRequired: shown if section condition met
|
|
152
|
+
* - visaType: shown if section condition met AND visaRequired = 'yes'
|
|
153
|
+
*
|
|
154
|
+
* Section 4 - Accommodation (multi-question condition):
|
|
155
|
+
* - accommodation: always shown
|
|
156
|
+
* - hotelStars + hotelBreakfast: shown only if accommodation = 'hotel' (multi-question group)
|
|
157
|
+
*
|
|
158
|
+
* Section 5 - Contact:
|
|
159
|
+
* - contactEmail: always shown
|
|
160
|
+
*/
|
|
161
|
+
function createConditionalJourney(questions, response) {
|
|
162
|
+
return new Journey({
|
|
163
|
+
journeyId: JOURNEY_ID,
|
|
164
|
+
sections: [
|
|
165
|
+
// Section 1: Insurance with simple and chained conditions
|
|
166
|
+
new Section('Insurance', 'insurance')
|
|
167
|
+
.addQuestion(questions.wantsInsurance)
|
|
168
|
+
.addQuestion(questions.insuranceLevel)
|
|
169
|
+
.withCondition(whenQuestionHasAnswer(questions.wantsInsurance, BOOLEAN_OPTIONS.YES))
|
|
170
|
+
.addQuestion(questions.premiumBenefits)
|
|
171
|
+
.withCondition(whenQuestionHasAnswer(questions.insuranceLevel, 'premium')),
|
|
172
|
+
|
|
173
|
+
// Section 2: Trip type (determines section condition for visa)
|
|
174
|
+
new Section('Trip Details', 'trip').addQuestion(questions.tripType),
|
|
175
|
+
|
|
176
|
+
// Section 3: Visa with section-wide condition
|
|
177
|
+
new Section('Visa', 'visa')
|
|
178
|
+
.withSectionCondition(whenQuestionHasAnswer(questions.tripType, 'international'))
|
|
179
|
+
.addQuestion(questions.visaRequired)
|
|
180
|
+
.addQuestion(questions.visaType)
|
|
181
|
+
.withCondition(whenQuestionHasAnswer(questions.visaRequired, BOOLEAN_OPTIONS.YES)),
|
|
182
|
+
|
|
183
|
+
// Section 4: Accommodation with multi-question condition
|
|
184
|
+
new Section('Accommodation', 'accommodation')
|
|
185
|
+
.addQuestion(questions.accommodation)
|
|
186
|
+
.startMultiQuestionCondition('hotel-group', whenQuestionHasAnswer(questions.accommodation, 'hotel'))
|
|
187
|
+
.addQuestion(questions.hotelStars)
|
|
188
|
+
.addQuestion(questions.hotelBreakfast)
|
|
189
|
+
.endMultiQuestionCondition('hotel-group'),
|
|
190
|
+
|
|
191
|
+
// Section 5: Contact (always shown)
|
|
192
|
+
new Section('Contact', 'contact').addQuestion(questions.contactEmail)
|
|
193
|
+
],
|
|
194
|
+
taskListUrl: 'check-your-answers',
|
|
195
|
+
journeyTemplate: 'views/layout-journey.njk',
|
|
196
|
+
taskListTemplate: 'views/layout-check-your-answers.njk',
|
|
197
|
+
journeyTitle: 'Conditional Journey',
|
|
198
|
+
returnToListing: false,
|
|
199
|
+
makeBaseUrl: () => '/',
|
|
200
|
+
initialBackLink: '/start',
|
|
201
|
+
response
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Helper to create an app with the conditional journey
|
|
207
|
+
* @param {import('node:test').TestContext} ctx
|
|
208
|
+
* @returns {Promise<import('#test/utils/test-server.js').TestServer>}
|
|
209
|
+
*/
|
|
210
|
+
function createAppWithJourney(ctx) {
|
|
211
|
+
return createAppWithQuestions(ctx, {
|
|
212
|
+
journeyId: JOURNEY_ID,
|
|
213
|
+
questions: conditionalQuestions,
|
|
214
|
+
createJourneyFn: createConditionalJourney
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const q = conditionalQuestionProps;
|
|
219
|
+
|
|
220
|
+
describe('conditional journey tests', () => {
|
|
221
|
+
describe('simple condition (whenQuestionHasAnswer on single question)', () => {
|
|
222
|
+
it('should show conditional question when condition is met', async (ctx) => {
|
|
223
|
+
const testServer = await createAppWithJourney(ctx);
|
|
224
|
+
|
|
225
|
+
// First, render the initial question
|
|
226
|
+
await renderQuestionCheck(ctx, testServer, '/insurance/wants-insurance', q.wantsInsurance.question);
|
|
227
|
+
|
|
228
|
+
// Answer 'yes' to wantsInsurance
|
|
229
|
+
const location = await postAnswer(testServer, '/insurance/wants-insurance', {
|
|
230
|
+
[q.wantsInsurance.fieldName]: BOOLEAN_OPTIONS.YES
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Should redirect to insuranceLevel (conditional question)
|
|
234
|
+
assert.strictEqual(location, 'insurance/insurance-level');
|
|
235
|
+
|
|
236
|
+
// Render the conditional question
|
|
237
|
+
await renderQuestionCheck(ctx, testServer, '/insurance/insurance-level', q.insuranceLevel.question);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('should skip conditional question when condition is not met', async (ctx) => {
|
|
241
|
+
const testServer = await createAppWithJourney(ctx);
|
|
242
|
+
|
|
243
|
+
// Answer 'no' to wantsInsurance
|
|
244
|
+
const location = await postAnswer(testServer, '/insurance/wants-insurance', {
|
|
245
|
+
[q.wantsInsurance.fieldName]: BOOLEAN_OPTIONS.NO
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// Should skip insuranceLevel and premiumBenefits, go to next section (trip)
|
|
249
|
+
assert.strictEqual(location, 'trip/trip-type');
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
describe('chained conditions (multiple dependent conditions)', () => {
|
|
254
|
+
it('should show both conditional questions when all conditions are met', async (ctx) => {
|
|
255
|
+
const testServer = await createAppWithJourney(ctx);
|
|
256
|
+
|
|
257
|
+
// Answer 'yes' to wantsInsurance
|
|
258
|
+
await postAnswer(testServer, '/insurance/wants-insurance', {
|
|
259
|
+
[q.wantsInsurance.fieldName]: BOOLEAN_OPTIONS.YES
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Answer 'premium' to insuranceLevel
|
|
263
|
+
const location = await postAnswer(testServer, '/insurance/insurance-level', {
|
|
264
|
+
[q.insuranceLevel.fieldName]: 'premium'
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Should go to premiumBenefits
|
|
268
|
+
assert.strictEqual(location, 'insurance/premium-benefits');
|
|
269
|
+
|
|
270
|
+
// Render the premium benefits question
|
|
271
|
+
await renderQuestionCheck(ctx, testServer, '/insurance/premium-benefits', q.premiumBenefits.question);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('should skip second conditional question when its condition is not met', async (ctx) => {
|
|
275
|
+
const testServer = await createAppWithJourney(ctx);
|
|
276
|
+
|
|
277
|
+
// Answer 'yes' to wantsInsurance
|
|
278
|
+
await postAnswer(testServer, '/insurance/wants-insurance', {
|
|
279
|
+
[q.wantsInsurance.fieldName]: BOOLEAN_OPTIONS.YES
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// Answer 'basic' to insuranceLevel (not 'premium')
|
|
283
|
+
const location = await postAnswer(testServer, '/insurance/insurance-level', {
|
|
284
|
+
[q.insuranceLevel.fieldName]: 'basic'
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Should skip premiumBenefits and go to next section (trip)
|
|
288
|
+
assert.strictEqual(location, 'trip/trip-type');
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('should skip all conditional questions when first condition is not met', async (ctx) => {
|
|
292
|
+
const testServer = await createAppWithJourney(ctx);
|
|
293
|
+
|
|
294
|
+
// Answer 'no' to wantsInsurance
|
|
295
|
+
const location = await postAnswer(testServer, '/insurance/wants-insurance', {
|
|
296
|
+
[q.wantsInsurance.fieldName]: BOOLEAN_OPTIONS.NO
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// Should skip insuranceLevel and premiumBenefits, go to next section (trip)
|
|
300
|
+
assert.strictEqual(location, 'trip/trip-type');
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
describe('section-wide conditions (withSectionCondition)', () => {
|
|
305
|
+
it('should show section questions when section condition is met', async (ctx) => {
|
|
306
|
+
const testServer = await createAppWithJourney(ctx);
|
|
307
|
+
|
|
308
|
+
// Answer 'international' to tripType
|
|
309
|
+
const location = await postAnswer(testServer, '/trip/trip-type', {
|
|
310
|
+
[q.tripType.fieldName]: 'international'
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// Should go to visa section (visaRequired)
|
|
314
|
+
assert.strictEqual(location, 'visa/visa-required');
|
|
315
|
+
|
|
316
|
+
// Render the visa question
|
|
317
|
+
await renderQuestionCheck(ctx, testServer, '/visa/visa-required', q.visaRequired.question);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('should skip entire section when section condition is not met', async (ctx) => {
|
|
321
|
+
const testServer = await createAppWithJourney(ctx);
|
|
322
|
+
|
|
323
|
+
// Answer 'domestic' to tripType
|
|
324
|
+
const location = await postAnswer(testServer, '/trip/trip-type', {
|
|
325
|
+
[q.tripType.fieldName]: 'domestic'
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Should skip visa section and go to accommodation section
|
|
329
|
+
assert.strictEqual(location, 'accommodation/accommodation');
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('should combine section condition with question condition', async (ctx) => {
|
|
333
|
+
const testServer = await createAppWithJourney(ctx);
|
|
334
|
+
|
|
335
|
+
// Answer 'international' to tripType
|
|
336
|
+
await postAnswer(testServer, '/trip/trip-type', {
|
|
337
|
+
[q.tripType.fieldName]: 'international'
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// Answer 'yes' to visaRequired
|
|
341
|
+
const location = await postAnswer(testServer, '/visa/visa-required', {
|
|
342
|
+
[q.visaRequired.fieldName]: BOOLEAN_OPTIONS.YES
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
// Should go to visaType (condition met)
|
|
346
|
+
assert.strictEqual(location, 'visa/visa-type');
|
|
347
|
+
|
|
348
|
+
// Render the visa type question
|
|
349
|
+
await renderQuestionCheck(ctx, testServer, '/visa/visa-type', q.visaType.question);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('should skip conditional question within section when its condition is not met', async (ctx) => {
|
|
353
|
+
const testServer = await createAppWithJourney(ctx);
|
|
354
|
+
|
|
355
|
+
// Answer 'international' to tripType
|
|
356
|
+
await postAnswer(testServer, '/trip/trip-type', {
|
|
357
|
+
[q.tripType.fieldName]: 'international'
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
// Answer 'no' to visaRequired
|
|
361
|
+
const location = await postAnswer(testServer, '/visa/visa-required', {
|
|
362
|
+
[q.visaRequired.fieldName]: BOOLEAN_OPTIONS.NO
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
// Should skip visaType and go to accommodation section
|
|
366
|
+
assert.strictEqual(location, 'accommodation/accommodation');
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
describe('multi-question conditions (startMultiQuestionCondition)', () => {
|
|
371
|
+
it('should show all questions in group when condition is met', async (ctx) => {
|
|
372
|
+
const testServer = await createAppWithJourney(ctx);
|
|
373
|
+
|
|
374
|
+
// Answer 'hotel' to accommodation
|
|
375
|
+
const location = await postAnswer(testServer, '/accommodation/accommodation', {
|
|
376
|
+
[q.accommodation.fieldName]: 'hotel'
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
// Should go to hotelStars (first question in group)
|
|
380
|
+
assert.strictEqual(location, 'accommodation/hotel-stars');
|
|
381
|
+
|
|
382
|
+
// Render the hotel stars question
|
|
383
|
+
await renderQuestionCheck(ctx, testServer, '/accommodation/hotel-stars', q.hotelStars.question);
|
|
384
|
+
|
|
385
|
+
// Answer hotelStars
|
|
386
|
+
const nextLocation = await postAnswer(testServer, '/accommodation/hotel-stars', {
|
|
387
|
+
[q.hotelStars.fieldName]: '4'
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// Should go to hotelBreakfast (second question in group)
|
|
391
|
+
assert.strictEqual(nextLocation, 'accommodation/hotel-breakfast');
|
|
392
|
+
|
|
393
|
+
// Render the hotel breakfast question
|
|
394
|
+
await renderQuestionCheck(ctx, testServer, '/accommodation/hotel-breakfast', q.hotelBreakfast.question);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it('should skip all questions in group when condition is not met', async (ctx) => {
|
|
398
|
+
const testServer = await createAppWithJourney(ctx);
|
|
399
|
+
|
|
400
|
+
// Answer 'hostel' to accommodation (not 'hotel')
|
|
401
|
+
const location = await postAnswer(testServer, '/accommodation/accommodation', {
|
|
402
|
+
[q.accommodation.fieldName]: 'hostel'
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// Should skip hotelStars and hotelBreakfast, go to contact section
|
|
406
|
+
assert.strictEqual(location, 'contact/contact-email');
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it('should proceed to question after group ends', async (ctx) => {
|
|
410
|
+
const testServer = await createAppWithJourney(ctx);
|
|
411
|
+
|
|
412
|
+
// Answer 'hotel' to accommodation
|
|
413
|
+
await postAnswer(testServer, '/accommodation/accommodation', {
|
|
414
|
+
[q.accommodation.fieldName]: 'hotel'
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
// Answer hotelStars
|
|
418
|
+
await postAnswer(testServer, '/accommodation/hotel-stars', {
|
|
419
|
+
[q.hotelStars.fieldName]: '5'
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// Answer hotelBreakfast (last in group)
|
|
423
|
+
const location = await postAnswer(testServer, '/accommodation/hotel-breakfast', {
|
|
424
|
+
[q.hotelBreakfast.fieldName]: BOOLEAN_OPTIONS.YES
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// Should go to contact section (after group ends)
|
|
428
|
+
assert.strictEqual(location, 'contact/contact-email');
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
});
|