@remoteoss/json-schema-form 0.7.1-dev.20231026204916 → 0.7.2-dev.20231106093837
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/CHANGELOG.md +14 -22
- package/dist/index.cjs +79 -61
- package/dist/index.js +79 -61
- package/dist/standalone.js +79 -61
- package/package.json +1 -1
- package/src/tests/conditions.test.js +309 -6
- package/src/tests/createHeadlessForm.test.js +109 -70
- package/src/tests/helpers.js +9 -40
package/dist/standalone.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
/*!
|
|
3
3
|
Copyright (c) 2023 Remote Technology, Inc.
|
|
4
|
-
NPM Package: @remoteoss/json-schema-form@0.7.
|
|
5
|
-
Generated:
|
|
4
|
+
NPM Package: @remoteoss/json-schema-form@0.7.2-dev.20231106093837
|
|
5
|
+
Generated: Mon, 06 Nov 2023 09:38:54 GMT
|
|
6
6
|
|
|
7
7
|
MIT License
|
|
8
8
|
|
|
@@ -11779,38 +11779,22 @@ var validateMaxDate = (value, minDate) => {
|
|
|
11779
11779
|
};
|
|
11780
11780
|
var yupSchemas = {
|
|
11781
11781
|
text: validateOnlyStrings,
|
|
11782
|
-
radioOrSelect: (options
|
|
11783
|
-
if (
|
|
11784
|
-
return
|
|
11782
|
+
radioOrSelect: (options, isString2) => {
|
|
11783
|
+
if (isString2) {
|
|
11784
|
+
return StringSchema().nullable();
|
|
11785
11785
|
}
|
|
11786
|
-
|
|
11787
|
-
|
|
11788
|
-
|
|
11789
|
-
return value === null ? void 0 : value;
|
|
11790
|
-
}).test(
|
|
11791
|
-
/*
|
|
11792
|
-
Custom test determines if the value either:
|
|
11793
|
-
- Matches a specific option by value
|
|
11794
|
-
- Matches a pattern
|
|
11795
|
-
If the option is undefined do not test, to allow for optional fields.
|
|
11796
|
-
*/
|
|
11797
|
-
"matchesOptionOrPattern",
|
|
11798
|
-
({ value }) => `The option ${JSON.stringify(value)} is not valid.`,
|
|
11799
|
-
(value) => {
|
|
11800
|
-
if (value === void 0) {
|
|
11801
|
-
return true;
|
|
11802
|
-
}
|
|
11803
|
-
const exactMatch = options.some((option) => option.value === value);
|
|
11804
|
-
if (exactMatch) {
|
|
11805
|
-
return true;
|
|
11786
|
+
return StringSchema().nullable().transform((value) => {
|
|
11787
|
+
if (value === "") {
|
|
11788
|
+
return void 0;
|
|
11806
11789
|
}
|
|
11807
|
-
|
|
11808
|
-
|
|
11809
|
-
return true;
|
|
11790
|
+
if (options?.includes(null)) {
|
|
11791
|
+
return value;
|
|
11810
11792
|
}
|
|
11811
|
-
return
|
|
11812
|
-
}
|
|
11813
|
-
|
|
11793
|
+
return value === null ? void 0 : value;
|
|
11794
|
+
}).oneOf(options, ({ value }) => {
|
|
11795
|
+
return `The option ${JSON.stringify(value)} is not valid.`;
|
|
11796
|
+
});
|
|
11797
|
+
},
|
|
11814
11798
|
date: ({ minDate, maxDate }) => {
|
|
11815
11799
|
let dateString = StringSchema().nullable().transform((value) => {
|
|
11816
11800
|
if (value === "") {
|
|
@@ -11868,21 +11852,19 @@ function getRequiredErrorMessage(inputType, { inlineError, configError }) {
|
|
|
11868
11852
|
}
|
|
11869
11853
|
var getJsonTypeInArray = (jsonType) => Array.isArray(jsonType) ? jsonType.find((val) => val !== "null") : jsonType;
|
|
11870
11854
|
var getOptions = (field) => {
|
|
11871
|
-
const allValues = field.options?.map((option) =>
|
|
11872
|
-
value: option.value,
|
|
11873
|
-
pattern: option.pattern ? new RegExp(option.pattern) : null
|
|
11874
|
-
}));
|
|
11855
|
+
const allValues = field.options?.map((option) => option.value);
|
|
11875
11856
|
const isOptionalWithNull = Array.isArray(field.jsonType) && // @TODO should also check the "oneOf" directly looking for "null"
|
|
11876
11857
|
// option but we don't have direct access at this point.
|
|
11877
11858
|
// Otherwise the JSON Schema validator will fail as explained in PR#18
|
|
11878
11859
|
field.jsonType.includes("null");
|
|
11879
|
-
return isOptionalWithNull ? [...allValues,
|
|
11860
|
+
return isOptionalWithNull ? [...allValues, null] : allValues;
|
|
11880
11861
|
};
|
|
11881
11862
|
var getYupSchema = ({ inputType, ...field }) => {
|
|
11882
11863
|
const jsonType = getJsonTypeInArray(field.jsonType);
|
|
11883
11864
|
if (field.options?.length > 0) {
|
|
11865
|
+
const isString2 = field.options?.findIndex((option) => option.type === "string") > -1;
|
|
11884
11866
|
const optionValues = getOptions(field);
|
|
11885
|
-
return yupSchemas.radioOrSelect(optionValues);
|
|
11867
|
+
return yupSchemas.radioOrSelect(optionValues, isString2);
|
|
11886
11868
|
}
|
|
11887
11869
|
if (field.format === "date") {
|
|
11888
11870
|
return yupSchemas.date({ minDate: field.minDate, maxDate: field.maxDate });
|
|
@@ -12373,6 +12355,33 @@ function processJSONLogicNode({
|
|
|
12373
12355
|
}
|
|
12374
12356
|
|
|
12375
12357
|
// src/helpers.js
|
|
12358
|
+
var dynamicInternalJsfAttrs = [
|
|
12359
|
+
"isVisible",
|
|
12360
|
+
// Driven from conditionals state
|
|
12361
|
+
"fields",
|
|
12362
|
+
// driven from group-array
|
|
12363
|
+
"getComputedAttributes",
|
|
12364
|
+
// From json-logic
|
|
12365
|
+
"computedAttributes",
|
|
12366
|
+
// From json-logic
|
|
12367
|
+
"calculateConditionalProperties",
|
|
12368
|
+
// driven from conditionals
|
|
12369
|
+
"calculateCustomValidationProperties",
|
|
12370
|
+
// To be deprecated in favor of json-logic
|
|
12371
|
+
"scopedJsonSchema"
|
|
12372
|
+
// The respective JSON Schema
|
|
12373
|
+
];
|
|
12374
|
+
var dynamicInternalJsfAttrsObj = Object.fromEntries(
|
|
12375
|
+
dynamicInternalJsfAttrs.map((k) => [k, true])
|
|
12376
|
+
);
|
|
12377
|
+
function removeConditionalStaleAttributes(field, conditionalAttrs, rootAttrs) {
|
|
12378
|
+
Object.keys(field).forEach((key) => {
|
|
12379
|
+
if (conditionalAttrs[key] === void 0 && rootAttrs[key] === void 0 && // Don't remove attrs that were declared in the root field.
|
|
12380
|
+
dynamicInternalJsfAttrsObj[key] === void 0) {
|
|
12381
|
+
field[key] = void 0;
|
|
12382
|
+
}
|
|
12383
|
+
});
|
|
12384
|
+
}
|
|
12376
12385
|
function hasType(type, typeName) {
|
|
12377
12386
|
return Array.isArray(type) ? type.includes(typeName) : type === typeName;
|
|
12378
12387
|
}
|
|
@@ -12465,19 +12474,21 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
|
12465
12474
|
if (fieldIsRequired) {
|
|
12466
12475
|
field.isVisible = true;
|
|
12467
12476
|
}
|
|
12468
|
-
const
|
|
12469
|
-
|
|
12470
|
-
|
|
12471
|
-
|
|
12472
|
-
|
|
12473
|
-
|
|
12474
|
-
|
|
12475
|
-
field.
|
|
12477
|
+
const updateAttributes = (fieldAttrs) => {
|
|
12478
|
+
Object.entries(fieldAttrs).forEach(([key, value]) => {
|
|
12479
|
+
field[key] = typeof value === "function" ? value() : value;
|
|
12480
|
+
if (key === "value") {
|
|
12481
|
+
const readOnlyPropertyWasUpdated = typeof fieldAttrs.readOnly !== "undefined";
|
|
12482
|
+
const isReadonlyByDefault = field.readOnly;
|
|
12483
|
+
const isReadonly = readOnlyPropertyWasUpdated ? fieldAttrs.readOnly : isReadonlyByDefault;
|
|
12484
|
+
if (!isReadonly && (value === null || field.inputType === "checkbox")) {
|
|
12485
|
+
field.value = void 0;
|
|
12486
|
+
}
|
|
12476
12487
|
}
|
|
12477
|
-
}
|
|
12478
|
-
}
|
|
12488
|
+
});
|
|
12489
|
+
};
|
|
12479
12490
|
if (field.getComputedAttributes) {
|
|
12480
|
-
const
|
|
12491
|
+
const newAttributes = field.getComputedAttributes({
|
|
12481
12492
|
field,
|
|
12482
12493
|
isRequired: fieldIsRequired,
|
|
12483
12494
|
node,
|
|
@@ -12485,23 +12496,24 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
|
12485
12496
|
config,
|
|
12486
12497
|
logic
|
|
12487
12498
|
});
|
|
12488
|
-
|
|
12499
|
+
updateAttributes(newAttributes);
|
|
12489
12500
|
}
|
|
12490
12501
|
if (field.calculateConditionalProperties) {
|
|
12491
|
-
const
|
|
12502
|
+
const { rootFieldAttrs, newAttributes } = field.calculateConditionalProperties({
|
|
12492
12503
|
isRequired: fieldIsRequired,
|
|
12493
12504
|
conditionBranch: node,
|
|
12494
12505
|
formValues
|
|
12495
12506
|
});
|
|
12496
|
-
|
|
12507
|
+
updateAttributes(newAttributes, rootFieldAttrs);
|
|
12508
|
+
removeConditionalStaleAttributes(field, newAttributes, rootFieldAttrs);
|
|
12497
12509
|
}
|
|
12498
12510
|
if (field.calculateCustomValidationProperties) {
|
|
12499
|
-
const
|
|
12511
|
+
const newAttributes = field.calculateCustomValidationProperties(
|
|
12500
12512
|
fieldIsRequired,
|
|
12501
12513
|
node,
|
|
12502
12514
|
formValues
|
|
12503
12515
|
);
|
|
12504
|
-
|
|
12516
|
+
updateAttributes(newAttributes);
|
|
12505
12517
|
}
|
|
12506
12518
|
}
|
|
12507
12519
|
function processNode({
|
|
@@ -12843,17 +12855,23 @@ function calculateConditionalProperties({ fieldParams, customProperties, logic,
|
|
|
12843
12855
|
logic
|
|
12844
12856
|
)
|
|
12845
12857
|
};
|
|
12846
|
-
return
|
|
12858
|
+
return {
|
|
12859
|
+
rootFieldAttrs: fieldParams,
|
|
12860
|
+
newAttributes: (0, import_omit2.default)((0, import_merge2.default)(base, presentation, newFieldParams), ["inputType"])
|
|
12861
|
+
};
|
|
12847
12862
|
}
|
|
12848
12863
|
const isVisible = isRequired;
|
|
12849
12864
|
return {
|
|
12850
|
-
|
|
12851
|
-
|
|
12852
|
-
|
|
12853
|
-
|
|
12854
|
-
|
|
12855
|
-
|
|
12856
|
-
|
|
12865
|
+
rootFieldAttrs: fieldParams,
|
|
12866
|
+
newAttributes: {
|
|
12867
|
+
isVisible,
|
|
12868
|
+
required: isRequired,
|
|
12869
|
+
schema: buildYupSchema({
|
|
12870
|
+
...fieldParams,
|
|
12871
|
+
...extractParametersFromNode(conditionBranch),
|
|
12872
|
+
required: isRequired
|
|
12873
|
+
})
|
|
12874
|
+
}
|
|
12857
12875
|
};
|
|
12858
12876
|
};
|
|
12859
12877
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remoteoss/json-schema-form",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2-dev.20231106093837",
|
|
4
4
|
"description": "Headless UI form powered by JSON Schemas",
|
|
5
5
|
"author": "Remote.com <engineering@remote.com> (https://remote.com/)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,12 +27,7 @@ it('Should allow check of a nested property in a conditional', () => {
|
|
|
27
27
|
additionalProperties: false,
|
|
28
28
|
properties: {
|
|
29
29
|
child: {
|
|
30
|
-
oneOf: [
|
|
31
|
-
{
|
|
32
|
-
const: 'yes',
|
|
33
|
-
},
|
|
34
|
-
{ const: 'no' },
|
|
35
|
-
],
|
|
30
|
+
oneOf: [{ const: 'yes' }, { const: 'no' }],
|
|
36
31
|
type: 'string',
|
|
37
32
|
},
|
|
38
33
|
},
|
|
@@ -56,3 +51,311 @@ it('Should allow check of a nested property in a conditional', () => {
|
|
|
56
51
|
undefined
|
|
57
52
|
);
|
|
58
53
|
});
|
|
54
|
+
|
|
55
|
+
describe('Conditional attributes updated', () => {
|
|
56
|
+
it('Update basic case with const, default, maximum', () => {
|
|
57
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
58
|
+
{
|
|
59
|
+
properties: {
|
|
60
|
+
is_full_time: { type: 'string', oneOf: [{ const: 'yes' }, { const: 'no' }] },
|
|
61
|
+
hours: { type: 'number' },
|
|
62
|
+
},
|
|
63
|
+
allOf: [
|
|
64
|
+
{
|
|
65
|
+
if: {
|
|
66
|
+
properties: { is_full_time: { const: 'yes' } },
|
|
67
|
+
required: ['is_full_time'],
|
|
68
|
+
},
|
|
69
|
+
then: {
|
|
70
|
+
properties: {
|
|
71
|
+
hours: {
|
|
72
|
+
const: 8,
|
|
73
|
+
default: 8,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
else: {
|
|
78
|
+
properties: {
|
|
79
|
+
hours: {
|
|
80
|
+
maximum: 4,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
{ strictInputType: false }
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
// Given "Yes" it applies "const" and "default"
|
|
91
|
+
expect(handleValidation({ is_full_time: 'yes', hours: 4 }).formErrors).toEqual({
|
|
92
|
+
hours: 'The only accepted value is 8.',
|
|
93
|
+
});
|
|
94
|
+
expect(fields[1]).toMatchObject({ const: 8, default: 8 });
|
|
95
|
+
expect(fields[1].maximum).toBeUndefined();
|
|
96
|
+
|
|
97
|
+
// Changing to "No", applies the "maximum" and cleans "const" and "default"
|
|
98
|
+
expect(handleValidation({ is_full_time: 'no', hours: 4 }).formErrors).toBeUndefined();
|
|
99
|
+
expect(fields[1]).toMatchObject({ maximum: 4 });
|
|
100
|
+
expect(fields[1].const).toBeUndefined();
|
|
101
|
+
expect(fields[1].default).toBeUndefined();
|
|
102
|
+
|
|
103
|
+
// Changing back to "Yes", it removes "maximum", and applies "const" and "default"
|
|
104
|
+
expect(handleValidation({}).formErrors).toBeUndefined();
|
|
105
|
+
expect(handleValidation({ is_full_time: 'yes', hours: 8 }).formErrors).toBeUndefined();
|
|
106
|
+
expect(fields[1].maximum).toBeUndefined();
|
|
107
|
+
expect(fields[1]).toMatchObject({ const: 8, default: 8 });
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('Update a new attribute (eg description)', () => {
|
|
111
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
112
|
+
{
|
|
113
|
+
properties: {
|
|
114
|
+
is_full_time: { type: 'string', oneOf: [{ const: 'yes' }, { const: 'no' }] },
|
|
115
|
+
hours: {
|
|
116
|
+
type: 'number',
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
allOf: [
|
|
120
|
+
{
|
|
121
|
+
if: {
|
|
122
|
+
properties: { is_full_time: { const: 'yes' } },
|
|
123
|
+
required: ['is_full_time'],
|
|
124
|
+
},
|
|
125
|
+
then: {
|
|
126
|
+
properties: {
|
|
127
|
+
hours: {
|
|
128
|
+
description: 'We recommend 8 hours.',
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
{ strictInputType: false }
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
// By default the attribute is not set.
|
|
139
|
+
expect(fields[1].description).toBeUndefined();
|
|
140
|
+
|
|
141
|
+
// Given "Yes" it applies the conditional attribute
|
|
142
|
+
expect(handleValidation({ is_full_time: 'yes' }).formErrors).toBeUndefined();
|
|
143
|
+
expect(fields[1].description).toBe('We recommend 8 hours.');
|
|
144
|
+
|
|
145
|
+
// Changing to "No", removes the description
|
|
146
|
+
expect(handleValidation({ is_full_time: 'no' }).formErrors).toBeUndefined();
|
|
147
|
+
expect(fields[1].description).toBeUndefined();
|
|
148
|
+
|
|
149
|
+
// Changing back to "Yes", it sets the attribute again
|
|
150
|
+
expect(handleValidation({ is_full_time: 'yes' }).formErrors).toBeUndefined();
|
|
151
|
+
expect(fields[1].description).toBe('We recommend 8 hours.');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('Update an existing attribute (eg description)', () => {
|
|
155
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
156
|
+
{
|
|
157
|
+
properties: {
|
|
158
|
+
is_full_time: { type: 'string', oneOf: [{ const: 'yes' }, { const: 'no' }] },
|
|
159
|
+
hours: {
|
|
160
|
+
type: 'number',
|
|
161
|
+
description: 'Any value works.',
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
allOf: [
|
|
165
|
+
{
|
|
166
|
+
if: {
|
|
167
|
+
properties: { is_full_time: { const: 'yes' } },
|
|
168
|
+
required: ['is_full_time'],
|
|
169
|
+
},
|
|
170
|
+
then: {
|
|
171
|
+
properties: {
|
|
172
|
+
hours: {
|
|
173
|
+
description: 'We recommend 8 hours.',
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
{ strictInputType: false }
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
// By default the attribute is set the base value.
|
|
184
|
+
expect(fields[1].description).toBe('Any value works.');
|
|
185
|
+
|
|
186
|
+
// Given "Yes" it applies the conditional attribute
|
|
187
|
+
expect(handleValidation({ is_full_time: 'yes', hours: 4 }).formErrors).toBeUndefined();
|
|
188
|
+
expect(fields[1].description).toBe('We recommend 8 hours.');
|
|
189
|
+
|
|
190
|
+
// Changing to "No", it applies the base value again.
|
|
191
|
+
expect(handleValidation({ is_full_time: 'no', hours: 4 }).formErrors).toBeUndefined();
|
|
192
|
+
expect(fields[1].description).toBe('Any value works.');
|
|
193
|
+
|
|
194
|
+
// Changing back to "Yes", it sets the attribute again
|
|
195
|
+
expect(handleValidation({ is_full_time: 'yes', hours: 8 }).formErrors).toBeUndefined();
|
|
196
|
+
expect(fields[1].description).toBe('We recommend 8 hours.');
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('Update a nested attribute', () => {
|
|
200
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
201
|
+
{
|
|
202
|
+
properties: {
|
|
203
|
+
is_full_time: { type: 'string', oneOf: [{ const: 'yes' }, { const: 'no' }] },
|
|
204
|
+
hours: {
|
|
205
|
+
type: 'number',
|
|
206
|
+
presentation: {
|
|
207
|
+
inputType: 'number',
|
|
208
|
+
anything: 'info',
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
allOf: [
|
|
213
|
+
{
|
|
214
|
+
if: {
|
|
215
|
+
properties: { is_full_time: { const: 'yes' } },
|
|
216
|
+
required: ['is_full_time'],
|
|
217
|
+
},
|
|
218
|
+
then: {
|
|
219
|
+
properties: {
|
|
220
|
+
hours: {
|
|
221
|
+
presentation: {
|
|
222
|
+
anything: 'danger',
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
],
|
|
229
|
+
},
|
|
230
|
+
{ strictInputType: false }
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
// By default the attribute is set the base value.
|
|
234
|
+
expect(fields[1].anything).toBe('info');
|
|
235
|
+
|
|
236
|
+
// Given "Yes" it applies the conditional attribute
|
|
237
|
+
expect(handleValidation({ is_full_time: 'yes' }).formErrors).toBeUndefined();
|
|
238
|
+
expect(fields[1].anything).toBe('danger');
|
|
239
|
+
|
|
240
|
+
// Changing to "No", it applies the base value again.
|
|
241
|
+
expect(handleValidation({ is_full_time: 'no' }).formErrors).toBeUndefined();
|
|
242
|
+
expect(fields[1].anything).toBe('info');
|
|
243
|
+
|
|
244
|
+
// Changing back to "Yes", it sets the attribute again
|
|
245
|
+
expect(handleValidation({ is_full_time: 'yes' }).formErrors).toBeUndefined();
|
|
246
|
+
expect(fields[1].anything).toBe('danger');
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('Keeps existing attributes in matches that dont change the attr', () => {
|
|
250
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
251
|
+
{
|
|
252
|
+
properties: {
|
|
253
|
+
is_full_time: { type: 'string', oneOf: [{ const: 'yes' }, { const: 'no' }] },
|
|
254
|
+
hours: {
|
|
255
|
+
type: 'number',
|
|
256
|
+
description: 'Any value works.',
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
allOf: [
|
|
260
|
+
{
|
|
261
|
+
if: {
|
|
262
|
+
properties: { is_full_time: { const: 'yes' } },
|
|
263
|
+
required: ['is_full_time'],
|
|
264
|
+
},
|
|
265
|
+
then: {
|
|
266
|
+
required: ['hours'],
|
|
267
|
+
},
|
|
268
|
+
else: {
|
|
269
|
+
properties: {
|
|
270
|
+
hours: false,
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
],
|
|
275
|
+
},
|
|
276
|
+
{ strictInputType: false }
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
// By default the attribute is set the base value, even though the field is invisible.
|
|
280
|
+
expect(fields[1].description).toBe('Any value works.');
|
|
281
|
+
expect(fields[1].isVisible).toBe(false);
|
|
282
|
+
|
|
283
|
+
// Given "Yes" it keeps the base value
|
|
284
|
+
expect(handleValidation({ is_full_time: 'yes' }).formErrors).toEqual({
|
|
285
|
+
hours: 'Required field',
|
|
286
|
+
});
|
|
287
|
+
expect(fields[1].description).toBe('Any value works.');
|
|
288
|
+
expect(fields[1].isVisible).toBe(true);
|
|
289
|
+
|
|
290
|
+
// Changing to "No" it keeps the base value
|
|
291
|
+
expect(handleValidation({ is_full_time: 'no' }).formErrors).toBeUndefined();
|
|
292
|
+
expect(fields[1].description).toBe('Any value works.');
|
|
293
|
+
expect(fields[1].isVisible).toBe(false);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('Keeps internal attributes (fieldAttrsFromJsf)', () => {
|
|
297
|
+
// This is necessary while we keep supporting "type", even if deprecated
|
|
298
|
+
// otherwise our Remote app will break because it didn't migrate
|
|
299
|
+
// from "type" to "inputType" yet.
|
|
300
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
301
|
+
{
|
|
302
|
+
properties: {
|
|
303
|
+
is_full_time: { type: 'string', oneOf: [{ const: 'yes' }, { const: 'no' }] },
|
|
304
|
+
salary_period: {
|
|
305
|
+
type: 'string',
|
|
306
|
+
title: 'Salary period',
|
|
307
|
+
oneOf: [
|
|
308
|
+
{ title: 'Weekly', const: 'weekly' },
|
|
309
|
+
{ title: 'Monthly', const: 'monthly' },
|
|
310
|
+
],
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
allOf: [
|
|
314
|
+
{
|
|
315
|
+
if: {
|
|
316
|
+
properties: { is_full_time: { const: 'yes' } },
|
|
317
|
+
required: ['is_full_time'],
|
|
318
|
+
},
|
|
319
|
+
then: {
|
|
320
|
+
properties: {
|
|
321
|
+
salary_period: {
|
|
322
|
+
description: 'We recommend montlhy.',
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
],
|
|
328
|
+
},
|
|
329
|
+
{ strictInputType: false }
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
// Given "Yes" it keeps the "type"
|
|
333
|
+
handleValidation({ is_full_time: 'yes' });
|
|
334
|
+
|
|
335
|
+
// All the following attrs are never removed
|
|
336
|
+
// during conditionals because they are core.
|
|
337
|
+
expect(fields[1]).toMatchObject({
|
|
338
|
+
name: 'salary_period',
|
|
339
|
+
label: 'Salary period',
|
|
340
|
+
required: false,
|
|
341
|
+
type: 'radio',
|
|
342
|
+
inputType: 'radio',
|
|
343
|
+
jsonType: 'string',
|
|
344
|
+
computedAttributes: {},
|
|
345
|
+
calculateConditionalProperties: expect.any(Function),
|
|
346
|
+
schema: expect.any(Object),
|
|
347
|
+
scopedJsonSchema: expect.any(Object),
|
|
348
|
+
isVisible: true,
|
|
349
|
+
options: [
|
|
350
|
+
{
|
|
351
|
+
label: 'Weekly',
|
|
352
|
+
value: 'weekly',
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
label: 'Monthly',
|
|
356
|
+
value: 'monthly',
|
|
357
|
+
},
|
|
358
|
+
],
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
});
|