@ukhomeoffice/cop-react-form-renderer 6.15.4-alpha → 6.15.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/dist/components/FormComponent/FormComponent.js +6 -0
  2. package/dist/components/FormComponent/helpers/addLabel.js +3 -2
  3. package/dist/components/FormPage/FormPage.js +20 -7
  4. package/dist/components/FormPage/FormPage.test.js +53 -0
  5. package/dist/components/FormRenderer/FormRenderer.js +0 -6
  6. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-chained-component-show-whens-containerised.json +119 -0
  7. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-chained-component-show-whens-dependent-component-nested-block.json +112 -0
  8. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-chained-component-show-whens-dependent-component-nested.json +105 -0
  9. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-chained-component-show-whens-refdata.json +105 -0
  10. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-chained-component-show-whens-target-component-nested.json +98 -0
  11. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-chained-component-show-whens.json +105 -0
  12. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-chained-show-whens-page-hidden.json +112 -0
  13. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-cop-airpax.json +26407 -0
  14. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-cop-mandec.json +9404 -0
  15. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-collection-component-dependent-on-external-data.json +157 -0
  16. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-collection-component.json +85 -0
  17. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-component-referring-to-collection.json +172 -0
  18. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-component-referring-to-hidden-collection.json +201 -0
  19. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-component-show-when-in-component-and-page.json +62 -0
  20. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-component-with-nested-questions.json +111 -0
  21. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-component.json +57 -0
  22. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-containerised-component.json +96 -0
  23. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-embedded-collection-component.json +82 -0
  24. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-embedded-component.json +54 -0
  25. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-multilevel-containerised-component-leaf-hidden.json +105 -0
  26. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-multilevel-containerised-component.json +105 -0
  27. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-options.json +98 -0
  28. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-page-collection.json +127 -0
  29. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-page-component-used-elsewhere.json +108 -0
  30. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-page-same-component-reused.json +61 -0
  31. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-page.json +95 -0
  32. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-nested-answers-hidden-by-option.json +111 -0
  33. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-page-same-component-reused-one-shown.json +74 -0
  34. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/cop-airpax-change-what-happened-before.json +300 -0
  35. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/cop-airpax-remove-photos-before.json +384 -0
  36. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/cop-mandec-remove-business-interests-before.json +140 -0
  37. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/cop-mandec-remove-criminality-before.json +186 -0
  38. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/cop-mandec-remove-unspent-convictions-before.json +143 -0
  39. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-chained-component-show-whens-containerised.json +11 -0
  40. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-chained-component-show-whens-dependent-component-nested-block.json +10 -0
  41. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-chained-component-show-whens-dependent-component-nested.json +9 -0
  42. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-chained-component-show-whens-refdata.json +11 -0
  43. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-chained-component-show-whens-target-component-nested.json +9 -0
  44. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-chained-component-show-whens.json +9 -0
  45. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-chained-show-whens-page-hidden.json +9 -0
  46. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-collection-component-dependent-on-external-data.json +26 -0
  47. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-collection-component.json +15 -0
  48. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-component-referring-to-collection.json +25 -0
  49. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-component-referring-to-hidden-collection.json +26 -0
  50. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-component-show-when-in-component-and-page.json +6 -0
  51. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-component-with-nested-questions.json +12 -0
  52. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-component.json +5 -0
  53. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-containerised-component.json +11 -0
  54. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-embedded-collection-component.json +15 -0
  55. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-embedded-component.json +5 -0
  56. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-multilevel-containerised-component-leaf-hidden.json +14 -0
  57. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-multilevel-containerised-component.json +14 -0
  58. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-options.json +10 -0
  59. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-page-collection.json +18 -0
  60. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-page-component-used-elsewhere.json +9 -0
  61. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-page-same-component-reused.json +6 -0
  62. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-page.json +9 -0
  63. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-nested-answers-hidden-by-option.json +12 -0
  64. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-page-same-component-reused-one-shown.json +8 -0
  65. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/cop-airpax-change-what-happened-after.json +280 -0
  66. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/cop-airpax-remove-photos-after.json +355 -0
  67. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/cop-mandec-base-file.json +80 -0
  68. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/cop-mandec-remove-business-interests-after.json +122 -0
  69. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/cop-mandec-remove-criminality-after.json +86 -0
  70. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/cop-mandec-remove-unspent-convictions-after.json +127 -0
  71. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-chained-component-show-whens-containerised-removed.json +11 -0
  72. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-chained-component-show-whens-dependent-component-nested-block-removed.json +7 -0
  73. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-chained-component-show-whens-dependent-component-nested-removed.json +7 -0
  74. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-chained-component-show-whens-refdata-removed.json +7 -0
  75. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-chained-component-show-whens-removed.json +7 -0
  76. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-chained-component-show-whens-target-component-nested-removed.json +6 -0
  77. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-chained-show-whens-page-hidden-removed.json +6 -0
  78. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-collection-component-dependent-on-external-data-removed.json +23 -0
  79. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-collection-component-removed.json +4 -0
  80. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-component-referring-to-collection-removed.json +21 -0
  81. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-component-referring-to-hidden-collection-removed.json +6 -0
  82. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-component-removed.json +4 -0
  83. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-component-show-when-in-component-and-page-removed.json +5 -0
  84. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-component-with-nested-questions-removed.json +10 -0
  85. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-containerised-component-removed.json +10 -0
  86. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-embedded-collection-component-removed.json +4 -0
  87. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-embedded-component-removed.json +4 -0
  88. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-multilevel-containerised-component-leaf-hidden-removed.json +13 -0
  89. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-multilevel-containerised-component-removed.json +10 -0
  90. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-options-removed.json +8 -0
  91. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-page-collection-removed.json +15 -0
  92. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-page-component-used-elsewhere-removed.json +5 -0
  93. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-page-removed.json +4 -0
  94. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-page-same-component-reused-removed.json +5 -0
  95. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-nested-answers-hidden-by-option-removed.json +11 -0
  96. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-page-same-component-reused-one-shown-removed.json +7 -0
  97. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutes.js +323 -0
  98. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutes.test.js +349 -0
  99. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutesUtils.js +381 -0
  100. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutesUtils.test.js +559 -0
  101. package/dist/components/FormRenderer/helpers/index.js +3 -1
  102. package/dist/components/FormRenderer/onCYAAction.js +12 -0
  103. package/dist/components/FormRenderer/onCYAAction.test.js +5 -0
  104. package/dist/components/FormRenderer/onPageAction.js +7 -0
  105. package/dist/components/FormRenderer/onPageAction.test.js +5 -0
  106. package/dist/utils/CollectionPage/mergeCollectionPages.js +1 -0
  107. package/package.json +2 -2
