@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.
@@ -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__*/React.createElement(HooksContext.Provider, {
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
- component.data.options[index].nested.value = page.formData[option.nested.id];
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', 'shown', 'formData'];
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.getNestedComponent = exports.default = void 0;
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.nestedJSX = getNestedComponent(config, 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 nested component with form data
160
- * @param {*} parentConfig
161
- * @param {*} nestedConfig
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 getNestedComponent = function getNestedComponent(parentConfig, nestedConfig) {
166
- nestedConfig.nested.onChange = parentConfig.onChange;
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
- nestedConfig.nested.value = parentConfig !== null && parentConfig !== void 0 && (_parentConfig$formDat = parentConfig.formData) !== null && _parentConfig$formDat !== void 0 && _parentConfig$formDat[nestedConfig.nested.fieldId] ? parentConfig.formData[nestedConfig.nested.fieldId] : '';
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 nestedConfig.nested) delete nestedConfig.nested.readonly;
174
+ if ('readonly' in child) delete child.readonly;
175
175
 
176
- if (parentConfig.readonly) {
177
- nestedConfig.nested.readonly = parentConfig.readonly;
178
- return getComponent(nestedConfig.nested, false);
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 getComponent(nestedConfig.nested);
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.getNestedComponent = getNestedComponent;
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 a component that is nested within another component', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
15
- var ID, FIELD_ID, LABEL, VALUE, PARENT_CONFIG, NESTED_CONFIG, _render, container, child, label, input;
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: _defineProperty({}, FIELD_ID, VALUE)
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
- _render = (0, _react.render)((0, _getComponent.getNestedComponent)(PARENT_CONFIG, NESTED_CONFIG)), container = _render.container;
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[1];
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 17:
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, _render2, container, child;
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
- nested: {
74
- id: ID,
75
- fieldId: FIELD_ID,
76
- label: LABEL,
77
- type: 'text',
78
- readonly: true
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
- (_component$data$optio = component.data.options) === null || _component$data$optio === void 0 ? void 0 : _component$data$optio.some(function (option) {
85
- var nestedError;
86
-
87
- if (option.nested && option.nested.shown) {
88
- nestedError = validateComponent(option.nested, outerData, fd);
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
- break;
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: nestedId || component.full_path || component.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
- shown: true
220
- }
218
+ required: true
219
+ }]
221
220
  }]
222
221
  }
223
222
  };
224
- expect((0, _validateComponent.default)(COMPONENT, FORMDATA)).toBeUndefined();
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
- shown: true
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
- nested: {
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, {})).toBeUndefined();
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.0.2",
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.1",
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",