@planning-inspectorate/dynamic-forms 2.3.0 → 3.0.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.
Files changed (43) hide show
  1. package/package.json +2 -1
  2. package/src/components/manage-list/README.md +97 -0
  3. package/src/components/manage-list/answer-summary-list.njk +10 -0
  4. package/src/components/manage-list/index.njk +61 -0
  5. package/src/components/manage-list/manage-list-section.js +39 -0
  6. package/src/components/manage-list/manage-list-section.test.js +52 -0
  7. package/src/components/manage-list/question.js +147 -0
  8. package/src/components/manage-list/question.test.js +139 -0
  9. package/src/components/utils/nunjucks.js +20 -0
  10. package/src/controller.js +60 -20
  11. package/src/controller.test.js +110 -43
  12. package/src/index.js +3 -2
  13. package/src/journey/journey-types.d.ts +18 -0
  14. package/src/journey/journey.js +104 -40
  15. package/src/journey/journey.test.js +94 -23
  16. package/src/lib/uuid.js +10 -0
  17. package/src/lib/uuid.test.js +24 -0
  18. package/src/middleware/dynamic-req-files-to-req-body-files.js +1 -2
  19. package/src/middleware/dynamic-req-files-to-req-body-files.test.js +2 -2
  20. package/src/questions/question-props.d.ts +2 -1
  21. package/src/questions/question.js +67 -18
  22. package/src/questions/question.test.js +26 -3
  23. package/src/questions/questions.js +3 -1
  24. package/src/section-types.d.ts +18 -0
  25. package/src/section.js +67 -2
  26. package/src/section.test.js +176 -1
  27. package/src/validator/validator.js +1 -3
  28. package/src/validator/validator.test.js +7 -7
  29. package/test/journey.js +5 -0
  30. package/test/mock/journey.js +17 -0
  31. package/test/questions.js +30 -1
  32. package/test/questions.test.js +119 -48
  33. package/test/snapshots/check-your-answers-not-started.html +11 -0
  34. package/test/snapshots/check-your-answers-with-answers.html +11 -0
  35. package/test/snapshots/manage-list-answer-summary.html +14 -0
  36. package/test/snapshots/manage-list-render-questions.html +97 -0
  37. package/test/snapshots/manage-list-render.html +91 -0
  38. package/test/snapshots/travel-companions.html +19 -0
  39. package/test/snapshots/travel-companions_travel-companion-email.html +21 -0
  40. package/test/snapshots/travel-companions_travel-companion-name.html +21 -0
  41. package/test/utils/test-server.js +31 -9
  42. package/test/utils/utils.js +2 -1
  43. package/tsconfig.json +23 -0