@@ -0,0 +1,559 @@
1
+ "use strict";
2
+
3
+ var Utils = _interopRequireWildcard(require("./clearOutUncompletedRoutesUtils"));
4
+ var _Condition = _interopRequireDefault(require("../../../utils/Condition"));
5
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
6
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
7
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
8
+ describe('deleteNodeByPath', () => {
9
+ it('delete where node is at parent level', () => {
10
+ const nested = {
11
+ type: "Example form",
12
+ alpha: "alpha",
13
+ bravo: "bravo",
14
+ person: {
15
+ charlie: "Smith",
16
+ delta: "Acme Inc"
17
+ },
18
+ gamma: "gamma",
19
+ epsilon: "epsilon"
20
+ };
21
+ const path = 'type';
22
+ Utils.deleteNodeByPath(nested, path);
23
+ expect(nested).toEqual({
24
+ alpha: "alpha",
25
+ bravo: "bravo",
26
+ person: {
27
+ charlie: "Smith",
28
+ delta: "Acme Inc"
29
+ },
30
+ gamma: "gamma",
31
+ epsilon: "epsilon"
32
+ });
33
+ });
34
+ it('delete where node is at child level', () => {
35
+ const nested = {
36
+ type: "Example form",
37
+ alpha: "alpha",
38
+ bravo: "bravo",
39
+ person: {
40
+ charlie: "Smith",
41
+ delta: "Acme Inc"
42
+ },
43
+ gamma: "gamma",
44
+ epsilon: "epsilon"
45
+ };
46
+ const path = 'person.charlie';
47
+ Utils.deleteNodeByPath(nested, path);
48
+ expect(nested).toEqual({
49
+ type: "Example form",
50
+ alpha: "alpha",
51
+ bravo: "bravo",
52
+ person: {
53
+ delta: "Acme Inc"
54
+ },
55
+ gamma: "gamma",
56
+ epsilon: "epsilon"
57
+ });
58
+ });
59
+ });
60
+ describe('removeObjectWithOnlySingleIdField', () => {
61
+ it('removes objects with only the "id" field', () => {
62
+ const inputArray = [{
63
+ id: 1
64
+ }, {
65
+ name: 'John'
66
+ }, {
67
+ id: 2
68
+ }, {
69
+ age: 30
70
+ }, {
71
+ id: 3
72
+ }, {
73
+ id: 4,
74
+ name: 'John'
75
+ }];
76
+ Utils.removeObjectWithOnlySingleIdField(inputArray);
77
+ expect(inputArray).toEqual([{
78
+ name: 'John'
79
+ }, {
80
+ age: 30
81
+ }, {
82
+ id: 4,
83
+ name: 'John'
84
+ }]);
85
+ });
86
+ it('does not mutate the array if no elements are removed', () => {
87
+ const inputArray = [{
88
+ name: 'John'
89
+ }, {
90
+ age: 30
91
+ }];
92
+ const originalArray = [].concat(inputArray);
93
+ Utils.removeObjectWithOnlySingleIdField(inputArray);
94
+ expect(inputArray).toEqual(originalArray);
95
+ });
96
+ });
97
+ describe('getImmediateParent', () => {
98
+ it('returns the immediate parent path when a valid path is provided', () => {
99
+ const path = 'user.profile.name';
100
+ const result = Utils.getImmediateParent(path);
101
+ expect(result).toBe('user.profile');
102
+ });
103
+ it('returns null if the path is an empty string', () => {
104
+ const result = Utils.getImmediateParent('');
105
+ expect(result).toBeNull();
106
+ });
107
+ it('returns the immediate parent when there is only one part in the path', () => {
108
+ const path = 'user.';
109
+ const result = Utils.getImmediateParent(path);
110
+ expect(result).toBe('user');
111
+ });
112
+ });
113
+ describe('getNestedQuestionPath', () => {
114
+ it('returns the correct nested path when the parent path is found', () => {
115
+ const result = Utils.getNestedQuestionPath('user.profile.name', 'age');
116
+ expect(result).toBe('user.profile.age');
117
+ });
118
+ it('returns the nestedFieldId when the parent path is not found', () => {
119
+ const result = Utils.getNestedQuestionPath('name', 'age');
120
+ expect(result).toBe('age');
121
+ });
122
+ it('handles an empty parent path correctly', () => {
123
+ const result = Utils.getNestedQuestionPath('', 'age');
124
+ expect(result).toBe('age');
125
+ });
126
+ it('handles nested paths with multiple parts correctly', () => {
127
+ const result = Utils.getNestedQuestionPath('user.profile.settings.theme', 'darkMode');
128
+ expect(result).toBe('user.profile.settings.darkMode');
129
+ });
130
+ });
131
+ describe('getDependencies', () => {
132
+ it('should extract "field" values from deeply nested structures', () => {
133
+ const input = {
134
+ "id": "firearms",
135
+ "show_when": [{
136
+ "type": "or",
137
+ "conditions": [{
138
+ "type": "and",
139
+ "conditions": [{
140
+ "op": "=",
141
+ "field": "itemCategory.category",
142
+ "value": "Weapons"
143
+ }, {
144
+ "op": "in",
145
+ "field": "itemSubCategory.epmscategory",
146
+ "values": ["ARM", "ARP"]
147
+ }]
148
+ }, {
149
+ "type": "and",
150
+ "conditions": [{
151
+ "op": "=",
152
+ "field": "itemCategory.category",
153
+ "value": "Firearms"
154
+ }, {
155
+ "op": "!=",
156
+ "field": "itemSubCategory.epmscategory",
157
+ "value": "AMM"
158
+ }]
159
+ }]
160
+ }]
161
+ };
162
+ expect(Utils.getDependencies(input)).toEqual(new Set(['itemCategory.category', 'itemSubCategory.epmscategory', 'itemCategory.category', 'itemSubCategory.epmscategory']));
163
+ });
164
+ it('should return null when no show_when', () => {
165
+ const input = {
166
+ "id": "firearms"
167
+ };
168
+ expect(Utils.getDependencies(input)).toEqual(null);
169
+ });
170
+ });
171
+ describe('getDependencyObjectFromPath', () => {
172
+ let allComponents;
173
+ beforeEach(() => {
174
+ allComponents = new Map([['whatHappened', {
175
+ id: 'whatHappened',
176
+ value: 'whatHappenedComponent'
177
+ }], ['modeOfTransport', {
178
+ id: 'modeOfTransport',
179
+ value: 'modeOfTransportComponent'
180
+ }]]);
181
+ });
182
+ it('should return the exact match from the map', () => {
183
+ expect(Utils.getDependencyObjectFromPath('whatHappened', allComponents)).toEqual({
184
+ id: 'whatHappened',
185
+ value: 'whatHappenedComponent'
186
+ });
187
+ });
188
+ it('should return the nearest parent found in the allComponents map', () => {
189
+ expect(Utils.getDependencyObjectFromPath('modeOfTransport.id', allComponents)).toEqual({
190
+ id: 'modeOfTransport',
191
+ value: 'modeOfTransportComponent'
192
+ });
193
+ });
194
+ it('should return the first matched component even when > 1 layers down', () => {
195
+ expect(Utils.getDependencyObjectFromPath('modeOfTransport.types.id', allComponents)).toEqual({
196
+ id: 'modeOfTransport',
197
+ value: 'modeOfTransportComponent'
198
+ });
199
+ });
200
+ it('should return null if no matching path is found', () => {
201
+ expect(Utils.getDependencyObjectFromPath('unknown.path', allComponents)).toBeNull();
202
+ });
203
+ });
204
+ jest.mock('../../../utils/Condition', () => ({
205
+ meetsOne: jest.fn(),
206
+ meetsAll: jest.fn()
207
+ }));
208
+ describe('isShowEntity', () => {
209
+ afterEach(() => {
210
+ jest.clearAllMocks(); // Reset mocks after each test
211
+ });
212
+ it('should return true if entity.show_when is not set', () => {
213
+ const entity = {}; // No show_when field
214
+ const data = {};
215
+ expect(Utils.isShowEntity(entity, data)).toBe(true);
216
+ });
217
+ it('should call meetsOne if show_when.type is "or"', () => {
218
+ const entity = {
219
+ show_when: {
220
+ type: 'or'
221
+ }
222
+ };
223
+ const data = {};
224
+ _Condition.default.meetsOne.mockReturnValue(true); // Mock meetsOne to return true
225
+
226
+ expect(Utils.isShowEntity(entity, data)).toBe(true);
227
+ expect(_Condition.default.meetsOne).toHaveBeenCalledWith(entity, data);
228
+ expect(_Condition.default.meetsAll).not.toHaveBeenCalled();
229
+ });
230
+ it('should call meetsAll if show_when.type is not "or"', () => {
231
+ const entity = {
232
+ show_when: {
233
+ type: 'and'
234
+ }
235
+ };
236
+ const data = {};
237
+ _Condition.default.meetsAll.mockReturnValue(false); // Mock meetsAll to return false
238
+
239
+ expect(Utils.isShowEntity(entity, data)).toBe(false);
240
+ expect(_Condition.default.meetsAll).toHaveBeenCalledWith(entity, data);
241
+ expect(_Condition.default.meetsOne).not.toHaveBeenCalled();
242
+ });
243
+ it('should call meetsAll if show_when.type is missing', () => {
244
+ const entity = {
245
+ show_when: {}
246
+ }; // No type specified
247
+ const data = {};
248
+ _Condition.default.meetsAll.mockReturnValue(true);
249
+ expect(Utils.isShowEntity(entity, data)).toBe(true);
250
+ expect(_Condition.default.meetsAll).toHaveBeenCalledWith(entity, data);
251
+ expect(_Condition.default.meetsOne).not.toHaveBeenCalled();
252
+ });
253
+ });
254
+ describe('findComponentDefinitionInForm', () => {
255
+ let componentByIdMap;
256
+ let componentByFieldIdMap;
257
+ beforeEach(() => {
258
+ componentByIdMap = new Map();
259
+ componentByFieldIdMap = new Map();
260
+ });
261
+ test('returns component from componentByIdMap when found', () => {
262
+ const component = {
263
+ id: 'comp1',
264
+ type: 'button'
265
+ };
266
+ componentByIdMap.set('comp1', component);
267
+ const pageComponentDef = {
268
+ use: 'comp1'
269
+ };
270
+ const result = Utils.findComponentDefinitionInForm(pageComponentDef, componentByIdMap, componentByFieldIdMap);
271
+ expect(result).toEqual(component);
272
+ expect(result).not.toBe(component); // Ensure it is a clone
273
+ });
274
+ test('returns component from componentByIdMap when found, but applies show_when from pageComponentDef', () => {
275
+ const component = {
276
+ id: 'comp1',
277
+ type: 'button',
278
+ show_when: 'rule1'
279
+ };
280
+ componentByIdMap.set('comp1', component);
281
+ const pageComponentDef = {
282
+ use: 'comp1',
283
+ show_when: 'rule2'
284
+ };
285
+ const result = Utils.findComponentDefinitionInForm(pageComponentDef, componentByIdMap, componentByFieldIdMap);
286
+ expect(result).toEqual({
287
+ id: 'comp1',
288
+ type: 'button',
289
+ show_when: 'rule2'
290
+ });
291
+ });
292
+ test('returns component from componentByFieldIdMap if not in componentByIdMap', () => {
293
+ const component = {
294
+ id: 'comp2',
295
+ type: 'input'
296
+ };
297
+ componentByFieldIdMap.set('comp2', component);
298
+ const pageComponentDef = {
299
+ use: 'comp2'
300
+ };
301
+ const result = Utils.findComponentDefinitionInForm(pageComponentDef, componentByIdMap, componentByFieldIdMap);
302
+ expect(result).toEqual(component);
303
+ expect(result).not.toBe(component); // Ensure it is a clone
304
+ });
305
+ test('returns pageComponentDef if not found in either map', () => {
306
+ const pageComponentDef = {
307
+ id: 'comp1',
308
+ definitions: "def values"
309
+ };
310
+ const result = Utils.findComponentDefinitionInForm(pageComponentDef, componentByIdMap, componentByFieldIdMap);
311
+ expect(result).toEqual(pageComponentDef);
312
+ expect(result).not.toBe(pageComponentDef); // Ensure it is a clone
313
+ });
314
+ test('ensures returned component is a deep clone', () => {
315
+ const component = {
316
+ id: 'comp3',
317
+ nested: {
318
+ key: 'value'
319
+ }
320
+ };
321
+ componentByIdMap.set('comp3', component);
322
+ const pageComponentDef = {
323
+ use: 'comp3'
324
+ };
325
+ const result = Utils.findComponentDefinitionInForm(pageComponentDef, componentByIdMap, componentByFieldIdMap);
326
+
327
+ // Modify the original to check deep cloning
328
+ component.nested.key = 'changed';
329
+ expect(result.nested.key).toBe('value'); // Should remain unchanged
330
+ expect(result).not.toBe(component); // Should not be the same reference
331
+ });
332
+ });
333
+ describe('deleteCorrespondingMetaInfo', () => {
334
+ let formData;
335
+ let collectionDataObject;
336
+ let component;
337
+ beforeEach(() => {
338
+ formData = {
339
+ meta: {
340
+ documents: [{
341
+ url: 'https://example.com/file1.pdf'
342
+ }, {
343
+ url: 'https://example.com/file2.pdf'
344
+ }, {
345
+ url: 'https://example.com/file3.pdf'
346
+ }]
347
+ }
348
+ };
349
+ collectionDataObject = {};
350
+ component = {
351
+ fieldId: 'fileField'
352
+ };
353
+ });
354
+ test('removes a matching document when found', () => {
355
+ collectionDataObject.fileField = {
356
+ url: 'https://example.com/file2.pdf'
357
+ };
358
+ Utils.deleteCorrespondingMetaInfo(component, collectionDataObject, formData);
359
+ expect(formData.meta.documents).toEqual([{
360
+ url: 'https://example.com/file1.pdf'
361
+ }, {
362
+ url: 'https://example.com/file3.pdf'
363
+ }]);
364
+ });
365
+ test('removes a matching document when fileDataBeingDeleted is an array', () => {
366
+ collectionDataObject.fileField = [{
367
+ url: 'https://example.com/file2.pdf'
368
+ }, {
369
+ url: 'https://example.com/file3.pdf'
370
+ }];
371
+ Utils.deleteCorrespondingMetaInfo(component, collectionDataObject, formData);
372
+ expect(formData.meta.documents).toEqual([{
373
+ url: 'https://example.com/file1.pdf'
374
+ }]);
375
+ });
376
+ test('does nothing if documents array is empty', () => {
377
+ formData.meta.documents = [];
378
+ collectionDataObject.fileField = {
379
+ url: 'https://example.com/file2.pdf'
380
+ };
381
+ Utils.deleteCorrespondingMetaInfo(component, collectionDataObject, formData);
382
+ expect(formData.meta.documents).toEqual([]);
383
+ });
384
+ test('does nothing if fileDataBeingDeleted is undefined', () => {
385
+ Utils.deleteCorrespondingMetaInfo(component, collectionDataObject, formData);
386
+ expect(formData.meta.documents).toEqual([{
387
+ url: 'https://example.com/file1.pdf'
388
+ }, {
389
+ url: 'https://example.com/file2.pdf'
390
+ }, {
391
+ url: 'https://example.com/file3.pdf'
392
+ }]);
393
+ });
394
+ test('does nothing if there is no match', () => {
395
+ collectionDataObject.fileField = {
396
+ url: 'https://example.com/nonexistent.pdf'
397
+ };
398
+ Utils.deleteCorrespondingMetaInfo(component, collectionDataObject, formData);
399
+ expect(formData.meta.documents).toEqual([{
400
+ url: 'https://example.com/file1.pdf'
401
+ }, {
402
+ url: 'https://example.com/file2.pdf'
403
+ }, {
404
+ url: 'https://example.com/file3.pdf'
405
+ }]);
406
+ });
407
+ });
408
+ describe("removeEmptyArraysAndUnusedCollectionIDs", () => {
409
+ test("removes empty arrays from an array", () => {
410
+ const input = [1, [], 2, []];
411
+ Utils.removeEmptyArraysAndUnusedCollectionIDs(input);
412
+ expect(input).toEqual([1, 2]);
413
+ });
414
+ test("removes empty arrays from an object and deletes corresponding ActiveId", () => {
415
+ const input = {
416
+ key1: [],
417
+ key1ActiveId: "123",
418
+ key2: "value"
419
+ };
420
+ Utils.removeEmptyArraysAndUnusedCollectionIDs(input);
421
+ expect(input).toEqual({
422
+ key2: "value"
423
+ });
424
+ });
425
+ test("removes empty arrays in nested structures", () => {
426
+ const input = {
427
+ level1: {
428
+ level2: {
429
+ arr: [],
430
+ arrActiveId: "456",
431
+ anotherKey: "data"
432
+ }
433
+ }
434
+ };
435
+ Utils.removeEmptyArraysAndUnusedCollectionIDs(input);
436
+ expect(input).toEqual({
437
+ level1: {
438
+ level2: {
439
+ anotherKey: "data"
440
+ }
441
+ }
442
+ });
443
+ });
444
+ test("removes multiple empty arrays and their ActiveIds", () => {
445
+ const input = {
446
+ list1: [],
447
+ list1ActiveId: "789",
448
+ list2: [1, 2],
449
+ nested: {
450
+ emptyList: [],
451
+ emptyListActiveId: "999"
452
+ }
453
+ };
454
+ Utils.removeEmptyArraysAndUnusedCollectionIDs(input);
455
+ expect(input).toEqual({
456
+ list2: [1, 2],
457
+ nested: {}
458
+ });
459
+ });
460
+ test("does not modify non-empty arrays", () => {
461
+ const input = {
462
+ arr: [1, 2, 3],
463
+ obj: {
464
+ nestedArr: ["a"]
465
+ }
466
+ };
467
+ const expected = {
468
+ arr: [1, 2, 3],
469
+ obj: {
470
+ nestedArr: ["a"]
471
+ }
472
+ };
473
+ Utils.removeEmptyArraysAndUnusedCollectionIDs(input);
474
+ expect(input).toEqual(expected);
475
+ });
476
+ test("handles null and empty object gracefully", () => {
477
+ const input1 = null;
478
+ const input2 = {};
479
+ Utils.removeEmptyArraysAndUnusedCollectionIDs(input1);
480
+ Utils.removeEmptyArraysAndUnusedCollectionIDs(input2);
481
+ expect(input1).toBeNull();
482
+ expect(input2).toEqual({});
483
+ });
484
+ test("handles arrays containing objects with empty arrays", () => {
485
+ const input = [{
486
+ key: []
487
+ }, {
488
+ key: "value"
489
+ }, {
490
+ nested: {
491
+ arr: [],
492
+ arrActiveId: "555"
493
+ }
494
+ }];
495
+ Utils.removeEmptyArraysAndUnusedCollectionIDs(input);
496
+ expect(input).toEqual([{
497
+ key: "value"
498
+ }, {
499
+ nested: {}
500
+ }]);
501
+ });
502
+ });
503
+ describe("pruneCollectionEntry", () => {
504
+ let pathsToKeep;
505
+ let componentsToPrune;
506
+ let collectionDataObject;
507
+ let formData;
508
+ let expectedFormData;
509
+ beforeEach(() => {
510
+ pathsToKeep = new Set(['keepThis']);
511
+ componentsToPrune = [{
512
+ fieldId: 'removeThis',
513
+ type: 'text'
514
+ }, {
515
+ fieldId: 'keepThis',
516
+ type: 'text'
517
+ }, {
518
+ fieldId: 'removeMultifile',
519
+ type: 'multifile'
520
+ }];
521
+ collectionDataObject = {
522
+ 'removeThis': 'value',
523
+ 'keepThis': 'value',
524
+ 'removeMultifile': {
525
+ 'url': 'https://example.com/file1.pdf'
526
+ }
527
+ };
528
+ formData = {
529
+ meta: {
530
+ documents: [{
531
+ url: 'https://example.com/file1.pdf'
532
+ }, {
533
+ url: 'https://example.com/file2.pdf'
534
+ }, {
535
+ url: 'https://example.com/file3.pdf'
536
+ }]
537
+ }
538
+ };
539
+ expectedFormData = {
540
+ meta: {
541
+ documents: [{
542
+ url: 'https://example.com/file2.pdf'
543
+ }, {
544
+ url: 'https://example.com/file3.pdf'
545
+ }]
546
+ }
547
+ };
548
+ });
549
+ it('should remove components not in pathsToKeep', () => {
550
+ Utils.pruneCollectionEntry(pathsToKeep, componentsToPrune, collectionDataObject, formData);
551
+ expect(collectionDataObject).toEqual({
552
+ 'keepThis': 'value'
553
+ });
554
+ });
555
+ it('should delete meta.documents for multifile components', () => {
556
+ Utils.pruneCollectionEntry(pathsToKeep, componentsToPrune, collectionDataObject, formData);
557
+ expect(formData).toEqual(expectedFormData);
558
+ });
559
+ });
@@ -13,6 +13,7 @@ var _getNextPageId = _interopRequireDefault(require("./getNextPageId"));
13
13
  var _getPage = _interopRequireDefault(require("./getPage"));
