@ukhomeoffice/cop-react-form-renderer 3.0.2 → 3.1.1
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/dist/components/FormComponent/Collection.js +1 -5
- package/dist/components/FormComponent/Collection.test.js +322 -0
- package/dist/components/FormRenderer/FormRenderer.js +2 -0
- package/dist/components/FormRenderer/helpers/cleanHiddenNestedData.js +38 -0
- package/dist/components/FormRenderer/helpers/cleanHiddenNestedData.test.js +50 -0
- package/dist/components/FormRenderer/helpers/index.js +3 -0
- package/dist/context/HooksContext/HooksContext.js +8 -2
- package/dist/utils/CheckYourAnswers/getCYARow.js +3 -1
- package/dist/utils/CheckYourAnswers/getCYARow.test.js +3 -3
- package/dist/utils/Component/cleanAttributes.js +1 -1
- package/dist/utils/Component/getComponent.js +37 -18
- package/dist/utils/Component/getComponentTests/getComponent.nested.test.js +49 -26
- package/dist/utils/FormPage/getFormPage.js +40 -0
- package/dist/utils/FormPage/getFormPage.test.js +85 -1
- package/dist/utils/Validate/validateComponent.js +8 -15
- package/dist/utils/Validate/validateComponent.test.js +13 -14
- package/package.json +2 -2
|
@@ -67,15 +67,11 @@ var Collection = function Collection(_ref) {
|
|
|
67
67
|
onChange = _ref.onChange,
|
|
68
68
|
wrap = _ref.wrap;
|
|
69
69
|
|
|
70
|
-
var _useState = (0, _react.useState)(),
|
|
70
|
+
var _useState = (0, _react.useState)(_value),
|
|
71
71
|
_useState2 = _slicedToArray(_useState, 2),
|
|
72
72
|
value = _useState2[0],
|
|
73
73
|
setValue = _useState2[1];
|
|
74
74
|
|
|
75
|
-
(0, _react.useEffect)(function () {
|
|
76
|
-
setValue(_value || []);
|
|
77
|
-
}, [_value, setValue]);
|
|
78
|
-
|
|
79
75
|
var reportChange = function reportChange(newValue) {
|
|
80
76
|
setValue(newValue);
|
|
81
77
|
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _react = require("@testing-library/react");
|
|
4
|
+
|
|
5
|
+
var _react2 = _interopRequireDefault(require("react"));
|
|
6
|
+
|
|
7
|
+
var _testUtils = require("react-dom/test-utils");
|
|
8
|
+
|
|
9
|
+
var _models = require("../../models");
|
|
10
|
+
|
|
11
|
+
var _setupTests = require("../../setupTests");
|
|
12
|
+
|
|
13
|
+
var _utils = _interopRequireDefault(require("../../utils"));
|
|
14
|
+
|
|
15
|
+
var _Collection = require("./Collection");
|
|
16
|
+
|
|
17
|
+
var _Container = require("./Container");
|
|
18
|
+
|
|
19
|
+
var _FormComponent = _interopRequireDefault(require("./FormComponent"));
|
|
20
|
+
|
|
21
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
22
|
+
|
|
23
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
24
|
+
|
|
25
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
26
|
+
|
|
27
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
28
|
+
|
|
29
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
30
|
+
|
|
31
|
+
function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
|
|
32
|
+
|
|
33
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
34
|
+
|
|
35
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
36
|
+
|
|
37
|
+
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
38
|
+
|
|
39
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
40
|
+
|
|
41
|
+
describe('components.FormComponent.Collection', function () {
|
|
42
|
+
var ID = 'collection';
|
|
43
|
+
var TEXT_ID = 'text';
|
|
44
|
+
var TEXT_VALUE = 'alpha';
|
|
45
|
+
|
|
46
|
+
var FORM_DATA = _defineProperty({}, ID, [_defineProperty({
|
|
47
|
+
id: '1'
|
|
48
|
+
}, TEXT_ID, TEXT_VALUE)]);
|
|
49
|
+
|
|
50
|
+
var TEXT_COMPONENT = {
|
|
51
|
+
id: TEXT_ID,
|
|
52
|
+
fieldId: TEXT_ID,
|
|
53
|
+
type: _models.ComponentTypes.TEXT,
|
|
54
|
+
label: 'Text component',
|
|
55
|
+
hint: 'Text hint'
|
|
56
|
+
};
|
|
57
|
+
it('should render a collection component appropriately', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
|
|
58
|
+
var COLLECTION, _renderWithValidation, container, c, item, _item$childNodes, title, itemContainer, formGroup, label, hint, input;
|
|
59
|
+
|
|
60
|
+
return regeneratorRuntime.wrap(function _callee$(_context) {
|
|
61
|
+
while (1) {
|
|
62
|
+
switch (_context.prev = _context.next) {
|
|
63
|
+
case 0:
|
|
64
|
+
COLLECTION = {
|
|
65
|
+
id: ID,
|
|
66
|
+
fieldId: ID,
|
|
67
|
+
type: _models.ComponentTypes.COLLECTION,
|
|
68
|
+
item: [TEXT_COMPONENT]
|
|
69
|
+
};
|
|
70
|
+
_renderWithValidation = (0, _setupTests.renderWithValidation)( /*#__PURE__*/_react2.default.createElement(_FormComponent.default, {
|
|
71
|
+
component: COLLECTION,
|
|
72
|
+
value: FORM_DATA[ID],
|
|
73
|
+
formData: FORM_DATA
|
|
74
|
+
})), container = _renderWithValidation.container; // Check the container itself.
|
|
75
|
+
|
|
76
|
+
c = container.childNodes[0];
|
|
77
|
+
expect(c.tagName).toEqual('DIV');
|
|
78
|
+
expect(c.classList).toContain(_Collection.DEFAULT_CLASS); // And now check the single text component within it.
|
|
79
|
+
|
|
80
|
+
item = c.childNodes[0];
|
|
81
|
+
expect(item.tagName).toEqual('DIV');
|
|
82
|
+
expect(item.classList).toContain("".concat(_Collection.DEFAULT_CLASS, "__item"));
|
|
83
|
+
_item$childNodes = _slicedToArray(item.childNodes, 2), title = _item$childNodes[0], itemContainer = _item$childNodes[1];
|
|
84
|
+
expect(title.tagName).toEqual('LABEL');
|
|
85
|
+
expect(title.classList).toContain("".concat(_Collection.DEFAULT_CLASS, "__item-title"));
|
|
86
|
+
expect(itemContainer.tagName).toEqual('DIV');
|
|
87
|
+
expect(itemContainer.classList).toContain(_Container.DEFAULT_CLASS);
|
|
88
|
+
formGroup = itemContainer.childNodes[0];
|
|
89
|
+
expect(formGroup.tagName).toEqual('DIV');
|
|
90
|
+
expect(formGroup.classList).toContain('govuk-form-group');
|
|
91
|
+
label = formGroup.childNodes[0];
|
|
92
|
+
expect(label.tagName).toEqual('LABEL');
|
|
93
|
+
expect(label.classList).toContain('govuk-label');
|
|
94
|
+
expect(label.textContent).toEqual("".concat(TEXT_COMPONENT.label, " (optional)"));
|
|
95
|
+
expect(label.getAttribute('for')).toEqual("".concat(ID, "[0].").concat(TEXT_ID));
|
|
96
|
+
hint = formGroup.childNodes[1];
|
|
97
|
+
expect(hint.tagName).toEqual('SPAN');
|
|
98
|
+
expect(hint.classList).toContain('govuk-hint');
|
|
99
|
+
expect(hint.textContent).toEqual(TEXT_COMPONENT.hint);
|
|
100
|
+
input = formGroup.childNodes[2];
|
|
101
|
+
expect(input.tagName).toEqual('INPUT');
|
|
102
|
+
expect(input.classList).toContain('govuk-input');
|
|
103
|
+
expect(input.id).toEqual("".concat(ID, "[0].").concat(TEXT_ID));
|
|
104
|
+
expect(input.value).toEqual(TEXT_VALUE);
|
|
105
|
+
|
|
106
|
+
case 30:
|
|
107
|
+
case "end":
|
|
108
|
+
return _context.stop();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}, _callee);
|
|
112
|
+
})));
|
|
113
|
+
it('should handle a change to a component appropriately', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
|
|
114
|
+
var ON_CHANGE_EVENTS, ON_CHANGE, COLLECTION, _renderWithValidation2, container, c, item, formGroup, input, NEW_TEXT_VALUE, EVENT;
|
|
115
|
+
|
|
116
|
+
return regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
117
|
+
while (1) {
|
|
118
|
+
switch (_context2.prev = _context2.next) {
|
|
119
|
+
case 0:
|
|
120
|
+
ON_CHANGE_EVENTS = [];
|
|
121
|
+
|
|
122
|
+
ON_CHANGE = function ON_CHANGE(e) {
|
|
123
|
+
ON_CHANGE_EVENTS.push(e);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
COLLECTION = {
|
|
127
|
+
id: ID,
|
|
128
|
+
fieldId: ID,
|
|
129
|
+
type: _models.ComponentTypes.COLLECTION,
|
|
130
|
+
item: [{
|
|
131
|
+
id: TEXT_ID,
|
|
132
|
+
fieldId: TEXT_ID,
|
|
133
|
+
type: _models.ComponentTypes.TEXT,
|
|
134
|
+
label: 'Text component'
|
|
135
|
+
}]
|
|
136
|
+
};
|
|
137
|
+
_renderWithValidation2 = (0, _setupTests.renderWithValidation)( /*#__PURE__*/_react2.default.createElement(_FormComponent.default, {
|
|
138
|
+
component: COLLECTION,
|
|
139
|
+
value: FORM_DATA[ID],
|
|
140
|
+
formData: FORM_DATA,
|
|
141
|
+
onChange: ON_CHANGE
|
|
142
|
+
})), container = _renderWithValidation2.container; // Get hold of the text input.
|
|
143
|
+
|
|
144
|
+
c = container.childNodes[0];
|
|
145
|
+
item = c.childNodes[0];
|
|
146
|
+
formGroup = item.childNodes[1].childNodes[0];
|
|
147
|
+
input = formGroup.childNodes[2];
|
|
148
|
+
NEW_TEXT_VALUE = 'bravo';
|
|
149
|
+
EVENT = {
|
|
150
|
+
target: {
|
|
151
|
+
name: TEXT_ID,
|
|
152
|
+
value: NEW_TEXT_VALUE
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
_react.fireEvent.change(input, EVENT); // And confirm the formData has been changed.
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
expect(ON_CHANGE_EVENTS.length).toEqual(1);
|
|
160
|
+
expect(ON_CHANGE_EVENTS[0].target.name).toEqual(ID);
|
|
161
|
+
expect(ON_CHANGE_EVENTS[0].target.value[0][TEXT_ID]).toEqual(NEW_TEXT_VALUE);
|
|
162
|
+
|
|
163
|
+
case 14:
|
|
164
|
+
case "end":
|
|
165
|
+
return _context2.stop();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}, _callee2);
|
|
169
|
+
})));
|
|
170
|
+
it('should handle a null value appropriately', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {
|
|
171
|
+
var COLLECTION, _renderWithValidation3, container, c, buttonGroup, button;
|
|
172
|
+
|
|
173
|
+
return regeneratorRuntime.wrap(function _callee3$(_context3) {
|
|
174
|
+
while (1) {
|
|
175
|
+
switch (_context3.prev = _context3.next) {
|
|
176
|
+
case 0:
|
|
177
|
+
COLLECTION = {
|
|
178
|
+
id: ID,
|
|
179
|
+
fieldId: ID,
|
|
180
|
+
type: _models.ComponentTypes.COLLECTION,
|
|
181
|
+
item: [TEXT_COMPONENT]
|
|
182
|
+
};
|
|
183
|
+
_renderWithValidation3 = (0, _setupTests.renderWithValidation)( /*#__PURE__*/_react2.default.createElement(_FormComponent.default, {
|
|
184
|
+
component: COLLECTION
|
|
185
|
+
})), container = _renderWithValidation3.container; // Check the container itself.
|
|
186
|
+
|
|
187
|
+
c = container.childNodes[0];
|
|
188
|
+
expect(c.tagName).toEqual('DIV');
|
|
189
|
+
expect(c.classList).toContain(_Collection.DEFAULT_CLASS); // And now make sure it has no children OTHER than the button to add an item.
|
|
190
|
+
|
|
191
|
+
expect(c.childNodes.length).toEqual(1);
|
|
192
|
+
buttonGroup = c.childNodes[0];
|
|
193
|
+
expect(buttonGroup.tagName).toEqual('DIV');
|
|
194
|
+
expect(buttonGroup.classList).toContain('hods-button-group');
|
|
195
|
+
button = buttonGroup.childNodes[0];
|
|
196
|
+
expect(button.tagName).toEqual('BUTTON');
|
|
197
|
+
expect(button.classList).toContain('hods-button');
|
|
198
|
+
expect(button.classList).toContain('hods-button--secondary');
|
|
199
|
+
expect(button.textContent).toContain(_models.CollectionLabels.add);
|
|
200
|
+
|
|
201
|
+
case 14:
|
|
202
|
+
case "end":
|
|
203
|
+
return _context3.stop();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}, _callee3);
|
|
207
|
+
})));
|
|
208
|
+
it('should handle a collection label appropriately', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {
|
|
209
|
+
var LABEL, COLLECTION, _renderWithValidation4, container, c, _c$childNodes, title, buttonGroup, button;
|
|
210
|
+
|
|
211
|
+
return regeneratorRuntime.wrap(function _callee4$(_context4) {
|
|
212
|
+
while (1) {
|
|
213
|
+
switch (_context4.prev = _context4.next) {
|
|
214
|
+
case 0:
|
|
215
|
+
LABEL = 'Alpha Collection';
|
|
216
|
+
COLLECTION = {
|
|
217
|
+
id: ID,
|
|
218
|
+
fieldId: ID,
|
|
219
|
+
type: _models.ComponentTypes.COLLECTION,
|
|
220
|
+
item: [TEXT_COMPONENT],
|
|
221
|
+
label: LABEL
|
|
222
|
+
};
|
|
223
|
+
_renderWithValidation4 = (0, _setupTests.renderWithValidation)( /*#__PURE__*/_react2.default.createElement(_FormComponent.default, {
|
|
224
|
+
component: COLLECTION
|
|
225
|
+
})), container = _renderWithValidation4.container; // Check the container itself.
|
|
226
|
+
|
|
227
|
+
c = container.childNodes[0];
|
|
228
|
+
expect(c.tagName).toEqual('DIV');
|
|
229
|
+
expect(c.classList).toContain(_Collection.DEFAULT_CLASS); // And now make sure it has no children OTHER than the button to add an item.
|
|
230
|
+
|
|
231
|
+
expect(c.childNodes.length).toEqual(2);
|
|
232
|
+
_c$childNodes = _slicedToArray(c.childNodes, 2), title = _c$childNodes[0], buttonGroup = _c$childNodes[1];
|
|
233
|
+
expect(title.tagName).toEqual('LABEL');
|
|
234
|
+
expect(title.classList).toContain("".concat(_Collection.DEFAULT_CLASS, "__title"));
|
|
235
|
+
expect(title.getAttribute('for')).toEqual(ID);
|
|
236
|
+
expect(title.textContent).toContain(LABEL);
|
|
237
|
+
expect(buttonGroup.tagName).toEqual('DIV');
|
|
238
|
+
expect(buttonGroup.classList).toContain('hods-button-group');
|
|
239
|
+
button = buttonGroup.childNodes[0];
|
|
240
|
+
expect(button.tagName).toEqual('BUTTON');
|
|
241
|
+
expect(button.classList).toContain('hods-button');
|
|
242
|
+
expect(button.classList).toContain('hods-button--secondary');
|
|
243
|
+
expect(button.textContent).toContain(_models.CollectionLabels.add);
|
|
244
|
+
|
|
245
|
+
case 19:
|
|
246
|
+
case "end":
|
|
247
|
+
return _context4.stop();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}, _callee4);
|
|
251
|
+
})));
|
|
252
|
+
it('should handle the addition and removal of an item', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee6() {
|
|
253
|
+
var COLLECTION, container, c, addButton, item, label, removeButton;
|
|
254
|
+
return regeneratorRuntime.wrap(function _callee6$(_context6) {
|
|
255
|
+
while (1) {
|
|
256
|
+
switch (_context6.prev = _context6.next) {
|
|
257
|
+
case 0:
|
|
258
|
+
COLLECTION = {
|
|
259
|
+
id: ID,
|
|
260
|
+
fieldId: ID,
|
|
261
|
+
type: _models.ComponentTypes.COLLECTION,
|
|
262
|
+
item: [TEXT_COMPONENT]
|
|
263
|
+
};
|
|
264
|
+
container = document.createElement('div');
|
|
265
|
+
document.body.appendChild(container);
|
|
266
|
+
_context6.next = 5;
|
|
267
|
+
return (0, _testUtils.act)( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5() {
|
|
268
|
+
return regeneratorRuntime.wrap(function _callee5$(_context5) {
|
|
269
|
+
while (1) {
|
|
270
|
+
switch (_context5.prev = _context5.next) {
|
|
271
|
+
case 0:
|
|
272
|
+
(0, _setupTests.renderDomWithValidation)( /*#__PURE__*/_react2.default.createElement(_FormComponent.default, {
|
|
273
|
+
component: COLLECTION
|
|
274
|
+
}), container);
|
|
275
|
+
|
|
276
|
+
case 1:
|
|
277
|
+
case "end":
|
|
278
|
+
return _context5.stop();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}, _callee5);
|
|
282
|
+
})));
|
|
283
|
+
|
|
284
|
+
case 5:
|
|
285
|
+
// Check the container itself.
|
|
286
|
+
c = container.childNodes[0];
|
|
287
|
+
expect(c.tagName).toEqual('DIV');
|
|
288
|
+
expect(c.classList).toContain(_Collection.DEFAULT_CLASS); // And now make sure it has no children OTHER than the button to add an item.
|
|
289
|
+
|
|
290
|
+
expect(c.childNodes.length).toEqual(1); // Get hold of that "Add another" button and click it.
|
|
291
|
+
|
|
292
|
+
addButton = c.childNodes[0].childNodes[0];
|
|
293
|
+
|
|
294
|
+
_react.fireEvent.click(addButton, {}); // Make sure an item has been added.
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
expect(c.childNodes.length).toEqual(2);
|
|
298
|
+
item = c.childNodes[0];
|
|
299
|
+
label = item.childNodes[0];
|
|
300
|
+
expect(label.textContent).toContain(_utils.default.interpolateString(_models.CollectionLabels.item, {
|
|
301
|
+
index: 1
|
|
302
|
+
})); // Get hold of the newly-add item's "Remove" button.
|
|
303
|
+
|
|
304
|
+
removeButton = label.childNodes[1];
|
|
305
|
+
expect(removeButton.tagName).toEqual('BUTTON');
|
|
306
|
+
expect(removeButton.classList).toContain('hods-button--secondary');
|
|
307
|
+
expect(removeButton.textContent).toContain(_models.CollectionLabels.remove); // Click the "Remove" button
|
|
308
|
+
|
|
309
|
+
_react.fireEvent.click(removeButton, {}); // Make sure the item has been removed.
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
expect(c.childNodes.length).toEqual(1);
|
|
313
|
+
expect(c.childNodes[0].classList).toContain('hods-button-group');
|
|
314
|
+
|
|
315
|
+
case 22:
|
|
316
|
+
case "end":
|
|
317
|
+
return _context6.stop();
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}, _callee6);
|
|
321
|
+
})));
|
|
322
|
+
});
|
|
@@ -247,6 +247,8 @@ var InternalFormRenderer = function InternalFormRenderer(_ref2) {
|
|
|
247
247
|
// Check to see whether the action is able to proceed, which in
|
|
248
248
|
// in the case of a submission will validate the fields in the page.
|
|
249
249
|
if (_helpers.default.canActionProceed(action, formState.page, validate.page)) {
|
|
250
|
+
patch = _helpers.default.cleanHiddenNestedData(patch, formState.page);
|
|
251
|
+
|
|
250
252
|
if (action.type === _models.PageAction.TYPES.NAVIGATE) {
|
|
251
253
|
_handlers.default.navigate(action, pageId, onPageChange);
|
|
252
254
|
} else {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var parentComponents = ['radios'];
|
|
8
|
+
|
|
9
|
+
var cleanHiddenNestedData = function cleanHiddenNestedData(patch, page) {
|
|
10
|
+
page.components.forEach(function (component) {
|
|
11
|
+
if (!parentComponents.includes(component.type)) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
var idsToDelete = getIdsToDelete(component, patch[component.id]);
|
|
16
|
+
idsToDelete.forEach(function (id) {
|
|
17
|
+
delete patch[id];
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
return patch;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function getIdsToDelete(component, selectedValue) {
|
|
24
|
+
var _component$data, _component$data$optio;
|
|
25
|
+
|
|
26
|
+
var idsToDelete = [];
|
|
27
|
+
component === null || component === void 0 ? void 0 : (_component$data = component.data) === null || _component$data === void 0 ? void 0 : (_component$data$optio = _component$data.options) === null || _component$data$optio === void 0 ? void 0 : _component$data$optio.forEach(function (option) {
|
|
28
|
+
if (option.value !== selectedValue && option.nested) {
|
|
29
|
+
option.nested.forEach(function (nested) {
|
|
30
|
+
idsToDelete.push(nested.id);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return idsToDelete;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var _default = cleanHiddenNestedData;
|
|
38
|
+
exports.default = _default;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _cleanHiddenNestedData = _interopRequireDefault(require("./cleanHiddenNestedData"));
|
|
4
|
+
|
|
5
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
6
|
+
|
|
7
|
+
// Local imports
|
|
8
|
+
describe('components', function () {
|
|
9
|
+
describe('FormRenderer', function () {
|
|
10
|
+
describe('helpers', function () {
|
|
11
|
+
describe('cleanHiddenNestedData', function () {
|
|
12
|
+
it('remove data corresponding to hidden nested components', function () {
|
|
13
|
+
var patch = {
|
|
14
|
+
parent: 'option2',
|
|
15
|
+
nested1: 'should not be included',
|
|
16
|
+
nested2: 'should be included'
|
|
17
|
+
};
|
|
18
|
+
var page = {
|
|
19
|
+
id: 'page',
|
|
20
|
+
name: 'page',
|
|
21
|
+
title: 'Page',
|
|
22
|
+
components: [{
|
|
23
|
+
id: 'parent',
|
|
24
|
+
fieldId: 'parent',
|
|
25
|
+
type: 'radios',
|
|
26
|
+
data: {
|
|
27
|
+
options: [{
|
|
28
|
+
value: 'option1',
|
|
29
|
+
nested: [{
|
|
30
|
+
id: 'nested1',
|
|
31
|
+
fieldId: 'nested1'
|
|
32
|
+
}]
|
|
33
|
+
}, {
|
|
34
|
+
value: 'option2',
|
|
35
|
+
nested: [{
|
|
36
|
+
id: 'nested2',
|
|
37
|
+
fieldId: 'nested2'
|
|
38
|
+
}]
|
|
39
|
+
}]
|
|
40
|
+
}
|
|
41
|
+
}]
|
|
42
|
+
};
|
|
43
|
+
var updatedPatch = (0, _cleanHiddenNestedData.default)(patch, page);
|
|
44
|
+
expect(updatedPatch['nested1']).toBeFalsy();
|
|
45
|
+
expect(updatedPatch['nested2']).toBeTruthy();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -9,6 +9,8 @@ var _canActionProceed = _interopRequireDefault(require("./canActionProceed"));
|
|
|
9
9
|
|
|
10
10
|
var _canCYASubmit = _interopRequireDefault(require("./canCYASubmit"));
|
|
11
11
|
|
|
12
|
+
var _cleanHiddenNestedData = _interopRequireDefault(require("./cleanHiddenNestedData"));
|
|
13
|
+
|
|
12
14
|
var _getFormState = _interopRequireDefault(require("./getFormState"));
|
|
13
15
|
|
|
14
16
|
var _getNextPageId = _interopRequireDefault(require("./getNextPageId"));
|
|
@@ -25,6 +27,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
25
27
|
var helpers = {
|
|
26
28
|
canActionProceed: _canActionProceed.default,
|
|
27
29
|
canCYASubmit: _canCYASubmit.default,
|
|
30
|
+
cleanHiddenNestedData: _cleanHiddenNestedData.default,
|
|
28
31
|
getFormState: _getFormState.default,
|
|
29
32
|
getNextPageId: _getNextPageId.default,
|
|
30
33
|
getPage: _getPage.default,
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
4
|
+
|
|
3
5
|
Object.defineProperty(exports, "__esModule", {
|
|
4
6
|
value: true
|
|
5
7
|
});
|
|
6
8
|
exports.default = exports.HooksContext = exports.ALLOWED_HOOKS = void 0;
|
|
7
9
|
|
|
8
|
-
var _react = require("react");
|
|
10
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
11
|
+
|
|
12
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
13
|
+
|
|
14
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
9
15
|
|
|
10
16
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
|
|
11
17
|
|
|
@@ -78,7 +84,7 @@ var HooksContextProvider = function HooksContextProvider(_ref) {
|
|
|
78
84
|
}
|
|
79
85
|
};
|
|
80
86
|
|
|
81
|
-
return /*#__PURE__*/
|
|
87
|
+
return /*#__PURE__*/_react.default.createElement(HooksContext.Provider, {
|
|
82
88
|
value: {
|
|
83
89
|
hooks: hooks,
|
|
84
90
|
addHook: addHook,
|
|
@@ -49,7 +49,9 @@ var setNestedValue = function setNestedValue(component, page) {
|
|
|
49
49
|
(_component$data = component.data) === null || _component$data === void 0 ? void 0 : (_component$data$optio = _component$data.options) === null || _component$data$optio === void 0 ? void 0 : _component$data$optio.forEach(function (option, index) {
|
|
50
50
|
//check if option is selected and has nested component
|
|
51
51
|
if (page.formData[component.id] === option.value && option.nested) {
|
|
52
|
-
|
|
52
|
+
option.nested.forEach(function (child) {
|
|
53
|
+
child.value = page.formData[child.id];
|
|
54
|
+
});
|
|
53
55
|
}
|
|
54
56
|
});
|
|
55
57
|
};
|
|
@@ -162,14 +162,14 @@ describe('utils', function () {
|
|
|
162
162
|
data: {
|
|
163
163
|
options: [{
|
|
164
164
|
value: SELECTED_VALUE,
|
|
165
|
-
nested: {
|
|
165
|
+
nested: [{
|
|
166
166
|
id: NESTED_ID
|
|
167
|
-
}
|
|
167
|
+
}]
|
|
168
168
|
}]
|
|
169
169
|
}
|
|
170
170
|
};
|
|
171
171
|
var ROW = (0, _getCYARow.default)(PAGE, COMPONENT, function () {});
|
|
172
|
-
expect(ROW.component.data.options[0].nested.value).toEqual(NESTED_VALUE);
|
|
172
|
+
expect(ROW.component.data.options[0].nested[0].value).toEqual(NESTED_VALUE);
|
|
173
173
|
});
|
|
174
174
|
});
|
|
175
175
|
});
|
|
@@ -19,7 +19,7 @@ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToAr
|
|
|
19
19
|
|
|
20
20
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
21
21
|
|
|
22
|
-
var JSON_ONLY_PROPERTIES = ['source', 'use', 'show_when', 'options', 'additionalValidation', 'full_path', '
|
|
22
|
+
var JSON_ONLY_PROPERTIES = ['source', 'use', 'show_when', 'options', 'additionalValidation', 'full_path', 'formData'];
|
|
23
23
|
/**
|
|
24
24
|
* This method removes and properties that are entirely specific to the JSON
|
|
25
25
|
* configuration and that should not be used as HTML attributes.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.getChildrenJsx = exports.default = void 0;
|
|
7
7
|
|
|
8
8
|
var _copReactComponents = require("@ukhomeoffice/cop-react-components");
|
|
9
9
|
|
|
@@ -17,6 +17,8 @@ var _cleanAttributes = _interopRequireDefault(require("./cleanAttributes"));
|
|
|
17
17
|
|
|
18
18
|
var _isEditable = _interopRequireDefault(require("./isEditable"));
|
|
19
19
|
|
|
20
|
+
var _FormComponent = _interopRequireDefault(require("../../components/FormComponent"));
|
|
21
|
+
|
|
20
22
|
var _wrapInFormGroup = _interopRequireDefault(require("./wrapInFormGroup"));
|
|
21
23
|
|
|
22
24
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -85,11 +87,11 @@ var getRadios = function getRadios(config) {
|
|
|
85
87
|
});
|
|
86
88
|
|
|
87
89
|
options.forEach(function (option) {
|
|
88
|
-
if (!option.nested) {
|
|
90
|
+
if (!Array.isArray(option.nested)) {
|
|
89
91
|
return;
|
|
90
92
|
}
|
|
91
93
|
|
|
92
|
-
option.
|
|
94
|
+
option.children = getChildrenJsx(config, option.nested);
|
|
93
95
|
});
|
|
94
96
|
var attrs = (0, _cleanAttributes.default)(config);
|
|
95
97
|
return /*#__PURE__*/_react.default.createElement(_copReactComponents.Radios, _extends({}, attrs, {
|
|
@@ -156,32 +158,49 @@ var getComponentByType = function getComponentByType(config) {
|
|
|
156
158
|
}
|
|
157
159
|
};
|
|
158
160
|
/**
|
|
159
|
-
* Get
|
|
160
|
-
* @param {*}
|
|
161
|
-
* @param {*}
|
|
161
|
+
* Get single child component for a parent
|
|
162
|
+
* @param {*} parent the parent configuration
|
|
163
|
+
* @param {*} child the child configuration
|
|
162
164
|
*/
|
|
163
165
|
|
|
164
166
|
|
|
165
|
-
var
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if (parentConfig.formData) {
|
|
169
|
-
var _parentConfig$formDat;
|
|
167
|
+
var getChildJsx = function getChildJsx(parent, child) {
|
|
168
|
+
if (parent.formData) {
|
|
169
|
+
var _parent$formData;
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
child.value = parent !== null && parent !== void 0 && (_parent$formData = parent.formData) !== null && _parent$formData !== void 0 && _parent$formData[child.fieldId] ? parent.formData[child.fieldId] : '';
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
if ('readonly' in
|
|
174
|
+
if ('readonly' in child) delete child.readonly;
|
|
175
175
|
|
|
176
|
-
if (
|
|
177
|
-
|
|
178
|
-
return getComponent(
|
|
176
|
+
if (parent.readonly) {
|
|
177
|
+
child.readonly = parent.readonly;
|
|
178
|
+
return /*#__PURE__*/_react.default.createElement("div", null, getComponent(child, false));
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
return
|
|
181
|
+
return /*#__PURE__*/_react.default.createElement(_FormComponent.default, {
|
|
182
|
+
component: child,
|
|
183
|
+
value: child.value,
|
|
184
|
+
onChange: parent.onChange,
|
|
185
|
+
key: child.key
|
|
186
|
+
});
|
|
187
|
+
};
|
|
188
|
+
/**
|
|
189
|
+
* Convert chidlrenConfigs into components
|
|
190
|
+
* @param {*} parentConfig parent component which the childrenConfigs will be under
|
|
191
|
+
* @param {*} childrenConfigs array of configurations for the child components
|
|
192
|
+
*/
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
var getChildrenJsx = function getChildrenJsx(parentConfig, childrenConfigs) {
|
|
196
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, childrenConfigs.map(function (config) {
|
|
197
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, {
|
|
198
|
+
key: config.id
|
|
199
|
+
}, getChildJsx(parentConfig, config));
|
|
200
|
+
}));
|
|
182
201
|
};
|
|
183
202
|
|
|
184
|
-
exports.
|
|
203
|
+
exports.getChildrenJsx = getChildrenJsx;
|
|
185
204
|
|
|
186
205
|
/**
|
|
187
206
|
* Get a renderable component, based on a configuration object.
|
|
@@ -4,6 +4,8 @@ var _react = require("@testing-library/react");
|
|
|
4
4
|
|
|
5
5
|
var _getComponent = require("../getComponent");
|
|
6
6
|
|
|
7
|
+
var _setupTests = require("../../../setupTests");
|
|
8
|
+
|
|
7
9
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
8
10
|
|
|
9
11
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
@@ -11,8 +13,10 @@ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try
|
|
|
11
13
|
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
12
14
|
|
|
13
15
|
describe('utils.Component.get', function () {
|
|
14
|
-
it('should return
|
|
15
|
-
var
|
|
16
|
+
it('should return components that are nested within another component', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
|
|
17
|
+
var _formData;
|
|
18
|
+
|
|
19
|
+
var ID, FIELD_ID, LABEL, ID2, FIELD_ID2, LABEL2, VALUE, VALUE2, PARENT_CONFIG, NESTED_CONFIG, _renderWithValidation, container, child, label, input, child2, label2, input2;
|
|
16
20
|
|
|
17
21
|
return regeneratorRuntime.wrap(function _callee$(_context) {
|
|
18
22
|
while (1) {
|
|
@@ -21,32 +25,53 @@ describe('utils.Component.get', function () {
|
|
|
21
25
|
ID = 'testId';
|
|
22
26
|
FIELD_ID = 'fieldId';
|
|
23
27
|
LABEL = 'Test label';
|
|
28
|
+
ID2 = 'testId2';
|
|
29
|
+
FIELD_ID2 = 'fieldId2';
|
|
30
|
+
LABEL2 = 'Test label 2';
|
|
24
31
|
VALUE = 'nestedValue';
|
|
32
|
+
VALUE2 = '1-2-2022';
|
|
25
33
|
PARENT_CONFIG = {
|
|
26
34
|
onChange: function onChange() {},
|
|
27
|
-
formData:
|
|
28
|
-
};
|
|
29
|
-
NESTED_CONFIG = {
|
|
30
|
-
nested: {
|
|
31
|
-
id: ID,
|
|
32
|
-
fieldId: FIELD_ID,
|
|
33
|
-
label: LABEL,
|
|
34
|
-
type: 'text'
|
|
35
|
-
}
|
|
35
|
+
formData: (_formData = {}, _defineProperty(_formData, FIELD_ID, VALUE), _defineProperty(_formData, FIELD_ID2, VALUE2), _formData)
|
|
36
36
|
};
|
|
37
|
-
|
|
37
|
+
NESTED_CONFIG = [{
|
|
38
|
+
id: ID,
|
|
39
|
+
fieldId: FIELD_ID,
|
|
40
|
+
label: LABEL,
|
|
41
|
+
type: 'text'
|
|
42
|
+
}, {
|
|
43
|
+
id: ID2,
|
|
44
|
+
fieldId: FIELD_ID2,
|
|
45
|
+
label: LABEL2,
|
|
46
|
+
type: 'date'
|
|
47
|
+
}];
|
|
48
|
+
_renderWithValidation = (0, _setupTests.renderWithValidation)((0, _getComponent.getChildrenJsx)(PARENT_CONFIG, NESTED_CONFIG)), container = _renderWithValidation.container;
|
|
38
49
|
child = container.childNodes[0];
|
|
50
|
+
expect(child.childNodes.length).toEqual(3);
|
|
39
51
|
expect(child.classList).toContain('govuk-form-group');
|
|
40
52
|
label = child.childNodes[0];
|
|
41
53
|
expect(label).toBeDefined();
|
|
42
54
|
expect(label.innerHTML).toContain(LABEL);
|
|
43
|
-
input = child.childNodes[
|
|
55
|
+
input = child.childNodes[2];
|
|
44
56
|
expect(input.tagName).toEqual('INPUT');
|
|
45
57
|
expect(input.classList).toContain('govuk-input');
|
|
46
58
|
expect(input.id).toEqual(ID);
|
|
47
59
|
expect(input.value).toEqual(VALUE);
|
|
60
|
+
child2 = container.childNodes[1];
|
|
61
|
+
expect(child2.childNodes.length).toEqual(3);
|
|
62
|
+
expect(child2.classList).toContain('govuk-form-group');
|
|
63
|
+
label2 = child2.childNodes[0];
|
|
64
|
+
expect(label2).toBeDefined();
|
|
65
|
+
expect(label2.innerHTML).toContain(LABEL2);
|
|
66
|
+
input2 = child2.childNodes[2];
|
|
67
|
+
expect(input2.tagName).toEqual('DIV');
|
|
68
|
+
expect(input2.classList).toContain('govuk-date-input');
|
|
69
|
+
expect(input2.id).toEqual(ID2);
|
|
70
|
+
expect(input2.childNodes[0].childNodes[1].value).toEqual('1');
|
|
71
|
+
expect(input2.childNodes[1].childNodes[1].value).toEqual('2');
|
|
72
|
+
expect(input2.childNodes[2].childNodes[1].value).toEqual('2022');
|
|
48
73
|
|
|
49
|
-
case
|
|
74
|
+
case 35:
|
|
50
75
|
case "end":
|
|
51
76
|
return _context.stop();
|
|
52
77
|
}
|
|
@@ -54,7 +79,7 @@ describe('utils.Component.get', function () {
|
|
|
54
79
|
}, _callee);
|
|
55
80
|
})));
|
|
56
81
|
it('should return a read only component that is nested within another readonly component', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
|
|
57
|
-
var ID, FIELD_ID, LABEL, VALUE, PARENT_CONFIG, NESTED_CONFIG,
|
|
82
|
+
var ID, FIELD_ID, LABEL, VALUE, PARENT_CONFIG, NESTED_CONFIG, _render, container, child;
|
|
58
83
|
|
|
59
84
|
return regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
60
85
|
while (1) {
|
|
@@ -69,17 +94,15 @@ describe('utils.Component.get', function () {
|
|
|
69
94
|
formData: _defineProperty({}, FIELD_ID, VALUE),
|
|
70
95
|
readonly: true
|
|
71
96
|
};
|
|
72
|
-
NESTED_CONFIG = {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
_render2 = (0, _react.render)((0, _getComponent.getNestedComponent)(PARENT_CONFIG, NESTED_CONFIG)), container = _render2.container;
|
|
82
|
-
child = container.childNodes[0];
|
|
97
|
+
NESTED_CONFIG = [{
|
|
98
|
+
id: ID,
|
|
99
|
+
fieldId: FIELD_ID,
|
|
100
|
+
label: LABEL,
|
|
101
|
+
type: 'text',
|
|
102
|
+
readonly: true
|
|
103
|
+
}];
|
|
104
|
+
_render = (0, _react.render)((0, _getComponent.getChildrenJsx)(PARENT_CONFIG, NESTED_CONFIG)), container = _render.container;
|
|
105
|
+
child = container.childNodes[0].childNodes[0];
|
|
83
106
|
expect(child.classList).toContain('hods-readonly');
|
|
84
107
|
|
|
85
108
|
case 9:
|
|
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
|
|
8
|
+
var _copReactComponents = require("@ukhomeoffice/cop-react-components");
|
|
9
|
+
|
|
8
10
|
var _Container = _interopRequireDefault(require("../Container"));
|
|
9
11
|
|
|
10
12
|
var _Data = _interopRequireDefault(require("../Data"));
|
|
@@ -35,6 +37,8 @@ var getFormPage = function getFormPage(pageOptions, formComponents, formData) {
|
|
|
35
37
|
return null;
|
|
36
38
|
}
|
|
37
39
|
|
|
40
|
+
pageOptions = interpolatePageOptions(pageOptions, formData);
|
|
41
|
+
formComponents = interpolateFormComponents(formComponents, formData);
|
|
38
42
|
var components = pageOptions.components.map(function (componentOptions) {
|
|
39
43
|
if (typeof componentOptions === 'string') {
|
|
40
44
|
return (0, _getParagraphFromText.default)(componentOptions);
|
|
@@ -57,6 +61,42 @@ var getFormPage = function getFormPage(pageOptions, formComponents, formData) {
|
|
|
57
61
|
actions: actions
|
|
58
62
|
}));
|
|
59
63
|
};
|
|
64
|
+
/**
|
|
65
|
+
* Interpolate 'Variable Expression' using formData - for local use only.
|
|
66
|
+
* @param {object} pageOptions The JSON page.
|
|
67
|
+
* @param {object} formData The top-level form data, used for setting up components.
|
|
68
|
+
* @returns interpolated pageOptions.
|
|
69
|
+
*/
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
var interpolatePageOptions = function interpolatePageOptions(pageOptions, formData) {
|
|
73
|
+
return JSON.parse(_copReactComponents.Utils.interpolateString(JSON.stringify(pageOptions), formData));
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Interpolate 'Variable Expression' using formData excluding each component's data block - for local use only.
|
|
77
|
+
* @param {Array} formComponents The components defined at the top-level of the form.
|
|
78
|
+
* @param {object} formData The top-level form data, used for setting up components.
|
|
79
|
+
* @returns interpolated formComponents
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
var interpolateFormComponents = function interpolateFormComponents(formComponents, formData) {
|
|
84
|
+
return formComponents.map(function (formComponent) {
|
|
85
|
+
var formComponentDataUrl = undefined;
|
|
86
|
+
|
|
87
|
+
if (formComponent.data && formComponent.data.url) {
|
|
88
|
+
formComponentDataUrl = formComponent.data.url;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
var interpolatedFormComponent = JSON.parse(_copReactComponents.Utils.interpolateString(JSON.stringify(formComponent), formData));
|
|
92
|
+
|
|
93
|
+
if (formComponentDataUrl) {
|
|
94
|
+
interpolatedFormComponent.data.url = formComponentDataUrl;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return interpolatedFormComponent;
|
|
98
|
+
});
|
|
99
|
+
};
|
|
60
100
|
|
|
61
101
|
var _default = getFormPage;
|
|
62
102
|
exports.default = _default;
|
|
@@ -32,6 +32,18 @@ describe('utils', function () {
|
|
|
32
32
|
data: {
|
|
33
33
|
url: '${urls.refData}/v3/charlies'
|
|
34
34
|
}
|
|
35
|
+
}, // eslint-disable-next-line no-template-curly-in-string
|
|
36
|
+
{
|
|
37
|
+
id: 'd',
|
|
38
|
+
fieldId: 'd',
|
|
39
|
+
label: 'Roger ${currentUser.firstname}',
|
|
40
|
+
type: 'text'
|
|
41
|
+
}, // eslint-disable-next-line no-template-curly-in-string
|
|
42
|
+
{
|
|
43
|
+
id: 'e',
|
|
44
|
+
fieldId: 'e',
|
|
45
|
+
label: 'Bravo ${currentUser.surname}',
|
|
46
|
+
type: 'text'
|
|
35
47
|
}];
|
|
36
48
|
var FORM_DATA = {
|
|
37
49
|
urls: {
|
|
@@ -165,6 +177,59 @@ describe('utils', function () {
|
|
|
165
177
|
var C = FORM_COMPONENTS[2];
|
|
166
178
|
expect((0, _getFormPage.default)(PAGE, FORM_COMPONENTS, {})).toEqual({
|
|
167
179
|
title: PAGE.title,
|
|
180
|
+
components: [{
|
|
181
|
+
type: 'html',
|
|
182
|
+
tagName: 'p',
|
|
183
|
+
content: PAGE.components[0]
|
|
184
|
+
}, _objectSpread(_objectSpread({}, PAGE.components[1]), {}, {
|
|
185
|
+
full_path: PAGE.components[1].fieldId
|
|
186
|
+
}), {
|
|
187
|
+
type: 'html',
|
|
188
|
+
tagName: 'p',
|
|
189
|
+
content: PAGE.components[2]
|
|
190
|
+
}, // eslint-disable-next-line no-template-curly-in-string
|
|
191
|
+
_objectSpread(_objectSpread({
|
|
192
|
+
use: 'c'
|
|
193
|
+
}, C), {}, {
|
|
194
|
+
cya_label: C.label,
|
|
195
|
+
full_path: C.fieldId,
|
|
196
|
+
data: {
|
|
197
|
+
url: '${urls.refData}/v3/charlies'
|
|
198
|
+
}
|
|
199
|
+
})],
|
|
200
|
+
formData: {}
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
it('should interpolate and handle a page that references a form-level component with formData', function () {
|
|
204
|
+
var PAGE = {
|
|
205
|
+
// eslint-disable-next-line no-template-curly-in-string
|
|
206
|
+
title: 'Page ${postFixTitle}',
|
|
207
|
+
components: ["Opening paragraph", {
|
|
208
|
+
type: 'heading',
|
|
209
|
+
size: 'l',
|
|
210
|
+
content: 'Page heading'
|
|
211
|
+
}, "Closing paragraph", {
|
|
212
|
+
use: 'c'
|
|
213
|
+
}, {
|
|
214
|
+
use: 'd'
|
|
215
|
+
}, "Kevin", {
|
|
216
|
+
use: 'e'
|
|
217
|
+
}]
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
var DATA = _objectSpread(_objectSpread({}, FORM_DATA), {}, {
|
|
221
|
+
currentUser: {
|
|
222
|
+
firstname: 'Bob',
|
|
223
|
+
surname: 'Kevin'
|
|
224
|
+
},
|
|
225
|
+
postFixTitle: 'Everyone'
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
var C = FORM_COMPONENTS[2];
|
|
229
|
+
var D = FORM_COMPONENTS[3];
|
|
230
|
+
var E = FORM_COMPONENTS[4];
|
|
231
|
+
expect((0, _getFormPage.default)(PAGE, FORM_COMPONENTS, DATA)).toEqual({
|
|
232
|
+
title: 'Page Everyone',
|
|
168
233
|
components: [{
|
|
169
234
|
type: 'html',
|
|
170
235
|
tagName: 'p',
|
|
@@ -179,9 +244,28 @@ describe('utils', function () {
|
|
|
179
244
|
use: 'c'
|
|
180
245
|
}, C), {}, {
|
|
181
246
|
cya_label: C.label,
|
|
247
|
+
data: {
|
|
248
|
+
url: "".concat(FORM_DATA.urls.refData, "/v3/charlies")
|
|
249
|
+
},
|
|
182
250
|
full_path: C.fieldId
|
|
251
|
+
}), _objectSpread(_objectSpread({
|
|
252
|
+
use: 'd'
|
|
253
|
+
}, D), {}, {
|
|
254
|
+
label: 'Roger ' + DATA.currentUser.firstname,
|
|
255
|
+
cya_label: 'Roger ' + DATA.currentUser.firstname,
|
|
256
|
+
full_path: D.fieldId
|
|
257
|
+
}), {
|
|
258
|
+
type: 'html',
|
|
259
|
+
tagName: 'p',
|
|
260
|
+
content: PAGE.components[5]
|
|
261
|
+
}, _objectSpread(_objectSpread({
|
|
262
|
+
use: 'e'
|
|
263
|
+
}, E), {}, {
|
|
264
|
+
label: 'Bravo ' + DATA.currentUser.surname,
|
|
265
|
+
cya_label: 'Bravo ' + DATA.currentUser.surname,
|
|
266
|
+
full_path: E.fieldId
|
|
183
267
|
})],
|
|
184
|
-
formData:
|
|
268
|
+
formData: DATA
|
|
185
269
|
});
|
|
186
270
|
});
|
|
187
271
|
});
|
|
@@ -50,7 +50,6 @@ var validateComponent = function validateComponent(component, outerData, formDat
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
var error = undefined;
|
|
53
|
-
var nestedId = undefined;
|
|
54
53
|
var properties = undefined;
|
|
55
54
|
var data = outerData && _typeof(outerData) === 'object' ? outerData : {};
|
|
56
55
|
var value = data[component.fieldId];
|
|
@@ -81,21 +80,15 @@ var validateComponent = function validateComponent(component, outerData, formDat
|
|
|
81
80
|
break;
|
|
82
81
|
|
|
83
82
|
case _models.ComponentTypes.RADIOS:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (nestedError) {
|
|
91
|
-
error = nestedError.error;
|
|
92
|
-
nestedId = nestedError.id;
|
|
93
|
-
}
|
|
83
|
+
var nestedErrors = [];
|
|
84
|
+
(_component$data$optio = component.data.options) === null || _component$data$optio === void 0 ? void 0 : _component$data$optio.forEach(function (option) {
|
|
85
|
+
if (option.nested && formData[component.id] === option.value) {
|
|
86
|
+
nestedErrors = nestedErrors.concat((0, _validateContainer.default)({
|
|
87
|
+
components: option.nested
|
|
88
|
+
}, formData));
|
|
94
89
|
}
|
|
95
|
-
|
|
96
|
-
return nestedError;
|
|
97
90
|
});
|
|
98
|
-
|
|
91
|
+
return nestedErrors;
|
|
99
92
|
|
|
100
93
|
default:
|
|
101
94
|
break;
|
|
@@ -120,7 +113,7 @@ var validateComponent = function validateComponent(component, outerData, formDat
|
|
|
120
113
|
|
|
121
114
|
if (error) {
|
|
122
115
|
return {
|
|
123
|
-
id:
|
|
116
|
+
id: component.full_path || component.id,
|
|
124
117
|
error: error,
|
|
125
118
|
properties: properties
|
|
126
119
|
};
|
|
@@ -211,17 +211,16 @@ describe('utils.Validate.Component', function () {
|
|
|
211
211
|
id: 'a',
|
|
212
212
|
data: {
|
|
213
213
|
options: [{
|
|
214
|
-
nested: {
|
|
214
|
+
nested: [{
|
|
215
215
|
type: 'text',
|
|
216
216
|
fieldId: NESTED_ID,
|
|
217
217
|
id: NESTED_ID,
|
|
218
|
-
required: true
|
|
219
|
-
|
|
220
|
-
}
|
|
218
|
+
required: true
|
|
219
|
+
}]
|
|
221
220
|
}]
|
|
222
221
|
}
|
|
223
222
|
};
|
|
224
|
-
expect((0, _validateComponent.default)(COMPONENT, FORMDATA)).
|
|
223
|
+
expect((0, _validateComponent.default)(COMPONENT, undefined, FORMDATA)).toEqual([]);
|
|
225
224
|
});
|
|
226
225
|
it('should return an error when the radio component contains nested components with errors', function () {
|
|
227
226
|
var NESTED_ID = 'nestedId';
|
|
@@ -231,20 +230,19 @@ describe('utils.Validate.Component', function () {
|
|
|
231
230
|
id: 'a',
|
|
232
231
|
data: {
|
|
233
232
|
options: [{
|
|
234
|
-
nested: {
|
|
233
|
+
nested: [{
|
|
235
234
|
type: 'text',
|
|
236
235
|
fieldId: NESTED_ID,
|
|
237
236
|
id: NESTED_ID,
|
|
238
|
-
required: true
|
|
239
|
-
|
|
240
|
-
}
|
|
237
|
+
required: true
|
|
238
|
+
}]
|
|
241
239
|
}]
|
|
242
240
|
}
|
|
243
241
|
};
|
|
244
|
-
expect((0, _validateComponent.default)(COMPONENT, FORMDATA)).toEqual({
|
|
242
|
+
expect((0, _validateComponent.default)(COMPONENT, undefined, FORMDATA)).toEqual([{
|
|
245
243
|
id: NESTED_ID,
|
|
246
244
|
error: "Field is required"
|
|
247
|
-
});
|
|
245
|
+
}]);
|
|
248
246
|
});
|
|
249
247
|
it('should return no error when a non selected radio component contains nested components with errors', function () {
|
|
250
248
|
var NESTED_ID = 'nestedId';
|
|
@@ -253,16 +251,17 @@ describe('utils.Validate.Component', function () {
|
|
|
253
251
|
id: 'a',
|
|
254
252
|
data: {
|
|
255
253
|
options: [{
|
|
256
|
-
|
|
254
|
+
value: 'optionValue',
|
|
255
|
+
nested: [{
|
|
257
256
|
type: 'text',
|
|
258
257
|
fieldId: NESTED_ID,
|
|
259
258
|
id: NESTED_ID,
|
|
260
259
|
required: true
|
|
261
|
-
}
|
|
260
|
+
}]
|
|
262
261
|
}]
|
|
263
262
|
}
|
|
264
263
|
};
|
|
265
|
-
expect((0, _validateComponent.default)(COMPONENT, {})).
|
|
264
|
+
expect((0, _validateComponent.default)(COMPONENT, undefined, {})).toEqual([]);
|
|
266
265
|
});
|
|
267
266
|
});
|
|
268
267
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ukhomeoffice/cop-react-form-renderer",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"clean": "rimraf dist",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"post-compile": "rimraf dist/*.test.* dist/**/*.test.* dist/**/*.stories.* dist/docs dist/assets"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@ukhomeoffice/cop-react-components": "1.7.
|
|
19
|
+
"@ukhomeoffice/cop-react-components": "1.7.3",
|
|
20
20
|
"axios": "^0.21.1",
|
|
21
21
|
"dayjs": "^1.11.0",
|
|
22
22
|
"govuk-frontend": "^3.13.0",
|