@@ -0,0 +1,97 @@
1
+ <div class="govuk-grid-row">
2
+ <div class="govuk-grid-column-two-thirds">
3
+ <form action="" method="post" novalidate>
4
+
5
+ <h1 class="govuk-heading-l">You have added 3 Things</h1>
6
+
7
+ <dl class="govuk-summary-list">
8
+ <div class="govuk-summary-list__row ">
9
+ <dt class="govuk-summary-list__key">
10
+ Thing 1
11
+ </dt>
12
+ <dt class="govuk-summary-list__value">
13
+ Q 1:<br>
14
+ mock answer
15
+ <br><br>
16
+ Q 2:<br>
17
+ mock answer 2
18
+ </dt>
19
+ <dd class="govuk-summary-list__actions">
20
+ <ul class="govuk-summary-list__actions-list">
21
+ <li class="govuk-summary-list__actions-list-item">
22
+ <a class="govuk-link" href="/edit/id-1/first-question">
23
+ Change <span class="govuk-visually-hidden">Thing 1</span>
24
+ </a>
25
+ </li>
26
+ <li class="govuk-summary-list__actions-list-item">
27
+ <a class="govuk-link" href="/remove/id-1/confirm">
28
+ Remove <span class="govuk-visually-hidden">Thing 1</span>
29
+ </a>
30
+ </li>
31
+ </ul>
32
+ </dd>
33
+ </div>
34
+ <div class="govuk-summary-list__row ">
35
+ <dt class="govuk-summary-list__key">
36
+ Thing 2
37
+ </dt>
38
+ <dt class="govuk-summary-list__value">
39
+ Q 1:<br>
40
+ mock answer
41
+ <br><br>
42
+ Q 2:<br>
43
+ mock answer 2
44
+ </dt>
45
+ <dd class="govuk-summary-list__actions">
46
+ <ul class="govuk-summary-list__actions-list">
47
+ <li class="govuk-summary-list__actions-list-item">
48
+ <a class="govuk-link" href="/edit/id-2/first-question">
49
+ Change <span class="govuk-visually-hidden">Thing 2</span>
50
+ </a>
51
+ </li>
52
+ <li class="govuk-summary-list__actions-list-item">
53
+ <a class="govuk-link" href="/remove/id-2/confirm">
54
+ Remove <span class="govuk-visually-hidden">Thing 2</span>
55
+ </a>
56
+ </li>
57
+ </ul>
58
+ </dd>
59
+ </div>
60
+ <div class="govuk-summary-list__row ">
61
+ <dt class="govuk-summary-list__key">
62
+ Thing 3
63
+ </dt>
64
+ <dt class="govuk-summary-list__value">
65
+ Q 1:<br>
66
+ mock answer
67
+ <br><br>
68
+ Q 2:<br>
69
+ mock answer 2
70
+ </dt>
71
+ <dd class="govuk-summary-list__actions">
72
+ <ul class="govuk-summary-list__actions-list">
73
+ <li class="govuk-summary-list__actions-list-item">
74
+ <a class="govuk-link" href="/edit/id-3/first-question">
75
+ Change <span class="govuk-visually-hidden">Thing 3</span>
76
+ </a>
77
+ </li>
78
+ <li class="govuk-summary-list__actions-list-item">
79
+ <a class="govuk-link" href="/remove/id-3/confirm">
80
+ Remove <span class="govuk-visually-hidden">Thing 3</span>
81
+ </a>
82
+ </li>
83
+ </ul>
84
+ </dd>
85
+ </div>
86
+ </dl>
87
+
88
+ <p class="govuk-body">
89
+ <a href="/add/00000000-0000-0000-0000-000000000000/first-question" class="govuk-link">Add another</a>
90
+ </p>
91
+
92
+ <button type="submit" class="govuk-button" data-module="govuk-button" data-cy="button-save-and-continue">
93
+ Continue
94
+ </button>
95
+ </form>
96
+ </div>
97
+ </div>
@@ -0,0 +1,91 @@
1
+ <div class="govuk-grid-row">
2
+ <div class="govuk-grid-column-two-thirds">
3
+ <form action="" method="post" novalidate>
4
+
5
+ <h1 class="govuk-heading-l">You have added 3 Things</h1>
6
+
7
+ <dl class="govuk-summary-list">
8
+ <div class="govuk-summary-list__row ">
9
+ <dt class="govuk-summary-list__key">
10
+ Thing 1
11
+ </dt>
12
+ <dt class="govuk-summary-list__value">
13
+ mock answer
14
+ <br>
15
+ mock answer 2
16
+ </dt>
17
+ <dd class="govuk-summary-list__actions">
18
+ <ul class="govuk-summary-list__actions-list">
19
+ <li class="govuk-summary-list__actions-list-item">
20
+ <a class="govuk-link" href="/edit/id-1/first-question">
21
+ Change <span class="govuk-visually-hidden">Thing 1</span>
22
+ </a>
23
+ </li>
24
+ <li class="govuk-summary-list__actions-list-item">
25
+ <a class="govuk-link" href="/remove/id-1/confirm">
26
+ Remove <span class="govuk-visually-hidden">Thing 1</span>
27
+ </a>
28
+ </li>
29
+ </ul>
30
+ </dd>
31
+ </div>
32
+ <div class="govuk-summary-list__row ">
33
+ <dt class="govuk-summary-list__key">
34
+ Thing 2
35
+ </dt>
36
+ <dt class="govuk-summary-list__value">
37
+ mock answer
38
+ <br>
39
+ mock answer 2
40
+ </dt>
41
+ <dd class="govuk-summary-list__actions">
42
+ <ul class="govuk-summary-list__actions-list">
43
+ <li class="govuk-summary-list__actions-list-item">
44
+ <a class="govuk-link" href="/edit/id-2/first-question">
45
+ Change <span class="govuk-visually-hidden">Thing 2</span>
46
+ </a>
47
+ </li>
48
+ <li class="govuk-summary-list__actions-list-item">
49
+ <a class="govuk-link" href="/remove/id-2/confirm">
50
+ Remove <span class="govuk-visually-hidden">Thing 2</span>
51
+ </a>
52
+ </li>
53
+ </ul>
54
+ </dd>
55
+ </div>
56
+ <div class="govuk-summary-list__row ">
57
+ <dt class="govuk-summary-list__key">
58
+ Thing 3
59
+ </dt>
60
+ <dt class="govuk-summary-list__value">
61
+ mock answer
62
+ <br>
63
+ mock answer 2
64
+ </dt>
65
+ <dd class="govuk-summary-list__actions">
66
+ <ul class="govuk-summary-list__actions-list">
67
+ <li class="govuk-summary-list__actions-list-item">
68
+ <a class="govuk-link" href="/edit/id-3/first-question">
69
+ Change <span class="govuk-visually-hidden">Thing 3</span>
70
+ </a>
71
+ </li>
72
+ <li class="govuk-summary-list__actions-list-item">
73
+ <a class="govuk-link" href="/remove/id-3/confirm">
74
+ Remove <span class="govuk-visually-hidden">Thing 3</span>
75
+ </a>
76
+ </li>
77
+ </ul>
78
+ </dd>
79
+ </div>
80
+ </dl>
81
+
82
+ <p class="govuk-body">
83
+ <a href="/add/00000000-0000-0000-0000-000000000000/first-question" class="govuk-link">Add another</a>
84
+ </p>
85
+
86
+ <button type="submit" class="govuk-button" data-module="govuk-button" data-cy="button-save-and-continue">
87
+ Continue
88
+ </button>
89
+ </form>
90
+ </div>
91
+ </div>
@@ -0,0 +1,19 @@
1
+ <div class="govuk-grid-row">
2
+ <div class="govuk-grid-column-two-thirds">
3
+ <form action="" method="post" novalidate>
4
+
5
+ <h1 class="govuk-heading-l">You have added 0 Travel Companions</h1>
6
+
7
+ <dl class="govuk-summary-list">
8
+ </dl>
9
+
10
+ <p class="govuk-body">
11
+ <a href="/questions/travel-companions/add/00000000-0000-0000-0000-000000000000/travel-companion-name" class="govuk-link">Add another</a>
12
+ </p>
13
+
14
+ <button type="submit" class="govuk-button" data-module="govuk-button" data-cy="button-save-and-continue">
15
+ Continue
16
+ </button>
17
+ </form>
18
+ </div>
19
+ </div>
@@ -0,0 +1,21 @@
1
+ <div class="govuk-grid-row">
2
+ <div class="govuk-grid-column-two-thirds">
3
+ <form action="" method="post" novalidate>
4
+
5
+ <div class="govuk-form-group">
6
+ <h1 class="govuk-label-wrapper">
7
+ <label class="govuk-label govuk-label--l" for="travelCompanionEmail">
8
+ Travel Companion Email
9
+ </label>
10
+ </h1>
11
+ <input class="govuk-input" id="travelCompanionEmail" name="travelCompanionEmail" type="email" value="" autocomplete="email" spellcheck="false">
12
+ </div>
13
+
14
+
15
+
16
+ <button type="submit" class="govuk-button" data-module="govuk-button" data-cy="button-save-and-continue">
17
+ Continue
18
+ </button>
19
+ </form>
20
+ </div>
21
+ </div>
@@ -0,0 +1,21 @@
1
+ <div class="govuk-grid-row">
2
+ <div class="govuk-grid-column-two-thirds">
3
+ <form action="" method="post" novalidate>
4
+
5
+ <div class="govuk-form-group">
6
+ <h1 class="govuk-label-wrapper">
7
+ <label class="govuk-label govuk-label--l" for="travelCompanionName">
8
+ Travel Companion Name
9
+ </label>
10
+ </h1>
11
+ <input class="govuk-input" id="travelCompanionName" name="travelCompanionName" type="text" value="">
12
+ </div>
13
+
14
+
15
+
16
+ <button type="submit" class="govuk-button" data-module="govuk-button" data-cy="button-save-and-continue">
17
+ Continue
18
+ </button>
19
+ </form>
20
+ </div>
21
+ </div>
@@ -8,10 +8,12 @@ export class TestServer {
8
8
  // Private cookie jar for storing cookies between requests
9
9
  /** @type {Object<string, string>} */
10
10
  #cookieJar = {};
11
+ #timeoutMs;
11
12
 
12
13
  /**
13
14
  * @param {import('http').RequestListener} requestListener
14
15
  * @param {object} [options]
16
+ * @param {number} [options.timeoutMs] - timeout to use for fetch requests
15
17
  * @param {boolean} [options.rememberCookies] - If true, cookies are stored and sent with each request
16
18
  */
17
19
  constructor(requestListener, options = {}) {
@@ -19,6 +21,7 @@ export class TestServer {
19
21
  this.server = null;
20
22
  this.port = null;
21
23
  this.rememberCookies = Boolean(options.rememberCookies);
24
+ this.#timeoutMs = options.timeoutMs || 5000;
22
25
  }
23
26
 
24
27
  /**
@@ -66,11 +69,7 @@ export class TestServer {
66
69
  }
67
70
  const fetchOptions = { headers: {}, ...DEFAULT_OPTIONS, ...options, method: 'GET' };
68
71
  this.#addCookies(fetchOptions.headers);
69
- const response = await fetch(`http://localhost:${this.port}${path}`, fetchOptions);
70
- if (this.rememberCookies) {
71
- this.#updateCookies(response);
72
- }
73
- return response;
72
+ return this.#fetch(path, fetchOptions);
74
73
  }
75
74
 
76
75
  /**
@@ -131,11 +130,34 @@ export class TestServer {
131
130
  body: JSON.stringify(body)
132
131
  };
133
132
  this.#addCookies(fetchOptions.headers);
134
- const response = await fetch(`http://localhost:${this.port}${path}`, fetchOptions);
135
- if (this.rememberCookies) {
136
- this.#updateCookies(response);
133
+ return this.#fetch(path, fetchOptions);
134
+ }
135
+
136
+ /**
137
+ * Perform a fetch request with a timeout
138
+ *
139
+ * @param {string} path
140
+ * @param {RequestInit} [options]
141
+ */
142
+ async #fetch(path, options) {
143
+ // set up an abort controller to cancel requests after timeout
144
+ const controller = new AbortController();
145
+ const timeoutId = setTimeout(() => controller.abort(), this.#timeoutMs);
146
+ options.signal = controller.signal;
147
+ try {
148
+ const response = await fetch(`http://localhost:${this.port}${path}`, options);
149
+ if (this.rememberCookies) {
150
+ this.#updateCookies(response);
151
+ }
152
+ return response;
153
+ } catch (error) {
154
+ if (error instanceof Error && error.name === 'AbortError') {
155
+ throw new Error(`Request to ${path} timed out after ${this.#timeoutMs}ms`);
156
+ }
157
+ throw error;
158
+ } finally {
159
+ clearTimeout(timeoutId);
137
160
  }
138
- return response;
139
161
  }
140
162
 
141
163
  #addCookies(headers) {
@@ -28,7 +28,8 @@ export function mockLogger() {
28
28
  export const mockReq = () => ({
29
29
  log: mockLogger(),
30
30
  params: {},
31
- body: {}
31
+ body: {},
32
+ originalUrl: '/original-url'
32
33
  });
33
34
  export const mockRes = () => {
34
35
  const res = {
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "include": ["**/*.ts", "**/*.js"],
3
+ "exclude": ["node_modules", "packages/database/src/client/**", "**/*.test.ts", "test/**"],
4
+ "compilerOptions": {
5
+ "allowImportingTsExtensions": true,
6
+ "allowJs": true,
7
+ "allowSyntheticDefaultImports": true,
8
+ "baseUrl": ".",
9
+ "checkJs": false,
10
+ "erasableSyntaxOnly": true,
11
+ "esModuleInterop": true,
12
+ "module": "NodeNext",
13
+ "moduleResolution": "nodenext",
14
+ "strict": true,
15
+ "target": "esnext",
16
+ "skipLibCheck": true,
17
+ "paths": {
18
+ "#question-types": ["./src/questions/question-types.d.ts"],
19
+ "#src/*": ["./src/*"],
20
+ "#test/*": ["./test/*"]
21
+ }
22
+ }
23
+ }