14
14
  var _getSubmissionStatus = _interopRequireDefault(require("./getSubmissionStatus"));
15
15
  var _getUpdatedSectionStates = _interopRequireDefault(require("./getUpdatedSectionStates"));
16
+ var _clearOutUncompletedRoutes = _interopRequireDefault(require("./clearOutUncompletedRoutes"));
16
17
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
18
  // Local imports
18
19
 
@@ -25,6 +26,7 @@ const helpers = {
25
26
  getNextPageId: _getNextPageId.default,
26
27
  getPage: _getPage.default,
27
28
  getSubmissionStatus: _getSubmissionStatus.default,
28
- getUpdatedSectionStates: _getUpdatedSectionStates.default
29
+ getUpdatedSectionStates: _getUpdatedSectionStates.default,
30
+ clearOutUncompletedRoutes: _clearOutUncompletedRoutes.default
29
31
  };
30
32
  var _default = exports.default = helpers;
@@ -30,6 +30,13 @@ const onCYAAction = (setPagePoint, action, pages, validate, components, data, se
30
30
  pages,
31
31
  components
32
32
  }, _objectSpread({}, data), _models.EventTypes.SUBMIT);
33
+
34
+ // Cleanse hidden data
35
+ const formPagesAndComponents = {
36
+ pages,
37
+ components
38
+ };
39
+ _helpers.default.clearOutUncompletedRoutes(formPagesAndComponents, submissionData);
33
40
  submissionData.formStatus = _helpers.default.getSubmissionStatus(type, pages, pageId, action, submissionData, currentTask, true);
