@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
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
schemaInputTypeRadioOptionsWithDetails,
|
|
16
16
|
schemaInputTypeSelectSoloDeprecated,
|
|
17
17
|
schemaInputTypeSelectSolo,
|
|
18
|
+
schemaInputTypeSelectString,
|
|
18
19
|
schemaInputTypeSelectMultipleDeprecated,
|
|
19
20
|
schemaInputTypeSelectMultiple,
|
|
20
21
|
schemaInputTypeSelectMultipleOptional,
|
|
@@ -38,7 +39,6 @@ import {
|
|
|
38
39
|
mockFileInput,
|
|
39
40
|
mockRadioCardInput,
|
|
40
41
|
mockRadioCardExpandableInput,
|
|
41
|
-
mockTelWithPattern,
|
|
42
42
|
mockTextInput,
|
|
43
43
|
mockTextInputDeprecated,
|
|
44
44
|
mockNumberInput,
|
|
@@ -431,7 +431,7 @@ describe('createHeadlessForm', () => {
|
|
|
431
431
|
});
|
|
432
432
|
|
|
433
433
|
describe('field support', () => {
|
|
434
|
-
function assertOptionsAllowed({ handleValidation, fieldName, validOptions }) {
|
|
434
|
+
function assertOptionsAllowed({ handleValidation, fieldName, validOptions, isString = false }) {
|
|
435
435
|
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
436
436
|
|
|
437
437
|
// All allowed options are valid
|
|
@@ -439,27 +439,34 @@ describe('createHeadlessForm', () => {
|
|
|
439
439
|
expect(validateForm({ [fieldName]: value })).toBeUndefined();
|
|
440
440
|
});
|
|
441
441
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
[fieldName]: '
|
|
445
|
-
|
|
442
|
+
if (!isString) {
|
|
443
|
+
// Any other arbitrary value is not valid.
|
|
444
|
+
expect(validateForm({ [fieldName]: 'blah-blah' })).toEqual({
|
|
445
|
+
[fieldName]: 'The option "blah-blah" is not valid.',
|
|
446
|
+
});
|
|
446
447
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
448
|
+
// Given undefined, it says it's a required field.
|
|
449
|
+
expect(validateForm({})).toEqual({
|
|
450
|
+
[fieldName]: 'Required field',
|
|
451
|
+
});
|
|
451
452
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
453
|
+
// As required field, empty string ("") is also considered empty. @BUG RMT-518
|
|
454
|
+
// Expectation: The error to be "The option '' is not valid."
|
|
455
|
+
expect(validateForm({ [fieldName]: '' })).toEqual({
|
|
456
|
+
[fieldName]: 'Required field',
|
|
457
|
+
});
|
|
457
458
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
459
|
+
// As required field, null is also considered empty @BUG RMT-518
|
|
460
|
+
// Expectation: The error to be "The option null is not valid."
|
|
461
|
+
expect(validateForm({ [fieldName]: null })).toEqual({
|
|
462
|
+
[fieldName]: 'Required field',
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (isString) {
|
|
467
|
+
// Any other arbitrary value is valid.
|
|
468
|
+
expect(validateForm({ [fieldName]: 'blah-blah' })).toBeUndefined();
|
|
469
|
+
}
|
|
463
470
|
}
|
|
464
471
|
|
|
465
472
|
it('support "text" field type', () => {
|
|
@@ -631,6 +638,41 @@ describe('createHeadlessForm', () => {
|
|
|
631
638
|
});
|
|
632
639
|
});
|
|
633
640
|
|
|
641
|
+
it('supports "select" field type with string option', () => {
|
|
642
|
+
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeSelectString);
|
|
643
|
+
const fieldSelect = fields[0];
|
|
644
|
+
expect(fieldSelect).toMatchObject({
|
|
645
|
+
name: 'browsers',
|
|
646
|
+
label: 'Browsers (solo)',
|
|
647
|
+
description: 'This solo select also includes a disabled option.',
|
|
648
|
+
options: [
|
|
649
|
+
{
|
|
650
|
+
value: 'chr',
|
|
651
|
+
label: 'Chrome',
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
value: 'ff',
|
|
655
|
+
label: 'Firefox',
|
|
656
|
+
},
|
|
657
|
+
{
|
|
658
|
+
value: 'ie',
|
|
659
|
+
label: 'Internet Explorer',
|
|
660
|
+
disabled: true,
|
|
661
|
+
},
|
|
662
|
+
{ value: undefined, type: 'string', label: '{Create another}' },
|
|
663
|
+
],
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
expect(fieldSelect).not.toHaveProperty('multiple');
|
|
667
|
+
|
|
668
|
+
assertOptionsAllowed({
|
|
669
|
+
handleValidation,
|
|
670
|
+
fieldName: 'browsers',
|
|
671
|
+
validOptions: ['chr', 'ff', 'ie'],
|
|
672
|
+
isString: true,
|
|
673
|
+
});
|
|
674
|
+
});
|
|
675
|
+
|
|
634
676
|
it('supports "select" field type with multiple options @deprecated', () => {
|
|
635
677
|
const result = createHeadlessForm(schemaInputTypeSelectMultipleDeprecated);
|
|
636
678
|
expect(result).toMatchObject({
|
|
@@ -813,6 +855,7 @@ describe('createHeadlessForm', () => {
|
|
|
813
855
|
has_car: 'yes',
|
|
814
856
|
})
|
|
815
857
|
).toBeUndefined();
|
|
858
|
+
|
|
816
859
|
expect(validateForm({})).toEqual({
|
|
817
860
|
has_siblings: 'Required field',
|
|
818
861
|
});
|
|
@@ -1376,6 +1419,50 @@ describe('createHeadlessForm', () => {
|
|
|
1376
1419
|
],
|
|
1377
1420
|
});
|
|
1378
1421
|
});
|
|
1422
|
+
|
|
1423
|
+
it('can be a conditional field', () => {
|
|
1424
|
+
const { fields, handleValidation } = createHeadlessForm({
|
|
1425
|
+
properties: {
|
|
1426
|
+
yes_or_no: {
|
|
1427
|
+
title: 'Show the dependents or not?',
|
|
1428
|
+
oneOf: [{ const: 'yes' }, { const: 'no' }],
|
|
1429
|
+
'x-jsf-presentation': { inputType: 'radio' },
|
|
1430
|
+
},
|
|
1431
|
+
dependent_details: mockGroupArrayInput,
|
|
1432
|
+
},
|
|
1433
|
+
allOf: [
|
|
1434
|
+
{
|
|
1435
|
+
if: {
|
|
1436
|
+
properties: {
|
|
1437
|
+
yes_or_no: { const: 'yes' },
|
|
1438
|
+
},
|
|
1439
|
+
required: ['yes_or_no'],
|
|
1440
|
+
},
|
|
1441
|
+
then: {
|
|
1442
|
+
required: ['dependent_details'],
|
|
1443
|
+
},
|
|
1444
|
+
else: {
|
|
1445
|
+
properties: {
|
|
1446
|
+
dependent_details: false,
|
|
1447
|
+
},
|
|
1448
|
+
},
|
|
1449
|
+
},
|
|
1450
|
+
],
|
|
1451
|
+
});
|
|
1452
|
+
|
|
1453
|
+
// By default is hidden but the fields are accessible
|
|
1454
|
+
expect(getField(fields, 'dependent_details').isVisible).toBe(false);
|
|
1455
|
+
expect(getField(fields, 'dependent_details').fields).toEqual(expect.any(Function));
|
|
1456
|
+
|
|
1457
|
+
// When the condition matches...
|
|
1458
|
+
const { formErrors } = handleValidation({ yes_or_no: 'yes' });
|
|
1459
|
+
expect(formErrors).toEqual({
|
|
1460
|
+
dependent_details: 'Required field',
|
|
1461
|
+
});
|
|
1462
|
+
// it gets visible with its inner fields.
|
|
1463
|
+
expect(getField(fields, 'dependent_details').isVisible).toBe(true);
|
|
1464
|
+
expect(getField(fields, 'dependent_details').fields).toEqual(expect.any(Function));
|
|
1465
|
+
});
|
|
1379
1466
|
});
|
|
1380
1467
|
|
|
1381
1468
|
it('supports "radio" field type with its "card" and "card-expandable" variants', () => {
|
|
@@ -1443,51 +1530,6 @@ describe('createHeadlessForm', () => {
|
|
|
1443
1530
|
});
|
|
1444
1531
|
});
|
|
1445
1532
|
|
|
1446
|
-
it('supports oneOf pattern validation', () => {
|
|
1447
|
-
const result = createHeadlessForm(mockTelWithPattern);
|
|
1448
|
-
|
|
1449
|
-
expect(result).toMatchObject({
|
|
1450
|
-
fields: [
|
|
1451
|
-
{
|
|
1452
|
-
label: 'Phone number',
|
|
1453
|
-
name: 'phone_number',
|
|
1454
|
-
type: 'tel',
|
|
1455
|
-
required: false,
|
|
1456
|
-
options: [
|
|
1457
|
-
{
|
|
1458
|
-
label: 'Portugal',
|
|
1459
|
-
pattern: '^(\\+351)[0-9]{9,}$',
|
|
1460
|
-
},
|
|
1461
|
-
{
|
|
1462
|
-
label: 'United Kingdom (UK)',
|
|
1463
|
-
pattern: '^(\\+44)[0-9]{1,}$',
|
|
1464
|
-
},
|
|
1465
|
-
{
|
|
1466
|
-
label: 'Bolivia',
|
|
1467
|
-
pattern: '^(\\+591)[0-9]{9,}$',
|
|
1468
|
-
},
|
|
1469
|
-
{
|
|
1470
|
-
label: 'Canada',
|
|
1471
|
-
pattern: '^(\\+1)(206|224)[0-9]{1,}$',
|
|
1472
|
-
},
|
|
1473
|
-
{
|
|
1474
|
-
label: 'United States',
|
|
1475
|
-
pattern: '^(\\+1)[0-9]{1,}$',
|
|
1476
|
-
},
|
|
1477
|
-
],
|
|
1478
|
-
},
|
|
1479
|
-
],
|
|
1480
|
-
});
|
|
1481
|
-
|
|
1482
|
-
const fieldValidator = result.fields[0].schema;
|
|
1483
|
-
|
|
1484
|
-
expect(fieldValidator.isValidSync('+351123123123')).toBe(true);
|
|
1485
|
-
expect(() => fieldValidator.validateSync('+35100')).toThrowError(
|
|
1486
|
-
'The option "+35100" is not valid.'
|
|
1487
|
-
);
|
|
1488
|
-
expect(fieldValidator.isValidSync(undefined)).toBe(true);
|
|
1489
|
-
});
|
|
1490
|
-
|
|
1491
1533
|
describe('supports "fieldset" field type', () => {
|
|
1492
1534
|
it('supports basic case', () => {
|
|
1493
1535
|
const result = createHeadlessForm({
|
|
@@ -1765,11 +1807,8 @@ describe('createHeadlessForm', () => {
|
|
|
1765
1807
|
expect(foodField.options).toHaveLength(4);
|
|
1766
1808
|
// ...Food description was back to the original
|
|
1767
1809
|
expect(foodField.description).toBeUndefined();
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
expect(getField(fields, 'pto').description).toBe(
|
|
1771
|
-
'Above 30 hours, the PTO needs to be at least 20 days.'
|
|
1772
|
-
);
|
|
1810
|
+
// ...PTO Description is removed too.
|
|
1811
|
+
expect(getField(fields, 'pto').description).toBeUndefined();
|
|
1773
1812
|
|
|
1774
1813
|
// Given again "low perks", the form valid.
|
|
1775
1814
|
expect(
|
package/src/tests/helpers.js
CHANGED
|
@@ -238,6 +238,11 @@ export const mockSelectInputSolo = {
|
|
|
238
238
|
},
|
|
239
239
|
};
|
|
240
240
|
|
|
241
|
+
export const mockSelectInputSoloCreatable = {
|
|
242
|
+
...mockSelectInputSolo,
|
|
243
|
+
oneOf: [...mockSelectInputSolo.oneOf, { type: 'string', title: '{Create another}' }],
|
|
244
|
+
};
|
|
245
|
+
|
|
241
246
|
export const mockSelectInputMultiple = {
|
|
242
247
|
title: 'Browsers (multiple)',
|
|
243
248
|
description: 'This multi-select also includes a disabled option.',
|
|
@@ -453,46 +458,6 @@ export const mockCheckboxInput = {
|
|
|
453
458
|
type: 'string',
|
|
454
459
|
};
|
|
455
460
|
|
|
456
|
-
export const mockTelWithPattern = {
|
|
457
|
-
properties: {
|
|
458
|
-
phone_number: {
|
|
459
|
-
title: 'Phone number',
|
|
460
|
-
description: 'Enter your telephone number',
|
|
461
|
-
type: 'string',
|
|
462
|
-
'x-jsf-presentation': {
|
|
463
|
-
inputType: 'tel',
|
|
464
|
-
},
|
|
465
|
-
oneOf: [
|
|
466
|
-
{
|
|
467
|
-
title: 'Portugal',
|
|
468
|
-
pattern: '^(\\+351)[0-9]{9,}$',
|
|
469
|
-
'x-jsf-presentation': { meta: { countryCode: '351' } },
|
|
470
|
-
},
|
|
471
|
-
{
|
|
472
|
-
title: 'United Kingdom (UK)',
|
|
473
|
-
pattern: '^(\\+44)[0-9]{1,}$',
|
|
474
|
-
'x-jsf-presentation': { meta: { countryCode: '44' } },
|
|
475
|
-
},
|
|
476
|
-
{
|
|
477
|
-
title: 'Bolivia',
|
|
478
|
-
pattern: '^(\\+591)[0-9]{9,}$',
|
|
479
|
-
'x-jsf-presentation': { meta: { countryCode: '591' } },
|
|
480
|
-
},
|
|
481
|
-
{
|
|
482
|
-
title: 'Canada',
|
|
483
|
-
pattern: '^(\\+1)(206|224)[0-9]{1,}$',
|
|
484
|
-
'x-jsf-presentation': { meta: { countryCode: '1' } },
|
|
485
|
-
},
|
|
486
|
-
{
|
|
487
|
-
title: 'United States',
|
|
488
|
-
pattern: '^(\\+1)[0-9]{1,}$',
|
|
489
|
-
'x-jsf-presentation': { meta: { countryCode: '1' } },
|
|
490
|
-
},
|
|
491
|
-
],
|
|
492
|
-
},
|
|
493
|
-
},
|
|
494
|
-
};
|
|
495
|
-
|
|
496
461
|
/**
|
|
497
462
|
* Compose a schema with lower chance of human error
|
|
498
463
|
* @param {Object} schema version
|
|
@@ -937,6 +902,10 @@ export const schemaInputTypeSelectSolo = JSONSchemaBuilder()
|
|
|
937
902
|
.setRequiredFields(['browsers'])
|
|
938
903
|
.build();
|
|
939
904
|
|
|
905
|
+
export const schemaInputTypeSelectString = JSONSchemaBuilder().addInput({
|
|
906
|
+
browsers: mockSelectInputSoloCreatable,
|
|
907
|
+
});
|
|
908
|
+
|
|
940
909
|
/** @deprecated */
|
|
941
910
|
export const schemaInputTypeSelectMultipleDeprecated = JSONSchemaBuilder()
|
|
942
911
|
.addInput({
|