34
41
  setData(submissionData);
35
42
  // Now submit the data to the backend...
@@ -69,6 +76,11 @@ const onCYAAction = (setPagePoint, action, pages, validate, components, data, se
69
76
  pages,
70
77
  components
71
78
  }, _objectSpread({}, data), _models.EventTypes.SUBMIT);
79
+ const formPagesAndComponents = {
80
+ pages,
81
+ components
82
+ };
83
+ _helpers.default.clearOutUncompletedRoutes(formPagesAndComponents, submissionData);
72
84
  submissionData.formStatus = _helpers.default.getSubmissionStatus(type, pages, pageId, action, submissionData, currentTask, true);
73
85
  setData(submissionData);
74
86
  // Now submit the data to the backend...
@@ -55,6 +55,11 @@ jest.mock('./helpers', () => ({
55
55
  this.getNextPageIdCalls = 0;
56
56
  this.getFormStateCalls = 0;
57
57
  this.getSubmissionStatusCalls = 0;
58
+ },
59
+ clearOutUncompletedRoutesCalls: 0,
60
+ clearOutUncompletedRoutes(formPagesAndComponents, formData) {
61
+ this.clearOutUncompletedRoutesCalls += 1;
62
+ return formData;
58
63
  }
59
64
  }));
60
65
  jest.mock('../../utils', () => ({
@@ -107,6 +107,13 @@ const onPageAction = (action, patch, patchLabel, hooks, data, formState, validat
107
107
  setData(submissionData);
108
108
  }
109
109
  ;
110
+ const formPagesAndComponents = {
111
+ pages,
112
+ components
113
+ };
114
+ if (action.type === _models.PageAction.TYPES.SUBMIT) {
115
+ _helpers.default.clearOutUncompletedRoutes(formPagesAndComponents, submissionData);
116
+ }
110
117
 
111
118
  // In case of hub-and-spoke if patchLabel has changed then
112
119
  // save name and value to variables for call to onSubmit hook
@@ -46,6 +46,11 @@ jest.mock('./helpers', () => ({
46
46
  this.cleanHiddenNestedDataCalls += 1;
47
47
  return patch;
48
48
  },
49
+ clearOutUncompletedRoutesCalls: 0,
50
+ clearOutUncompletedRoutes(formPagesAndComponents, formData) {
51
+ this.clearOutUncompletedRoutesCalls += 1;
52
+ return formData;
53
+ },
49
54
  getNextPageIdCalls: 0,
50
55
  getNextPageId() {
51
56
  this.getNextPageIdCalls += 1;
@@ -31,6 +31,7 @@ const createMasterPage = page => ({
31
31
  id: page.id,
32
32
  name: page.name,
33
33
  orderInForm: page.orderInForm,
34
+ deleteCollectionWhenHidden: page.deleteCollectionWhenHidden,
34
35
  collection: _objectSpread({
35
36
  masterPage: true
36
37
  }, page.collection),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ukhomeoffice/cop-react-form-renderer",
3
- "version": "6.15.4-alpha",
3
+ "version": "6.15.4",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "clean": "rimraf dist",
@@ -16,7 +16,7 @@
16
16
  "yalc-publish": "yarn compile-with-maps && cp -r src dist/src && yalc publish --push"
17
17
  },
18
18
  "dependencies": {
19
- "@ukhomeoffice/cop-react-components": "4.7.15",
19
+ "@ukhomeoffice/cop-react-components": "4.7.16",
20
20
  "axios": "^0.23.0",
21
21
  "dayjs": "^1.11.0",
22
22
  "govuk-frontend": "^5.0.0",