@remoteoss/json-schema-form 0.11.9-dev.20241210213029 → 0.11.10-beta.0
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 +26 -0
- package/dist/index.cjs +14 -39
- package/dist/index.js +14 -39
- package/dist/standalone.js +14 -39
- package/package.json +2 -2
- package/src/tests/checkIfConditionMatches.test.js +59 -45
- package/src/tests/conditions.test.js +238 -122
- package/src/tests/createHeadlessForm.customValidations.test.js +2 -1
- package/src/tests/createHeadlessForm.test.js +1077 -1077
- package/src/tests/helpers.js +37 -0
- package/src/tests/utils.test.jsx +1 -1
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
schemaInputWithStatement,
|
|
32
32
|
schemaInputTypeCheckbox,
|
|
33
33
|
schemaInputTypeCheckboxBooleans,
|
|
34
|
+
schemaInputTypeCheckboxBooleanConditional,
|
|
34
35
|
schemaInputTypeNull,
|
|
35
36
|
schemaWithOrderKeyword,
|
|
36
37
|
schemaWithPositionDeprecated,
|
|
@@ -500,450 +501,450 @@ describe('createHeadlessForm', () => {
|
|
|
500
501
|
expect(() => fieldValidator.validateSync('')).toThrowError('Required field');
|
|
501
502
|
});
|
|
502
503
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
})
|
|
509
|
-
.setRequiredFields(['username'])
|
|
510
|
-
.build()
|
|
511
|
-
);
|
|
512
|
-
|
|
513
|
-
expect(resultsWithRootDescription.fields[0].description).toMatch(/your username/i);
|
|
504
|
+
describe('support "select" field type', () => {
|
|
505
|
+
it('support "select" field type @deprecated', () => {
|
|
506
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
507
|
+
schemaInputTypeSelectSoloDeprecated
|
|
508
|
+
);
|
|
514
509
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
510
|
+
expect(fields).toMatchObject([
|
|
511
|
+
{
|
|
512
|
+
description: 'Life Insurance',
|
|
513
|
+
label: 'Benefits (solo)',
|
|
514
|
+
name: 'benefits',
|
|
515
|
+
placeholder: 'Select...',
|
|
516
|
+
type: 'select',
|
|
517
|
+
options: [
|
|
518
|
+
{
|
|
519
|
+
label: 'Medical Insurance',
|
|
520
|
+
value: 'Medical Insurance',
|
|
525
521
|
},
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
.build()
|
|
530
|
-
);
|
|
531
|
-
|
|
532
|
-
expect(resultsWithPresentationDescription.fields[0].description).toMatch(
|
|
533
|
-
/a different description /i
|
|
534
|
-
);
|
|
535
|
-
});
|
|
536
|
-
|
|
537
|
-
it('supports both root level "description" and "presentation.description" (deprecated)', () => {
|
|
538
|
-
const resultsWithRootDescription = createHeadlessForm(
|
|
539
|
-
JSONSchemaBuilder()
|
|
540
|
-
.addInput({
|
|
541
|
-
username: mockTextInputDeprecated,
|
|
542
|
-
})
|
|
543
|
-
.setRequiredFields(['username'])
|
|
544
|
-
.build()
|
|
545
|
-
);
|
|
546
|
-
|
|
547
|
-
expect(resultsWithRootDescription.fields[0].description).toMatch(/your username/i);
|
|
548
|
-
|
|
549
|
-
const resultsWithPresentationDescription = createHeadlessForm(
|
|
550
|
-
JSONSchemaBuilder()
|
|
551
|
-
.addInput({
|
|
552
|
-
username: {
|
|
553
|
-
...mockTextInputDeprecated,
|
|
554
|
-
presentation: {
|
|
555
|
-
inputType: 'text',
|
|
556
|
-
maskSecret: 2,
|
|
557
|
-
// should override the root level description
|
|
558
|
-
description: 'a different description with <span>markup</span>',
|
|
522
|
+
{
|
|
523
|
+
label: 'Health Insurance',
|
|
524
|
+
value: 'Health Insurance',
|
|
559
525
|
},
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
526
|
+
{
|
|
527
|
+
label: 'Travel Bonus',
|
|
528
|
+
value: 'Travel Bonus',
|
|
529
|
+
},
|
|
530
|
+
],
|
|
531
|
+
},
|
|
532
|
+
]);
|
|
565
533
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
534
|
+
assertOptionsAllowed({
|
|
535
|
+
handleValidation,
|
|
536
|
+
fieldName: 'benefits',
|
|
537
|
+
validOptions: ['Medical Insurance', 'Health Insurance', 'Travel Bonus'],
|
|
538
|
+
});
|
|
539
|
+
});
|
|
570
540
|
|
|
571
|
-
|
|
572
|
-
|
|
541
|
+
it('support "select" field type', () => {
|
|
542
|
+
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeSelectSolo);
|
|
573
543
|
|
|
574
|
-
|
|
575
|
-
{
|
|
576
|
-
|
|
577
|
-
label: '
|
|
578
|
-
|
|
579
|
-
placeholder: 'Select...',
|
|
580
|
-
type: 'select',
|
|
544
|
+
const fieldSelect = fields[0];
|
|
545
|
+
expect(fieldSelect).toMatchObject({
|
|
546
|
+
name: 'browsers',
|
|
547
|
+
label: 'Browsers (solo)',
|
|
548
|
+
description: 'This solo select also includes a disabled option.',
|
|
581
549
|
options: [
|
|
582
550
|
{
|
|
583
|
-
|
|
584
|
-
|
|
551
|
+
value: 'chr',
|
|
552
|
+
label: 'Chrome',
|
|
585
553
|
},
|
|
586
554
|
{
|
|
587
|
-
|
|
588
|
-
|
|
555
|
+
value: 'ff',
|
|
556
|
+
label: 'Firefox',
|
|
589
557
|
},
|
|
590
558
|
{
|
|
591
|
-
|
|
592
|
-
|
|
559
|
+
value: 'ie',
|
|
560
|
+
label: 'Internet Explorer',
|
|
561
|
+
disabled: true,
|
|
593
562
|
},
|
|
594
563
|
],
|
|
595
|
-
}
|
|
596
|
-
]);
|
|
597
|
-
|
|
598
|
-
assertOptionsAllowed({
|
|
599
|
-
handleValidation,
|
|
600
|
-
fieldName: 'benefits',
|
|
601
|
-
validOptions: ['Medical Insurance', 'Health Insurance', 'Travel Bonus'],
|
|
602
|
-
});
|
|
603
|
-
});
|
|
564
|
+
});
|
|
604
565
|
|
|
605
|
-
|
|
606
|
-
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeSelectSolo);
|
|
566
|
+
expect(fieldSelect).not.toHaveProperty('multiple');
|
|
607
567
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
options: [
|
|
614
|
-
{
|
|
615
|
-
value: 'chr',
|
|
616
|
-
label: 'Chrome',
|
|
617
|
-
},
|
|
618
|
-
{
|
|
619
|
-
value: 'ff',
|
|
620
|
-
label: 'Firefox',
|
|
621
|
-
},
|
|
622
|
-
{
|
|
623
|
-
value: 'ie',
|
|
624
|
-
label: 'Internet Explorer',
|
|
625
|
-
disabled: true,
|
|
626
|
-
},
|
|
627
|
-
],
|
|
568
|
+
assertOptionsAllowed({
|
|
569
|
+
handleValidation,
|
|
570
|
+
fieldName: 'browsers',
|
|
571
|
+
validOptions: ['chr', 'ff', 'ie'],
|
|
572
|
+
});
|
|
628
573
|
});
|
|
629
574
|
|
|
630
|
-
|
|
575
|
+
it('supports "select" field type with multiple options @deprecated', () => {
|
|
576
|
+
const result = createHeadlessForm(schemaInputTypeSelectMultipleDeprecated);
|
|
577
|
+
expect(result).toMatchObject({
|
|
578
|
+
fields: [
|
|
579
|
+
{
|
|
580
|
+
description: 'Life Insurance',
|
|
581
|
+
label: 'Benefits (multiple)',
|
|
582
|
+
name: 'benefits_multi',
|
|
583
|
+
placeholder: 'Select...',
|
|
584
|
+
type: 'select',
|
|
585
|
+
options: [
|
|
586
|
+
{
|
|
587
|
+
label: 'Medical Insurance',
|
|
588
|
+
value: 'Medical Insurance',
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
label: 'Health Insurance',
|
|
592
|
+
value: 'Health Insurance',
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
label: 'Travel Bonus',
|
|
596
|
+
value: 'Travel Bonus',
|
|
597
|
+
},
|
|
598
|
+
],
|
|
599
|
+
multiple: true,
|
|
600
|
+
},
|
|
601
|
+
],
|
|
602
|
+
});
|
|
603
|
+
});
|
|
604
|
+
it('supports "select" field type with multiple options', () => {
|
|
605
|
+
const result = createHeadlessForm(schemaInputTypeSelectMultiple);
|
|
606
|
+
expect(result).toMatchObject({
|
|
607
|
+
fields: [
|
|
608
|
+
{
|
|
609
|
+
name: 'browsers_multi',
|
|
610
|
+
label: 'Browsers (multiple)',
|
|
611
|
+
description: 'This multi-select also includes a disabled option.',
|
|
612
|
+
options: [
|
|
613
|
+
{
|
|
614
|
+
value: 'chr',
|
|
615
|
+
label: 'Chrome',
|
|
616
|
+
},
|
|
617
|
+
{
|
|
618
|
+
value: 'ff',
|
|
619
|
+
label: 'Firefox',
|
|
620
|
+
},
|
|
621
|
+
{
|
|
622
|
+
value: 'ie',
|
|
623
|
+
label: 'Internet Explorer',
|
|
624
|
+
disabled: true,
|
|
625
|
+
},
|
|
626
|
+
],
|
|
627
|
+
multiple: true,
|
|
628
|
+
},
|
|
629
|
+
],
|
|
630
|
+
});
|
|
631
|
+
});
|
|
631
632
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
633
|
+
it('supports "select" field type with multiple options and optional', () => {
|
|
634
|
+
const result = createHeadlessForm(schemaInputTypeSelectMultipleOptional);
|
|
635
|
+
expect(result).toMatchObject({
|
|
636
|
+
fields: [
|
|
637
|
+
{
|
|
638
|
+
name: 'browsers_multi_optional',
|
|
639
|
+
label: 'Browsers (multiple) (optional)',
|
|
640
|
+
description: 'This optional multi-select also includes a disabled option.',
|
|
641
|
+
options: [
|
|
642
|
+
{
|
|
643
|
+
value: 'chr',
|
|
644
|
+
label: 'Chrome',
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
value: 'ff',
|
|
648
|
+
label: 'Firefox',
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
value: 'ie',
|
|
652
|
+
label: 'Internet Explorer',
|
|
653
|
+
disabled: true,
|
|
654
|
+
},
|
|
655
|
+
],
|
|
656
|
+
multiple: true,
|
|
657
|
+
},
|
|
658
|
+
],
|
|
659
|
+
});
|
|
636
660
|
});
|
|
637
661
|
});
|
|
662
|
+
describe('support "radio" field type', () => {
|
|
663
|
+
it('support "radio" field type @deprecated', () => {
|
|
664
|
+
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeRadioDeprecated);
|
|
638
665
|
|
|
639
|
-
|
|
640
|
-
const result = createHeadlessForm(schemaInputTypeSelectMultipleDeprecated);
|
|
641
|
-
expect(result).toMatchObject({
|
|
642
|
-
fields: [
|
|
666
|
+
expect(fields).toMatchObject([
|
|
643
667
|
{
|
|
644
|
-
description: '
|
|
645
|
-
label: '
|
|
646
|
-
name: '
|
|
647
|
-
placeholder: 'Select...',
|
|
648
|
-
type: 'select',
|
|
668
|
+
description: 'Do you have any siblings?',
|
|
669
|
+
label: 'Has siblings',
|
|
670
|
+
name: 'has_siblings',
|
|
649
671
|
options: [
|
|
650
672
|
{
|
|
651
|
-
label: '
|
|
652
|
-
value: '
|
|
673
|
+
label: 'Yes',
|
|
674
|
+
value: 'yes',
|
|
653
675
|
},
|
|
654
676
|
{
|
|
655
|
-
label: '
|
|
656
|
-
value: '
|
|
657
|
-
},
|
|
658
|
-
{
|
|
659
|
-
label: 'Travel Bonus',
|
|
660
|
-
value: 'Travel Bonus',
|
|
677
|
+
label: 'No',
|
|
678
|
+
value: 'no',
|
|
661
679
|
},
|
|
662
680
|
],
|
|
663
|
-
|
|
681
|
+
required: true,
|
|
682
|
+
schema: expect.any(Object),
|
|
683
|
+
type: 'radio',
|
|
664
684
|
},
|
|
665
|
-
]
|
|
685
|
+
]);
|
|
686
|
+
|
|
687
|
+
assertOptionsAllowed({
|
|
688
|
+
handleValidation,
|
|
689
|
+
fieldName: 'has_siblings',
|
|
690
|
+
validOptions: ['yes', 'no'],
|
|
691
|
+
});
|
|
666
692
|
});
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
fields: [
|
|
693
|
+
it('support "radio" field string type', () => {
|
|
694
|
+
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeRadioString);
|
|
695
|
+
|
|
696
|
+
expect(fields).toMatchObject([
|
|
672
697
|
{
|
|
673
|
-
|
|
674
|
-
label: '
|
|
675
|
-
|
|
698
|
+
description: 'Do you have any siblings?',
|
|
699
|
+
label: 'Has siblings',
|
|
700
|
+
name: 'has_siblings',
|
|
676
701
|
options: [
|
|
677
702
|
{
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
},
|
|
681
|
-
{
|
|
682
|
-
value: 'ff',
|
|
683
|
-
label: 'Firefox',
|
|
703
|
+
label: 'Yes',
|
|
704
|
+
value: 'yes',
|
|
684
705
|
},
|
|
685
706
|
{
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
disabled: true,
|
|
707
|
+
label: 'No',
|
|
708
|
+
value: 'no',
|
|
689
709
|
},
|
|
690
710
|
],
|
|
691
|
-
|
|
711
|
+
required: true,
|
|
712
|
+
schema: expect.any(Object),
|
|
713
|
+
type: 'radio',
|
|
692
714
|
},
|
|
693
|
-
]
|
|
715
|
+
]);
|
|
716
|
+
|
|
717
|
+
assertOptionsAllowed({
|
|
718
|
+
handleValidation,
|
|
719
|
+
fieldName: 'has_siblings',
|
|
720
|
+
validOptions: ['yes', 'no'],
|
|
721
|
+
});
|
|
694
722
|
});
|
|
695
|
-
});
|
|
696
723
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
724
|
+
it('support "radio" field boolean type', () => {
|
|
725
|
+
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeRadioBoolean);
|
|
726
|
+
|
|
727
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
728
|
+
|
|
729
|
+
expect(fields).toMatchObject([
|
|
701
730
|
{
|
|
702
|
-
|
|
703
|
-
label: '
|
|
704
|
-
|
|
731
|
+
description: 'Are you over 18 years old?',
|
|
732
|
+
label: 'Over 18',
|
|
733
|
+
name: 'over_18',
|
|
705
734
|
options: [
|
|
706
735
|
{
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
},
|
|
710
|
-
{
|
|
711
|
-
value: 'ff',
|
|
712
|
-
label: 'Firefox',
|
|
736
|
+
label: 'Yes',
|
|
737
|
+
value: true,
|
|
713
738
|
},
|
|
714
739
|
{
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
disabled: true,
|
|
740
|
+
label: 'No',
|
|
741
|
+
value: false,
|
|
718
742
|
},
|
|
719
743
|
],
|
|
720
|
-
|
|
744
|
+
required: true,
|
|
745
|
+
schema: expect.any(Object),
|
|
746
|
+
type: 'radio',
|
|
721
747
|
},
|
|
722
|
-
]
|
|
723
|
-
});
|
|
724
|
-
});
|
|
725
|
-
|
|
726
|
-
it('support "radio" field type @deprecated', () => {
|
|
727
|
-
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeRadioDeprecated);
|
|
728
|
-
|
|
729
|
-
expect(fields).toMatchObject([
|
|
730
|
-
{
|
|
731
|
-
description: 'Do you have any siblings?',
|
|
732
|
-
label: 'Has siblings',
|
|
733
|
-
name: 'has_siblings',
|
|
734
|
-
options: [
|
|
735
|
-
{
|
|
736
|
-
label: 'Yes',
|
|
737
|
-
value: 'yes',
|
|
738
|
-
},
|
|
739
|
-
{
|
|
740
|
-
label: 'No',
|
|
741
|
-
value: 'no',
|
|
742
|
-
},
|
|
743
|
-
],
|
|
744
|
-
required: true,
|
|
745
|
-
schema: expect.any(Object),
|
|
746
|
-
type: 'radio',
|
|
747
|
-
},
|
|
748
|
-
]);
|
|
749
|
-
|
|
750
|
-
assertOptionsAllowed({
|
|
751
|
-
handleValidation,
|
|
752
|
-
fieldName: 'has_siblings',
|
|
753
|
-
validOptions: ['yes', 'no'],
|
|
754
|
-
});
|
|
755
|
-
});
|
|
756
|
-
it('support "radio" field string type', () => {
|
|
757
|
-
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeRadioString);
|
|
748
|
+
]);
|
|
758
749
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
{
|
|
766
|
-
label: 'Yes',
|
|
767
|
-
value: 'yes',
|
|
768
|
-
},
|
|
769
|
-
{
|
|
770
|
-
label: 'No',
|
|
771
|
-
value: 'no',
|
|
772
|
-
},
|
|
773
|
-
],
|
|
774
|
-
required: true,
|
|
775
|
-
schema: expect.any(Object),
|
|
776
|
-
type: 'radio',
|
|
777
|
-
},
|
|
778
|
-
]);
|
|
750
|
+
assertOptionsAllowed({
|
|
751
|
+
handleValidation,
|
|
752
|
+
fieldName: 'over_18',
|
|
753
|
+
validOptions: [true, false],
|
|
754
|
+
type: schemaInputTypeRadioBoolean.properties.over_18.type,
|
|
755
|
+
});
|
|
779
756
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
validOptions: ['yes', 'no'],
|
|
757
|
+
expect(validateForm({ over_18: 'true' })).toEqual({
|
|
758
|
+
over_18: 'The option "true" is not valid.',
|
|
759
|
+
});
|
|
784
760
|
});
|
|
785
|
-
});
|
|
786
761
|
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
762
|
+
it('supports "radio" field type with its "card" and "card-expandable" variants', () => {
|
|
763
|
+
const result = createHeadlessForm(
|
|
764
|
+
JSONSchemaBuilder()
|
|
765
|
+
.addInput({
|
|
766
|
+
experience_level: mockRadioCardExpandableInput,
|
|
767
|
+
payment_method: mockRadioCardInput,
|
|
768
|
+
})
|
|
769
|
+
.build()
|
|
770
|
+
);
|
|
791
771
|
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
description: 'Are you over 18 years old?',
|
|
795
|
-
label: 'Over 18',
|
|
796
|
-
name: 'over_18',
|
|
797
|
-
options: [
|
|
772
|
+
expect(result).toMatchObject({
|
|
773
|
+
fields: [
|
|
798
774
|
{
|
|
799
|
-
|
|
800
|
-
|
|
775
|
+
description:
|
|
776
|
+
'Please select the experience level that aligns with this role based on the job description (not the employees overall experience)',
|
|
777
|
+
label: 'Experience level',
|
|
778
|
+
name: 'experience_level',
|
|
779
|
+
type: 'radio',
|
|
780
|
+
required: false,
|
|
781
|
+
variant: 'card-expandable',
|
|
782
|
+
options: [
|
|
783
|
+
{
|
|
784
|
+
label: 'Junior level',
|
|
785
|
+
value: 'junior',
|
|
786
|
+
description:
|
|
787
|
+
'Entry level employees who perform tasks under the supervision of a more experienced employee.',
|
|
788
|
+
},
|
|
789
|
+
{
|
|
790
|
+
label: 'Mid level',
|
|
791
|
+
value: 'mid',
|
|
792
|
+
description:
|
|
793
|
+
'Employees who perform tasks with a good degree of autonomy and/or with coordination and control functions.',
|
|
794
|
+
},
|
|
795
|
+
{
|
|
796
|
+
label: 'Senior level',
|
|
797
|
+
value: 'senior',
|
|
798
|
+
description:
|
|
799
|
+
'Employees who perform tasks with a high degree of autonomy and/or with coordination and control functions.',
|
|
800
|
+
},
|
|
801
|
+
],
|
|
801
802
|
},
|
|
802
803
|
{
|
|
803
|
-
|
|
804
|
-
|
|
804
|
+
description: 'Chose how you want to be paid',
|
|
805
|
+
label: 'Payment method',
|
|
806
|
+
name: 'payment_method',
|
|
807
|
+
type: 'radio',
|
|
808
|
+
variant: 'card',
|
|
809
|
+
required: false,
|
|
810
|
+
options: [
|
|
811
|
+
{
|
|
812
|
+
label: 'Credit Card',
|
|
813
|
+
value: 'cc',
|
|
814
|
+
description: 'Plastic money, which is still money',
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
label: 'Cash',
|
|
818
|
+
value: 'cash',
|
|
819
|
+
description: 'Rules Everything Around Me',
|
|
820
|
+
},
|
|
821
|
+
],
|
|
805
822
|
},
|
|
806
823
|
],
|
|
807
|
-
|
|
808
|
-
schema: expect.any(Object),
|
|
809
|
-
type: 'radio',
|
|
810
|
-
},
|
|
811
|
-
]);
|
|
812
|
-
|
|
813
|
-
assertOptionsAllowed({
|
|
814
|
-
handleValidation,
|
|
815
|
-
fieldName: 'over_18',
|
|
816
|
-
validOptions: [true, false],
|
|
817
|
-
type: schemaInputTypeRadioBoolean.properties.over_18.type,
|
|
824
|
+
});
|
|
818
825
|
});
|
|
819
826
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
827
|
+
// @BUG COD-1859
|
|
828
|
+
// it should validate when type is string but value is not a boolean
|
|
829
|
+
it('support "radio" field string-y type', () => {
|
|
830
|
+
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeRadioStringY);
|
|
824
831
|
|
|
825
|
-
|
|
826
|
-
// it should validate when type is string but value is not a boolean
|
|
827
|
-
it('support "radio" field string-y type', () => {
|
|
828
|
-
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeRadioStringY);
|
|
829
|
-
|
|
830
|
-
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
832
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
831
833
|
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
834
|
+
expect(fields).toMatchObject([
|
|
835
|
+
{
|
|
836
|
+
description: 'Do you have any siblings?',
|
|
837
|
+
label: 'Has siblings',
|
|
838
|
+
name: 'has_siblings',
|
|
839
|
+
options: [
|
|
840
|
+
{
|
|
841
|
+
label: 'Yes',
|
|
842
|
+
value: 'true',
|
|
843
|
+
},
|
|
844
|
+
{
|
|
845
|
+
label: 'No',
|
|
846
|
+
value: 'false',
|
|
847
|
+
},
|
|
848
|
+
],
|
|
849
|
+
required: true,
|
|
850
|
+
schema: expect.any(Object),
|
|
851
|
+
type: 'radio',
|
|
852
|
+
},
|
|
853
|
+
]);
|
|
852
854
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
855
|
+
assertOptionsAllowed({
|
|
856
|
+
handleValidation,
|
|
857
|
+
fieldName: 'has_siblings',
|
|
858
|
+
validOptions: ['true', 'false'],
|
|
859
|
+
});
|
|
858
860
|
|
|
859
|
-
|
|
860
|
-
|
|
861
|
+
expect(validateForm({ has_siblings: false })).toEqual({
|
|
862
|
+
has_siblings: 'The option "false" is not valid.',
|
|
863
|
+
});
|
|
861
864
|
});
|
|
862
|
-
});
|
|
863
865
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
+
it('support "radio" field number type', () => {
|
|
867
|
+
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeRadioNumber);
|
|
866
868
|
|
|
867
|
-
|
|
869
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
868
870
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
871
|
+
expect(fields).toMatchObject([
|
|
872
|
+
{
|
|
873
|
+
description: 'How many siblings do you have?',
|
|
874
|
+
label: 'Number of siblings',
|
|
875
|
+
name: 'siblings_count',
|
|
876
|
+
options: [
|
|
877
|
+
{
|
|
878
|
+
label: 'One',
|
|
879
|
+
value: 1,
|
|
880
|
+
},
|
|
881
|
+
{
|
|
882
|
+
label: 'Two',
|
|
883
|
+
value: 2,
|
|
884
|
+
},
|
|
885
|
+
{
|
|
886
|
+
label: 'Three',
|
|
887
|
+
value: 3,
|
|
888
|
+
},
|
|
889
|
+
],
|
|
890
|
+
required: true,
|
|
891
|
+
schema: expect.any(Object),
|
|
892
|
+
type: 'radio',
|
|
893
|
+
},
|
|
894
|
+
]);
|
|
893
895
|
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
896
|
+
assertOptionsAllowed({
|
|
897
|
+
handleValidation,
|
|
898
|
+
fieldName: 'siblings_count',
|
|
899
|
+
validOptions: [1, 2, 3],
|
|
900
|
+
type: schemaInputTypeRadioNumber.properties.siblings_count.type,
|
|
901
|
+
});
|
|
900
902
|
|
|
901
|
-
|
|
902
|
-
|
|
903
|
+
expect(validateForm({ siblings_count: '3' })).toEqual({
|
|
904
|
+
siblings_count: 'The option "3" is not valid.',
|
|
905
|
+
});
|
|
903
906
|
});
|
|
904
|
-
});
|
|
905
907
|
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
908
|
+
it('support "radio" optional field', () => {
|
|
909
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
910
|
+
schemaInputTypeRadioRequiredAndOptional
|
|
911
|
+
);
|
|
912
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
911
913
|
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
914
|
+
expect(fields).toMatchObject([
|
|
915
|
+
{},
|
|
916
|
+
{
|
|
917
|
+
name: 'has_car',
|
|
918
|
+
label: 'Has car',
|
|
919
|
+
description: 'Do you have a car? (optional field, check oneOf)',
|
|
920
|
+
options: [
|
|
921
|
+
{
|
|
922
|
+
label: 'Yes',
|
|
923
|
+
value: 'yes',
|
|
924
|
+
},
|
|
925
|
+
{
|
|
926
|
+
label: 'No',
|
|
927
|
+
value: 'no',
|
|
928
|
+
},
|
|
929
|
+
],
|
|
930
|
+
required: false,
|
|
931
|
+
schema: expect.any(Object),
|
|
932
|
+
type: 'radio',
|
|
933
|
+
},
|
|
934
|
+
]);
|
|
933
935
|
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
936
|
+
expect(
|
|
937
|
+
validateForm({
|
|
938
|
+
has_siblings: 'yes',
|
|
939
|
+
has_car: 'yes',
|
|
940
|
+
})
|
|
941
|
+
).toBeUndefined();
|
|
940
942
|
|
|
941
|
-
|
|
942
|
-
|
|
943
|
+
expect(validateForm({})).toEqual({
|
|
944
|
+
has_siblings: 'Required field',
|
|
945
|
+
});
|
|
943
946
|
});
|
|
944
|
-
});
|
|
945
947
|
|
|
946
|
-
describe('support "radio" optional field - more examples @BUG RMT-518', () => {
|
|
947
948
|
function assertCommonBehavior(validateForm) {
|
|
948
949
|
// Note: Very similar to assertOptionsAllowed()
|
|
949
950
|
// We could reuse it in a next iteration.
|
|
@@ -969,13 +970,13 @@ describe('createHeadlessForm', () => {
|
|
|
969
970
|
expect(validateForm({ has_car: '' })).toBeUndefined();
|
|
970
971
|
}
|
|
971
972
|
|
|
972
|
-
it('
|
|
973
|
+
it('support "radio" optional field - optional (conventional way) - @BUG RMT-518', () => {
|
|
973
974
|
const { handleValidation } = createHeadlessForm(schemaInputRadioOptionalConventional);
|
|
974
975
|
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
975
976
|
|
|
976
977
|
assertCommonBehavior(validateForm);
|
|
977
978
|
|
|
978
|
-
// Accepts null, even though it
|
|
979
|
+
// Accepts null, even though it shouldn't @BUG RMT-518
|
|
979
980
|
// This is for cases where we (Remote) still have incorrect
|
|
980
981
|
// JSON Schemas in our Platform.
|
|
981
982
|
expect(validateForm({ has_car: null })).toBeUndefined();
|
|
@@ -986,53 +987,98 @@ describe('createHeadlessForm', () => {
|
|
|
986
987
|
// });
|
|
987
988
|
});
|
|
988
989
|
|
|
989
|
-
it('with null option (as Remote does)', () => {
|
|
990
|
+
it('support "radio" optional field - optional with null option (as Remote does) - @BUG RMT-518', () => {
|
|
990
991
|
const { handleValidation } = createHeadlessForm(schemaInputRadioOptionalNull);
|
|
991
992
|
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
992
993
|
|
|
993
|
-
assertCommonBehavior(validateForm);
|
|
994
|
+
assertCommonBehavior(validateForm);
|
|
995
|
+
|
|
996
|
+
// Accepts null value
|
|
997
|
+
expect(validateForm({ has_car: null })).toBeUndefined();
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
it('support "radio" field type with extra info inside each option', () => {
|
|
1001
|
+
const result = createHeadlessForm(schemaInputTypeRadioOptionsWithDetails);
|
|
1002
|
+
|
|
1003
|
+
expect(result.fields).toHaveLength(1);
|
|
1004
|
+
|
|
1005
|
+
const fieldOptions = result.fields[0].options;
|
|
1006
|
+
|
|
1007
|
+
// The x-jsf-presentation content was spread to the root:
|
|
1008
|
+
expect(fieldOptions[0]).not.toHaveProperty('x-jsf-presentation');
|
|
1009
|
+
expect(fieldOptions).toEqual([
|
|
1010
|
+
{
|
|
1011
|
+
label: 'Basic',
|
|
1012
|
+
value: 'basic',
|
|
1013
|
+
meta: {
|
|
1014
|
+
displayCost: '$30.00/mo',
|
|
1015
|
+
},
|
|
1016
|
+
// Other x-* keywords are kept as it is.
|
|
1017
|
+
'x-another': 'extra-thing',
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
label: 'Standard',
|
|
1021
|
+
value: 'standard',
|
|
1022
|
+
meta: {
|
|
1023
|
+
displayCost: '$50.00/mo',
|
|
1024
|
+
},
|
|
1025
|
+
},
|
|
1026
|
+
]);
|
|
1027
|
+
});
|
|
1028
|
+
|
|
1029
|
+
it('supports oneOf pattern validation', () => {
|
|
1030
|
+
const result = createHeadlessForm(mockTelWithPattern);
|
|
1031
|
+
|
|
1032
|
+
expect(result).toMatchObject({
|
|
1033
|
+
fields: [
|
|
1034
|
+
{
|
|
1035
|
+
label: 'Phone number',
|
|
1036
|
+
name: 'phone_number',
|
|
1037
|
+
type: 'tel',
|
|
1038
|
+
required: false,
|
|
1039
|
+
options: [
|
|
1040
|
+
{
|
|
1041
|
+
label: 'Portugal',
|
|
1042
|
+
pattern: '^(\\+351)[0-9]{9,}$',
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
label: 'United Kingdom (UK)',
|
|
1046
|
+
pattern: '^(\\+44)[0-9]{1,}$',
|
|
1047
|
+
},
|
|
1048
|
+
{
|
|
1049
|
+
label: 'Bolivia',
|
|
1050
|
+
pattern: '^(\\+591)[0-9]{9,}$',
|
|
1051
|
+
},
|
|
1052
|
+
{
|
|
1053
|
+
label: 'Canada',
|
|
1054
|
+
pattern: '^(\\+1)(206|224)[0-9]{1,}$',
|
|
1055
|
+
},
|
|
1056
|
+
{
|
|
1057
|
+
label: 'United States',
|
|
1058
|
+
pattern: '^(\\+1)[0-9]{1,}$',
|
|
1059
|
+
},
|
|
1060
|
+
],
|
|
1061
|
+
},
|
|
1062
|
+
],
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
const fieldValidator = result.fields[0].schema;
|
|
994
1066
|
|
|
995
|
-
|
|
996
|
-
expect(
|
|
1067
|
+
expect(fieldValidator.isValidSync('+351123123123')).toBe(true);
|
|
1068
|
+
expect(() => fieldValidator.validateSync('+35100')).toThrowError(
|
|
1069
|
+
'The option "+35100" is not valid.'
|
|
1070
|
+
);
|
|
1071
|
+
expect(fieldValidator.isValidSync(undefined)).toBe(true);
|
|
997
1072
|
});
|
|
998
|
-
});
|
|
999
|
-
|
|
1000
|
-
it('support "radio" field type with extra info inside each option', () => {
|
|
1001
|
-
const result = createHeadlessForm(schemaInputTypeRadioOptionsWithDetails);
|
|
1002
|
-
|
|
1003
|
-
expect(result.fields).toHaveLength(1);
|
|
1004
|
-
|
|
1005
|
-
const fieldOptions = result.fields[0].options;
|
|
1006
|
-
|
|
1007
|
-
// The x-jsf-presentation content was spread to the root:
|
|
1008
|
-
expect(fieldOptions[0]).not.toHaveProperty('x-jsf-presentation');
|
|
1009
|
-
expect(fieldOptions).toEqual([
|
|
1010
|
-
{
|
|
1011
|
-
label: 'Basic',
|
|
1012
|
-
value: 'basic',
|
|
1013
|
-
meta: {
|
|
1014
|
-
displayCost: '$30.00/mo',
|
|
1015
|
-
},
|
|
1016
|
-
// Other x-* keywords are kept as it is.
|
|
1017
|
-
'x-another': 'extra-thing',
|
|
1018
|
-
},
|
|
1019
|
-
{
|
|
1020
|
-
label: 'Standard',
|
|
1021
|
-
value: 'standard',
|
|
1022
|
-
meta: {
|
|
1023
|
-
displayCost: '$50.00/mo',
|
|
1024
|
-
},
|
|
1025
|
-
},
|
|
1026
|
-
]);
|
|
1027
|
-
});
|
|
1028
1073
|
|
|
1029
|
-
|
|
1030
|
-
|
|
1074
|
+
it('support "radio" field type without oneOf options', () => {
|
|
1075
|
+
const result = createHeadlessForm(schemaInputTypeRadioWithoutOptions);
|
|
1031
1076
|
|
|
1032
|
-
|
|
1077
|
+
expect(result.fields).toHaveLength(1);
|
|
1033
1078
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1079
|
+
const fieldOptions = result.fields[0].options;
|
|
1080
|
+
expect(fieldOptions).toEqual([]);
|
|
1081
|
+
});
|
|
1036
1082
|
});
|
|
1037
1083
|
|
|
1038
1084
|
it('support "integer" field type', () => {
|
|
@@ -1201,110 +1247,298 @@ describe('createHeadlessForm', () => {
|
|
|
1201
1247
|
});
|
|
1202
1248
|
});
|
|
1203
1249
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1250
|
+
describe('support "date" field type', () => {
|
|
1251
|
+
it('support "date" field type with a minDate', () => {
|
|
1252
|
+
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeDate);
|
|
1206
1253
|
|
|
1207
|
-
|
|
1254
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
1208
1255
|
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1256
|
+
expect(fields[0]).toMatchObject({
|
|
1257
|
+
label: 'Birthdate',
|
|
1258
|
+
name: 'birthdate',
|
|
1259
|
+
required: true,
|
|
1260
|
+
schema: expect.any(Object),
|
|
1261
|
+
type: 'date',
|
|
1262
|
+
minDate: '1922-03-01',
|
|
1263
|
+
maxDate: '2022-03-17',
|
|
1264
|
+
});
|
|
1265
|
+
|
|
1266
|
+
expect(validateForm({})).toEqual({
|
|
1267
|
+
birthdate: 'Required field',
|
|
1268
|
+
});
|
|
1269
|
+
|
|
1270
|
+
expect(validateForm({ birthdate: '' })).toEqual({
|
|
1271
|
+
birthdate: `Required field`,
|
|
1272
|
+
});
|
|
1273
|
+
|
|
1274
|
+
expect(validateForm({ birthdate: '1922-02-01' })).toEqual({
|
|
1275
|
+
birthdate: 'The date must be 1922-03-01 or after.',
|
|
1276
|
+
});
|
|
1277
|
+
|
|
1278
|
+
expect(validateForm({ birthdate: '1922-03-01' })).toBeUndefined();
|
|
1279
|
+
|
|
1280
|
+
expect(validateForm({ birthdate: '2021-03-01' })).toBeUndefined();
|
|
1217
1281
|
});
|
|
1218
1282
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1283
|
+
it('support "date" field type with a maxDate', () => {
|
|
1284
|
+
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeDate);
|
|
1285
|
+
|
|
1286
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
1287
|
+
|
|
1288
|
+
expect(fields[0]).toMatchObject({
|
|
1289
|
+
label: 'Birthdate',
|
|
1290
|
+
name: 'birthdate',
|
|
1291
|
+
required: true,
|
|
1292
|
+
schema: expect.any(Object),
|
|
1293
|
+
type: 'date',
|
|
1294
|
+
minDate: '1922-03-01',
|
|
1295
|
+
maxDate: '2022-03-17',
|
|
1296
|
+
});
|
|
1297
|
+
|
|
1298
|
+
expect(validateForm({ birthdate: '' })).toEqual({
|
|
1299
|
+
birthdate: `Required field`,
|
|
1300
|
+
});
|
|
1301
|
+
|
|
1302
|
+
expect(validateForm({ birthdate: '2022-02-01' })).toBeUndefined();
|
|
1303
|
+
expect(validateForm({ birthdate: '2022-03-01' })).toBeUndefined();
|
|
1304
|
+
expect(validateForm({ birthdate: '2022-04-01' })).toEqual({
|
|
1305
|
+
birthdate: 'The date must be 2022-03-17 or before.',
|
|
1306
|
+
});
|
|
1221
1307
|
});
|
|
1222
1308
|
|
|
1223
|
-
|
|
1224
|
-
|
|
1309
|
+
it('support format date with minDate and maxDate', () => {
|
|
1310
|
+
const schemaFormatDate = {
|
|
1311
|
+
properties: {
|
|
1312
|
+
birthdate: {
|
|
1313
|
+
title: 'Birthdate',
|
|
1314
|
+
type: 'string',
|
|
1315
|
+
format: 'date',
|
|
1316
|
+
'x-jsf-presentation': {
|
|
1317
|
+
inputType: 'myDateType',
|
|
1318
|
+
maxDate: '2022-03-01',
|
|
1319
|
+
minDate: '1922-03-01',
|
|
1320
|
+
},
|
|
1321
|
+
},
|
|
1322
|
+
},
|
|
1323
|
+
};
|
|
1324
|
+
|
|
1325
|
+
const { handleValidation } = createHeadlessForm(schemaFormatDate);
|
|
1326
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
1327
|
+
|
|
1328
|
+
expect(validateForm({ birthdate: '1922-02-01' })).toEqual({
|
|
1329
|
+
birthdate: 'The date must be 1922-03-01 or after.',
|
|
1330
|
+
});
|
|
1225
1331
|
});
|
|
1332
|
+
});
|
|
1333
|
+
|
|
1334
|
+
describe('supports "file" field type', () => {
|
|
1335
|
+
it('supports "file" field type', () => {
|
|
1336
|
+
const result = createHeadlessForm(
|
|
1337
|
+
JSONSchemaBuilder()
|
|
1338
|
+
.addInput({
|
|
1339
|
+
fileInput: mockFileInput,
|
|
1340
|
+
})
|
|
1341
|
+
.build()
|
|
1342
|
+
);
|
|
1226
1343
|
|
|
1227
|
-
|
|
1228
|
-
|
|
1344
|
+
expect(result).toMatchObject({
|
|
1345
|
+
fields: [
|
|
1346
|
+
{
|
|
1347
|
+
type: 'file',
|
|
1348
|
+
fileDownload: 'http://some.domain.com/file-name.pdf',
|
|
1349
|
+
description: 'File Input Description',
|
|
1350
|
+
fileName: 'My File',
|
|
1351
|
+
label: 'File Input',
|
|
1352
|
+
name: 'fileInput',
|
|
1353
|
+
required: false,
|
|
1354
|
+
accept: '.png,.jpg,.jpeg,.pdf',
|
|
1355
|
+
},
|
|
1356
|
+
],
|
|
1357
|
+
});
|
|
1229
1358
|
});
|
|
1230
1359
|
|
|
1231
|
-
|
|
1360
|
+
describe('when a field has accepted extensions', () => {
|
|
1361
|
+
let fields;
|
|
1362
|
+
beforeEach(() => {
|
|
1363
|
+
const result = createHeadlessForm(
|
|
1364
|
+
JSONSchemaBuilder().addInput({ fileInput: mockFileInput }).build()
|
|
1365
|
+
);
|
|
1366
|
+
fields = result.fields;
|
|
1367
|
+
});
|
|
1232
1368
|
|
|
1233
|
-
|
|
1234
|
-
|
|
1369
|
+
describe('and file is of incorrect format', () => {
|
|
1370
|
+
const file = new File(['foo'], 'file.txt', {
|
|
1371
|
+
type: 'text/plain',
|
|
1372
|
+
});
|
|
1235
1373
|
|
|
1236
|
-
|
|
1237
|
-
|
|
1374
|
+
it('should throw an error', async () =>
|
|
1375
|
+
expect(
|
|
1376
|
+
object()
|
|
1377
|
+
.shape({
|
|
1378
|
+
fileInput: fields[0].schema,
|
|
1379
|
+
})
|
|
1380
|
+
.validate({ fileInput: [file] })
|
|
1381
|
+
).rejects.toMatchObject({
|
|
1382
|
+
errors: ['Unsupported file format. The acceptable formats are .png,.jpg,.jpeg,.pdf.'],
|
|
1383
|
+
}));
|
|
1384
|
+
});
|
|
1238
1385
|
|
|
1239
|
-
|
|
1386
|
+
describe('and file is of correct format', () => {
|
|
1387
|
+
const file = new File(['foo'], 'file.png', {
|
|
1388
|
+
type: 'image/png',
|
|
1389
|
+
});
|
|
1390
|
+
Object.defineProperty(file, 'size', { value: 1024 * 1024 });
|
|
1391
|
+
|
|
1392
|
+
const assertObj = { fileInput: [file] };
|
|
1393
|
+
it('should validate field', async () =>
|
|
1394
|
+
expect(
|
|
1395
|
+
object()
|
|
1396
|
+
.shape({
|
|
1397
|
+
fileInput: fields[0].schema,
|
|
1398
|
+
})
|
|
1399
|
+
.validate({ fileInput: [file] })
|
|
1400
|
+
).resolves.toEqual(assertObj));
|
|
1401
|
+
});
|
|
1240
1402
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1403
|
+
describe('and file is of correct but uppercase format ', () => {
|
|
1404
|
+
const file = new File(['foo'], 'file.PNG', {
|
|
1405
|
+
type: 'image/png',
|
|
1406
|
+
});
|
|
1407
|
+
Object.defineProperty(file, 'size', { value: 1024 * 1024 });
|
|
1408
|
+
|
|
1409
|
+
const assertObj = { fileInput: [file] };
|
|
1410
|
+
it('should validate field', async () =>
|
|
1411
|
+
expect(
|
|
1412
|
+
object()
|
|
1413
|
+
.shape({
|
|
1414
|
+
fileInput: fields[0].schema,
|
|
1415
|
+
})
|
|
1416
|
+
.validate({ fileInput: [file] })
|
|
1417
|
+
).resolves.toEqual(assertObj));
|
|
1418
|
+
});
|
|
1419
|
+
|
|
1420
|
+
describe('and file is not instance of a File', () => {
|
|
1421
|
+
it('accepts if file object has name property', async () => {
|
|
1422
|
+
expect(
|
|
1423
|
+
object()
|
|
1424
|
+
.shape({
|
|
1425
|
+
fileInput: fields[0].schema,
|
|
1426
|
+
})
|
|
1427
|
+
.validate({ fileInput: [{ name: 'foo.pdf' }] })
|
|
1428
|
+
).resolves.toEqual({ fileInput: [{ name: 'foo.pdf' }] });
|
|
1429
|
+
});
|
|
1250
1430
|
|
|
1251
|
-
|
|
1252
|
-
|
|
1431
|
+
it('should validate format', async () =>
|
|
1432
|
+
expect(
|
|
1433
|
+
object()
|
|
1434
|
+
.shape({
|
|
1435
|
+
fileInput: fields[0].schema,
|
|
1436
|
+
})
|
|
1437
|
+
.validate({ fileInput: [{ name: 'foo.txt' }] })
|
|
1438
|
+
).rejects.toMatchObject({
|
|
1439
|
+
errors: ['Unsupported file format. The acceptable formats are .png,.jpg,.jpeg,.pdf.'],
|
|
1440
|
+
}));
|
|
1441
|
+
|
|
1442
|
+
it('should validate max size', async () =>
|
|
1443
|
+
expect(
|
|
1444
|
+
object()
|
|
1445
|
+
.shape({
|
|
1446
|
+
fileInput: fields[0].schema,
|
|
1447
|
+
})
|
|
1448
|
+
.validate({ fileInput: [{ name: 'foo.txt', size: 1024 * 1024 * 1024 }] })
|
|
1449
|
+
).rejects.toMatchObject({ errors: ['File size too large. The limit is 20 MB.'] }));
|
|
1450
|
+
|
|
1451
|
+
it('throw an error if invalid file object', async () =>
|
|
1452
|
+
expect(
|
|
1453
|
+
object()
|
|
1454
|
+
.shape({
|
|
1455
|
+
fileInput: fields[0].schema,
|
|
1456
|
+
})
|
|
1457
|
+
.validate({ fileInput: [{ path: 'foo.txt' }] })
|
|
1458
|
+
).rejects.toMatchObject({ errors: ['Not a valid file.'] }));
|
|
1459
|
+
});
|
|
1253
1460
|
});
|
|
1254
1461
|
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1462
|
+
describe('when a field has max file size', () => {
|
|
1463
|
+
let fields;
|
|
1464
|
+
beforeEach(() => {
|
|
1465
|
+
const result = createHeadlessForm(
|
|
1466
|
+
JSONSchemaBuilder().addInput({ fileInput: mockFileInput }).build()
|
|
1467
|
+
);
|
|
1468
|
+
fields = result.fields;
|
|
1469
|
+
});
|
|
1470
|
+
describe('and file is greater than that', () => {
|
|
1471
|
+
const file = new File([''], 'file.png');
|
|
1472
|
+
Object.defineProperty(file, 'size', { value: 1024 * 1024 * 1024 });
|
|
1473
|
+
|
|
1474
|
+
it('should throw an error', async () =>
|
|
1475
|
+
expect(
|
|
1476
|
+
object()
|
|
1477
|
+
.shape({
|
|
1478
|
+
fileInput: fields[0].schema,
|
|
1479
|
+
})
|
|
1480
|
+
.validate({ fileInput: [file] })
|
|
1481
|
+
).rejects.toMatchObject({ errors: ['File size too large. The limit is 20 MB.'] }));
|
|
1482
|
+
});
|
|
1483
|
+
describe('and file is smaller than that', () => {
|
|
1484
|
+
const file = new File([''], 'file.png');
|
|
1485
|
+
Object.defineProperty(file, 'size', { value: 1024 * 1024 });
|
|
1486
|
+
|
|
1487
|
+
const assertObj = { fileInput: [file] };
|
|
1488
|
+
it('should validate field', async () =>
|
|
1489
|
+
expect(
|
|
1490
|
+
object()
|
|
1491
|
+
.shape({
|
|
1492
|
+
fileInput: fields[0].schema,
|
|
1493
|
+
})
|
|
1494
|
+
.validate({ fileInput: [file] })
|
|
1495
|
+
).resolves.toEqual(assertObj));
|
|
1496
|
+
});
|
|
1259
1497
|
});
|
|
1260
|
-
});
|
|
1261
1498
|
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
}
|
|
1276
|
-
};
|
|
1499
|
+
describe('when a field file is optional', () => {
|
|
1500
|
+
it('it accepts an empty array', () => {
|
|
1501
|
+
const result = createHeadlessForm(
|
|
1502
|
+
JSONSchemaBuilder().addInput({ fileInput: mockFileInput }).build()
|
|
1503
|
+
);
|
|
1504
|
+
const emptyFile = { fileInput: [] };
|
|
1505
|
+
expect(
|
|
1506
|
+
object()
|
|
1507
|
+
.shape({
|
|
1508
|
+
fileInput: result.fields[0].schema,
|
|
1509
|
+
})
|
|
1510
|
+
.validate(emptyFile)
|
|
1511
|
+
).resolves.toEqual(emptyFile);
|
|
1512
|
+
});
|
|
1277
1513
|
|
|
1278
|
-
|
|
1279
|
-
|
|
1514
|
+
it('it validates missing file correctly', () => {
|
|
1515
|
+
const { handleValidation } = createHeadlessForm(
|
|
1516
|
+
JSONSchemaBuilder().addInput({ fileInput: mockFileInput }).build()
|
|
1517
|
+
);
|
|
1518
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
1280
1519
|
|
|
1281
|
-
|
|
1282
|
-
|
|
1520
|
+
expect(validateForm({})).toBeUndefined();
|
|
1521
|
+
expect(validateForm({ fileInput: null })).toBeUndefined();
|
|
1522
|
+
});
|
|
1283
1523
|
});
|
|
1284
|
-
});
|
|
1285
1524
|
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
fileInput: mockFileInput,
|
|
1291
|
-
})
|
|
1292
|
-
.build()
|
|
1293
|
-
);
|
|
1525
|
+
describe('when a field file is required', () => {
|
|
1526
|
+
it('it validates missing file correctly', () => {
|
|
1527
|
+
const { handleValidation } = createHeadlessForm(schemaInputTypeFile);
|
|
1528
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
1294
1529
|
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
],
|
|
1530
|
+
expect(validateForm({})).toEqual({
|
|
1531
|
+
a_file: 'Required field',
|
|
1532
|
+
});
|
|
1533
|
+
|
|
1534
|
+
expect(
|
|
1535
|
+
validateForm({
|
|
1536
|
+
a_file: null,
|
|
1537
|
+
})
|
|
1538
|
+
).toEqual({
|
|
1539
|
+
a_file: 'Required field',
|
|
1540
|
+
});
|
|
1541
|
+
});
|
|
1308
1542
|
});
|
|
1309
1543
|
});
|
|
1310
1544
|
|
|
@@ -1591,71 +1825,6 @@ describe('createHeadlessForm', () => {
|
|
|
1591
1825
|
});
|
|
1592
1826
|
});
|
|
1593
1827
|
|
|
1594
|
-
it('supports "radio" field type with its "card" and "card-expandable" variants', () => {
|
|
1595
|
-
const result = createHeadlessForm(
|
|
1596
|
-
JSONSchemaBuilder()
|
|
1597
|
-
.addInput({
|
|
1598
|
-
experience_level: mockRadioCardExpandableInput,
|
|
1599
|
-
payment_method: mockRadioCardInput,
|
|
1600
|
-
})
|
|
1601
|
-
.build()
|
|
1602
|
-
);
|
|
1603
|
-
|
|
1604
|
-
expect(result).toMatchObject({
|
|
1605
|
-
fields: [
|
|
1606
|
-
{
|
|
1607
|
-
description:
|
|
1608
|
-
'Please select the experience level that aligns with this role based on the job description (not the employees overall experience)',
|
|
1609
|
-
label: 'Experience level',
|
|
1610
|
-
name: 'experience_level',
|
|
1611
|
-
type: 'radio',
|
|
1612
|
-
required: false,
|
|
1613
|
-
variant: 'card-expandable',
|
|
1614
|
-
options: [
|
|
1615
|
-
{
|
|
1616
|
-
label: 'Junior level',
|
|
1617
|
-
value: 'junior',
|
|
1618
|
-
description:
|
|
1619
|
-
'Entry level employees who perform tasks under the supervision of a more experienced employee.',
|
|
1620
|
-
},
|
|
1621
|
-
{
|
|
1622
|
-
label: 'Mid level',
|
|
1623
|
-
value: 'mid',
|
|
1624
|
-
description:
|
|
1625
|
-
'Employees who perform tasks with a good degree of autonomy and/or with coordination and control functions.',
|
|
1626
|
-
},
|
|
1627
|
-
{
|
|
1628
|
-
label: 'Senior level',
|
|
1629
|
-
value: 'senior',
|
|
1630
|
-
description:
|
|
1631
|
-
'Employees who perform tasks with a high degree of autonomy and/or with coordination and control functions.',
|
|
1632
|
-
},
|
|
1633
|
-
],
|
|
1634
|
-
},
|
|
1635
|
-
{
|
|
1636
|
-
description: 'Chose how you want to be paid',
|
|
1637
|
-
label: 'Payment method',
|
|
1638
|
-
name: 'payment_method',
|
|
1639
|
-
type: 'radio',
|
|
1640
|
-
variant: 'card',
|
|
1641
|
-
required: false,
|
|
1642
|
-
options: [
|
|
1643
|
-
{
|
|
1644
|
-
label: 'Credit Card',
|
|
1645
|
-
value: 'cc',
|
|
1646
|
-
description: 'Plastic money, which is still money',
|
|
1647
|
-
},
|
|
1648
|
-
{
|
|
1649
|
-
label: 'Cash',
|
|
1650
|
-
value: 'cash',
|
|
1651
|
-
description: 'Rules Everything Around Me',
|
|
1652
|
-
},
|
|
1653
|
-
],
|
|
1654
|
-
},
|
|
1655
|
-
],
|
|
1656
|
-
});
|
|
1657
|
-
});
|
|
1658
|
-
|
|
1659
1828
|
it('supports "null" field type', () => {
|
|
1660
1829
|
const { handleValidation, fields } = createHeadlessForm(schemaInputTypeNull, {
|
|
1661
1830
|
strictInputType: false,
|
|
@@ -1698,51 +1867,6 @@ describe('createHeadlessForm', () => {
|
|
|
1698
1867
|
expect(validateForm({ username: 'john', name: null })).toBeUndefined();
|
|
1699
1868
|
});
|
|
1700
1869
|
|
|
1701
|
-
it('supports oneOf pattern validation', () => {
|
|
1702
|
-
const result = createHeadlessForm(mockTelWithPattern);
|
|
1703
|
-
|
|
1704
|
-
expect(result).toMatchObject({
|
|
1705
|
-
fields: [
|
|
1706
|
-
{
|
|
1707
|
-
label: 'Phone number',
|
|
1708
|
-
name: 'phone_number',
|
|
1709
|
-
type: 'tel',
|
|
1710
|
-
required: false,
|
|
1711
|
-
options: [
|
|
1712
|
-
{
|
|
1713
|
-
label: 'Portugal',
|
|
1714
|
-
pattern: '^(\\+351)[0-9]{9,}$',
|
|
1715
|
-
},
|
|
1716
|
-
{
|
|
1717
|
-
label: 'United Kingdom (UK)',
|
|
1718
|
-
pattern: '^(\\+44)[0-9]{1,}$',
|
|
1719
|
-
},
|
|
1720
|
-
{
|
|
1721
|
-
label: 'Bolivia',
|
|
1722
|
-
pattern: '^(\\+591)[0-9]{9,}$',
|
|
1723
|
-
},
|
|
1724
|
-
{
|
|
1725
|
-
label: 'Canada',
|
|
1726
|
-
pattern: '^(\\+1)(206|224)[0-9]{1,}$',
|
|
1727
|
-
},
|
|
1728
|
-
{
|
|
1729
|
-
label: 'United States',
|
|
1730
|
-
pattern: '^(\\+1)[0-9]{1,}$',
|
|
1731
|
-
},
|
|
1732
|
-
],
|
|
1733
|
-
},
|
|
1734
|
-
],
|
|
1735
|
-
});
|
|
1736
|
-
|
|
1737
|
-
const fieldValidator = result.fields[0].schema;
|
|
1738
|
-
|
|
1739
|
-
expect(fieldValidator.isValidSync('+351123123123')).toBe(true);
|
|
1740
|
-
expect(() => fieldValidator.validateSync('+35100')).toThrowError(
|
|
1741
|
-
'The option "+35100" is not valid.'
|
|
1742
|
-
);
|
|
1743
|
-
expect(fieldValidator.isValidSync(undefined)).toBe(true);
|
|
1744
|
-
});
|
|
1745
|
-
|
|
1746
1870
|
describe('supports "fieldset" field type', () => {
|
|
1747
1871
|
it('supports basic case', () => {
|
|
1748
1872
|
const result = createHeadlessForm({
|
|
@@ -2009,8 +2133,6 @@ describe('createHeadlessForm', () => {
|
|
|
2009
2133
|
});
|
|
2010
2134
|
|
|
2011
2135
|
it('When changing back to low work hours, the perks.food goes back to the original state', () => {
|
|
2012
|
-
// HACK FOR NOW THAT IS CAUSING THIS EXTRA VALIDATION. Fix me!!
|
|
2013
|
-
validateForm({});
|
|
2014
2136
|
expect(
|
|
2015
2137
|
validateForm({
|
|
2016
2138
|
work_hours_per_week: 10,
|
|
@@ -2021,7 +2143,6 @@ describe('createHeadlessForm', () => {
|
|
|
2021
2143
|
food: 'Required field',
|
|
2022
2144
|
retirement: 'Required field',
|
|
2023
2145
|
},
|
|
2024
|
-
// pto_minimum: 20 would appear if not for the extra validation above.
|
|
2025
2146
|
// ...pto is minimum error is gone! (sanity-check)
|
|
2026
2147
|
});
|
|
2027
2148
|
|
|
@@ -2120,7 +2241,7 @@ describe('createHeadlessForm', () => {
|
|
|
2120
2241
|
expect(fieldValidator.isValidSync(false)).toBe(true);
|
|
2121
2242
|
expect(fieldValidator.isValidSync(undefined)).toBe(true);
|
|
2122
2243
|
expect(() => fieldValidator.validateSync('foo')).toThrowError(
|
|
2123
|
-
'
|
|
2244
|
+
'The value must be a boolean, but received "foo"'
|
|
2124
2245
|
);
|
|
2125
2246
|
});
|
|
2126
2247
|
|
|
@@ -2148,6 +2269,27 @@ describe('createHeadlessForm', () => {
|
|
|
2148
2269
|
default: true,
|
|
2149
2270
|
});
|
|
2150
2271
|
});
|
|
2272
|
+
|
|
2273
|
+
it('conditional: it works as undefined value', () => {
|
|
2274
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
2275
|
+
schemaInputTypeCheckboxBooleanConditional
|
|
2276
|
+
);
|
|
2277
|
+
const checkboxField = fields.find((field) => field.name === 'pet_is_cat');
|
|
2278
|
+
|
|
2279
|
+
expect(handleValidation({ has_pet: false }).formErrors).toBeUndefined();
|
|
2280
|
+
expect(checkboxField.isVisible).toBe(false);
|
|
2281
|
+
|
|
2282
|
+
expect(handleValidation({ has_pet: true, pet_is_cat: true }).formErrors).toBeUndefined();
|
|
2283
|
+
expect(checkboxField.isVisible).toBe(true);
|
|
2284
|
+
|
|
2285
|
+
expect(handleValidation({ has_pet: true, pet_is_cat: 'foo' }).formErrors).toEqual({
|
|
2286
|
+
pet_is_cat: 'The value must be a boolean, but received "foo"',
|
|
2287
|
+
});
|
|
2288
|
+
|
|
2289
|
+
// Bug: It should throw an error saying pet_is_cat is not allowed, but it doesn't.
|
|
2290
|
+
// Explained at "Given values from hidden fields, it does not thrown an error"
|
|
2291
|
+
expect(handleValidation({ has_pet: false, pet_is_cat: true }).formErrors).toBeUndefined();
|
|
2292
|
+
});
|
|
2151
2293
|
});
|
|
2152
2294
|
});
|
|
2153
2295
|
|
|
@@ -2269,43 +2411,12 @@ describe('createHeadlessForm', () => {
|
|
|
2269
2411
|
'x-jsf-order': ['pets'],
|
|
2270
2412
|
});
|
|
2271
2413
|
|
|
2272
|
-
const fieldValidator = result.fields[0].schema;
|
|
2273
|
-
|
|
2274
|
-
expect(fieldValidator.isValidSync(0)).toBe(true);
|
|
2275
|
-
expect(fieldValidator.isValidSync(1)).toBe(true);
|
|
2276
|
-
expect(() => fieldValidator.validateSync('2')).toThrowError('The option "2" is not valid.');
|
|
2277
|
-
expect(fieldValidator.isValidSync(null)).toBe(true);
|
|
2278
|
-
});
|
|
2279
|
-
|
|
2280
|
-
describe('x-jsf-presentation attribute', () => {
|
|
2281
|
-
it('support field with "x-jsf-presentation.statement"', () => {
|
|
2282
|
-
const result = createHeadlessForm(schemaInputWithStatement);
|
|
2283
|
-
|
|
2284
|
-
expect(result).toMatchObject({
|
|
2285
|
-
fields: [
|
|
2286
|
-
{
|
|
2287
|
-
name: 'bonus',
|
|
2288
|
-
label: 'Bonus',
|
|
2289
|
-
type: 'text',
|
|
2290
|
-
statement: {
|
|
2291
|
-
description: 'This is a custom statement message.',
|
|
2292
|
-
inputType: 'statement',
|
|
2293
|
-
severity: 'info',
|
|
2294
|
-
},
|
|
2295
|
-
},
|
|
2296
|
-
{
|
|
2297
|
-
name: 'role',
|
|
2298
|
-
label: 'Role',
|
|
2299
|
-
type: 'text',
|
|
2300
|
-
statement: {
|
|
2301
|
-
description: 'This is another statement message, but more severe.',
|
|
2302
|
-
inputType: 'statement',
|
|
2303
|
-
severity: 'warning',
|
|
2304
|
-
},
|
|
2305
|
-
},
|
|
2306
|
-
],
|
|
2307
|
-
});
|
|
2308
|
-
});
|
|
2414
|
+
const fieldValidator = result.fields[0].schema;
|
|
2415
|
+
|
|
2416
|
+
expect(fieldValidator.isValidSync(0)).toBe(true);
|
|
2417
|
+
expect(fieldValidator.isValidSync(1)).toBe(true);
|
|
2418
|
+
expect(() => fieldValidator.validateSync('2')).toThrowError('The option "2" is not valid.');
|
|
2419
|
+
expect(fieldValidator.isValidSync(null)).toBe(true);
|
|
2309
2420
|
});
|
|
2310
2421
|
|
|
2311
2422
|
describe('property misc attributes', () => {
|
|
@@ -2367,27 +2478,93 @@ describe('createHeadlessForm', () => {
|
|
|
2367
2478
|
});
|
|
2368
2479
|
});
|
|
2369
2480
|
|
|
2370
|
-
it('pass "description"
|
|
2371
|
-
const
|
|
2481
|
+
it('pass both root level "description" and "x-jsf-presentation.description"', () => {
|
|
2482
|
+
const resultsWithRootDescription = createHeadlessForm({
|
|
2372
2483
|
properties: {
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2484
|
+
username: mockTextInput,
|
|
2485
|
+
},
|
|
2486
|
+
required: ['username'],
|
|
2487
|
+
});
|
|
2488
|
+
|
|
2489
|
+
expect(resultsWithRootDescription.fields[0].description).toMatch(/your username/i);
|
|
2490
|
+
|
|
2491
|
+
const resultsWithPresentationDescription = createHeadlessForm({
|
|
2492
|
+
properties: {
|
|
2493
|
+
username: {
|
|
2494
|
+
...mockTextInput,
|
|
2495
|
+
'x-jsf-presentation': {
|
|
2383
2496
|
inputType: 'text',
|
|
2497
|
+
// should override the root level description
|
|
2498
|
+
description: 'a different description with <span>markup</span>',
|
|
2384
2499
|
},
|
|
2385
2500
|
},
|
|
2386
2501
|
},
|
|
2502
|
+
required: ['username'],
|
|
2387
2503
|
});
|
|
2388
2504
|
|
|
2505
|
+
expect(resultsWithPresentationDescription.fields[0].description).toMatch(
|
|
2506
|
+
/a different description /i
|
|
2507
|
+
);
|
|
2508
|
+
});
|
|
2509
|
+
|
|
2510
|
+
it('pass both root level "description" and "presentation.description" (deprecated)', () => {
|
|
2511
|
+
const resultsWithRootDescription = createHeadlessForm({
|
|
2512
|
+
properties: {
|
|
2513
|
+
username: mockTextInputDeprecated,
|
|
2514
|
+
},
|
|
2515
|
+
required: ['username'],
|
|
2516
|
+
});
|
|
2517
|
+
|
|
2518
|
+
expect(resultsWithRootDescription.fields[0].description).toMatch(/your username/i);
|
|
2519
|
+
|
|
2520
|
+
const resultsWithPresentationDescription = createHeadlessForm(
|
|
2521
|
+
JSONSchemaBuilder()
|
|
2522
|
+
.addInput({
|
|
2523
|
+
username: {
|
|
2524
|
+
...mockTextInputDeprecated,
|
|
2525
|
+
presentation: {
|
|
2526
|
+
inputType: 'text',
|
|
2527
|
+
maskSecret: 2,
|
|
2528
|
+
// should override the root level description
|
|
2529
|
+
description: 'a different description with <span>markup</span>',
|
|
2530
|
+
},
|
|
2531
|
+
},
|
|
2532
|
+
})
|
|
2533
|
+
.setRequiredFields(['username'])
|
|
2534
|
+
.build()
|
|
2535
|
+
);
|
|
2536
|
+
|
|
2537
|
+
expect(resultsWithPresentationDescription.fields[0].description).toMatch(
|
|
2538
|
+
/a different description /i
|
|
2539
|
+
);
|
|
2540
|
+
});
|
|
2541
|
+
|
|
2542
|
+
it('support field with "x-jsf-presentation.statement"', () => {
|
|
2543
|
+
const result = createHeadlessForm(schemaInputWithStatement);
|
|
2544
|
+
|
|
2389
2545
|
expect(result).toMatchObject({
|
|
2390
|
-
fields: [
|
|
2546
|
+
fields: [
|
|
2547
|
+
{
|
|
2548
|
+
name: 'bonus',
|
|
2549
|
+
label: 'Bonus',
|
|
2550
|
+
type: 'text',
|
|
2551
|
+
statement: {
|
|
2552
|
+
description: 'This is a custom statement message.',
|
|
2553
|
+
inputType: 'statement',
|
|
2554
|
+
severity: 'info',
|
|
2555
|
+
},
|
|
2556
|
+
},
|
|
2557
|
+
{
|
|
2558
|
+
name: 'role',
|
|
2559
|
+
label: 'Role',
|
|
2560
|
+
type: 'text',
|
|
2561
|
+
statement: {
|
|
2562
|
+
description: 'This is another statement message, but more severe.',
|
|
2563
|
+
inputType: 'statement',
|
|
2564
|
+
severity: 'warning',
|
|
2565
|
+
},
|
|
2566
|
+
},
|
|
2567
|
+
],
|
|
2391
2568
|
});
|
|
2392
2569
|
});
|
|
2393
2570
|
|
|
@@ -2460,7 +2637,7 @@ describe('createHeadlessForm', () => {
|
|
|
2460
2637
|
});
|
|
2461
2638
|
});
|
|
2462
2639
|
|
|
2463
|
-
it('
|
|
2640
|
+
it('pass scopedJsonSchema to each field', () => {
|
|
2464
2641
|
const { fields } = createHeadlessForm(schemaWithoutInputTypes, {
|
|
2465
2642
|
strictInputType: false,
|
|
2466
2643
|
});
|
|
@@ -2525,7 +2702,7 @@ describe('createHeadlessForm', () => {
|
|
|
2525
2702
|
expect(fieldsetByName).toEqual(['line_one', 'number', 'postal_code']);
|
|
2526
2703
|
});
|
|
2527
2704
|
|
|
2528
|
-
it('sorts fields based on original properties (
|
|
2705
|
+
it('sorts fields based on original properties (without x-jsf-order)', () => {
|
|
2529
2706
|
// Assert the sample schema has x-jsf-order
|
|
2530
2707
|
expect(schemaWithOrderKeyword['x-jsf-order']).toBeDefined();
|
|
2531
2708
|
|
|
@@ -2546,467 +2723,276 @@ describe('createHeadlessForm', () => {
|
|
|
2546
2723
|
});
|
|
2547
2724
|
});
|
|
2548
2725
|
|
|
2549
|
-
describe('
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
describe('and value is empty', () => {
|
|
2558
|
-
it('should throw an error', async () =>
|
|
2559
|
-
expect(
|
|
2560
|
-
object()
|
|
2561
|
-
.shape({
|
|
2562
|
-
test: fields[0].schema,
|
|
2563
|
-
})
|
|
2564
|
-
.validate({ test: '' })
|
|
2565
|
-
).rejects.toMatchObject({ errors: ['Required field'] }));
|
|
2566
|
-
});
|
|
2567
|
-
describe('and value is defined', () => {
|
|
2568
|
-
it('should validate field', async () => {
|
|
2569
|
-
const assertObj = { test: 'Hello' };
|
|
2570
|
-
return expect(
|
|
2571
|
-
object()
|
|
2572
|
-
.shape({
|
|
2573
|
-
test: fields[0].schema,
|
|
2574
|
-
})
|
|
2575
|
-
.validate(assertObj)
|
|
2576
|
-
).resolves.toEqual(assertObj);
|
|
2726
|
+
describe('more validations', () => {
|
|
2727
|
+
describe('when a field is required', () => {
|
|
2728
|
+
let fields;
|
|
2729
|
+
beforeEach(() => {
|
|
2730
|
+
const result = createHeadlessForm(
|
|
2731
|
+
buildJSONSchemaInput({ presentationFields: { inputType: 'text' }, required: true })
|
|
2732
|
+
);
|
|
2733
|
+
fields = result.fields;
|
|
2577
2734
|
});
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
fields = result.fields;
|
|
2588
|
-
});
|
|
2589
|
-
describe('and value is a string', () => {
|
|
2590
|
-
it('should throw an error', async () =>
|
|
2591
|
-
expect(
|
|
2592
|
-
object()
|
|
2593
|
-
.shape({
|
|
2594
|
-
test: fields[0].schema,
|
|
2595
|
-
})
|
|
2596
|
-
.validate({ test: 'Hello' })
|
|
2597
|
-
).rejects.toThrow());
|
|
2598
|
-
});
|
|
2599
|
-
describe('and value is a number', () => {
|
|
2600
|
-
it('should validate field', async () => {
|
|
2601
|
-
const assertObj = { test: 3 };
|
|
2602
|
-
return expect(
|
|
2603
|
-
object()
|
|
2604
|
-
.shape({
|
|
2605
|
-
test: fields[0].schema,
|
|
2606
|
-
})
|
|
2607
|
-
.validate(assertObj)
|
|
2608
|
-
).resolves.toEqual(assertObj);
|
|
2735
|
+
describe('and value is empty', () => {
|
|
2736
|
+
it('should throw an error', async () =>
|
|
2737
|
+
expect(
|
|
2738
|
+
object()
|
|
2739
|
+
.shape({
|
|
2740
|
+
test: fields[0].schema,
|
|
2741
|
+
})
|
|
2742
|
+
.validate({ test: '' })
|
|
2743
|
+
).rejects.toMatchObject({ errors: ['Required field'] }));
|
|
2609
2744
|
});
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
tabs: 'Must be smaller or equal to 0',
|
|
2745
|
+
describe('and value is defined', () => {
|
|
2746
|
+
it('should validate field', async () => {
|
|
2747
|
+
const assertObj = { test: 'Hello' };
|
|
2748
|
+
return expect(
|
|
2749
|
+
object()
|
|
2750
|
+
.shape({
|
|
2751
|
+
test: fields[0].schema,
|
|
2752
|
+
})
|
|
2753
|
+
.validate(assertObj)
|
|
2754
|
+
).resolves.toEqual(assertObj);
|
|
2621
2755
|
});
|
|
2622
2756
|
});
|
|
2623
2757
|
});
|
|
2624
|
-
});
|
|
2625
2758
|
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
})
|
|
2634
|
-
);
|
|
2635
|
-
fields = result.fields;
|
|
2636
|
-
});
|
|
2637
|
-
describe('and value is greater than that', () => {
|
|
2638
|
-
it('should throw an error', async () =>
|
|
2639
|
-
expect(
|
|
2640
|
-
object()
|
|
2641
|
-
.shape({
|
|
2642
|
-
test: fields[0].schema,
|
|
2643
|
-
})
|
|
2644
|
-
.validate({ test: 'Hello Mr John Doe' })
|
|
2645
|
-
).rejects.toMatchObject({ errors: ['Please insert up to 10 characters'] }));
|
|
2646
|
-
});
|
|
2647
|
-
describe('and value is less than that', () => {
|
|
2648
|
-
it('should validate field', async () => {
|
|
2649
|
-
const assertObj = { test: 'Hello John' };
|
|
2650
|
-
return expect(
|
|
2651
|
-
object()
|
|
2652
|
-
.shape({
|
|
2653
|
-
test: fields[0].schema,
|
|
2654
|
-
})
|
|
2655
|
-
.validate(assertObj)
|
|
2656
|
-
).resolves.toEqual(assertObj);
|
|
2759
|
+
describe('when a field is number', () => {
|
|
2760
|
+
let fields;
|
|
2761
|
+
beforeEach(() => {
|
|
2762
|
+
const result = createHeadlessForm(
|
|
2763
|
+
buildJSONSchemaInput({ presentationFields: { inputType: 'number' } })
|
|
2764
|
+
);
|
|
2765
|
+
fields = result.fields;
|
|
2657
2766
|
});
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
inputFields: { minLength: 2 },
|
|
2668
|
-
})
|
|
2669
|
-
);
|
|
2670
|
-
fields = result.fields;
|
|
2671
|
-
});
|
|
2672
|
-
describe('and value is smaller than that', () => {
|
|
2673
|
-
it('should throw an error', async () =>
|
|
2674
|
-
expect(
|
|
2675
|
-
object()
|
|
2676
|
-
.shape({
|
|
2677
|
-
test: fields[0].schema,
|
|
2678
|
-
})
|
|
2679
|
-
.validate({ test: 'H' })
|
|
2680
|
-
).rejects.toMatchObject({ errors: ['Please insert at least 2 characters'] }));
|
|
2681
|
-
});
|
|
2682
|
-
describe('and value is greater than that', () => {
|
|
2683
|
-
it('should validate field', async () => {
|
|
2684
|
-
const assertObj = { test: 'Hello John' };
|
|
2685
|
-
return expect(
|
|
2686
|
-
object()
|
|
2687
|
-
.shape({
|
|
2688
|
-
test: fields[0].schema,
|
|
2689
|
-
})
|
|
2690
|
-
.validate(assertObj)
|
|
2691
|
-
).resolves.toEqual(assertObj);
|
|
2767
|
+
describe('and value is a string', () => {
|
|
2768
|
+
it('should throw an error', async () =>
|
|
2769
|
+
expect(
|
|
2770
|
+
object()
|
|
2771
|
+
.shape({
|
|
2772
|
+
test: fields[0].schema,
|
|
2773
|
+
})
|
|
2774
|
+
.validate({ test: 'Hello' })
|
|
2775
|
+
).rejects.toThrow());
|
|
2692
2776
|
});
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
})
|
|
2704
|
-
);
|
|
2705
|
-
fields = result.fields;
|
|
2706
|
-
});
|
|
2707
|
-
|
|
2708
|
-
describe('and value is less than that', () => {
|
|
2709
|
-
it('should throw an error', async () =>
|
|
2710
|
-
expect(
|
|
2711
|
-
object()
|
|
2712
|
-
.shape({
|
|
2713
|
-
test: fields[0].schema,
|
|
2714
|
-
})
|
|
2715
|
-
.validate({ test: -1 })
|
|
2716
|
-
).rejects.toMatchObject({ errors: ['Must be greater or equal to 0'] }));
|
|
2717
|
-
});
|
|
2718
|
-
|
|
2719
|
-
describe('and value is greater than that', () => {
|
|
2720
|
-
it('should validate field', async () => {
|
|
2721
|
-
const assertObj = { test: 4 };
|
|
2722
|
-
return expect(
|
|
2723
|
-
object()
|
|
2724
|
-
.shape({
|
|
2725
|
-
test: fields[0].schema,
|
|
2726
|
-
})
|
|
2727
|
-
.validate(assertObj)
|
|
2728
|
-
).resolves.toEqual(assertObj);
|
|
2777
|
+
describe('and value is a number', () => {
|
|
2778
|
+
it('should validate field', async () => {
|
|
2779
|
+
const assertObj = { test: 3 };
|
|
2780
|
+
return expect(
|
|
2781
|
+
object()
|
|
2782
|
+
.shape({
|
|
2783
|
+
test: fields[0].schema,
|
|
2784
|
+
})
|
|
2785
|
+
.validate(assertObj)
|
|
2786
|
+
).resolves.toEqual(assertObj);
|
|
2787
|
+
});
|
|
2729
2788
|
});
|
|
2730
|
-
|
|
2731
|
-
|
|
2789
|
+
describe('and maximum is set to zero', () => {
|
|
2790
|
+
it('shows the correct validation', () => {
|
|
2791
|
+
const { handleValidation } = createHeadlessForm(schemaInputTypeNumberZeroMaximum);
|
|
2792
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
2732
2793
|
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
beforeEach(() => {
|
|
2736
|
-
const result = createHeadlessForm(
|
|
2737
|
-
buildJSONSchemaInput({
|
|
2738
|
-
presentationFields: { inputType: 'number' },
|
|
2739
|
-
inputFields: { maximum: 10 },
|
|
2740
|
-
})
|
|
2741
|
-
);
|
|
2742
|
-
fields = result.fields;
|
|
2743
|
-
});
|
|
2744
|
-
|
|
2745
|
-
describe('and value is greater than that', () => {
|
|
2746
|
-
it('should throw an error', async () =>
|
|
2747
|
-
expect(
|
|
2748
|
-
object()
|
|
2749
|
-
.shape({
|
|
2750
|
-
test: fields[0].schema,
|
|
2751
|
-
})
|
|
2752
|
-
.validate({ test: 11 })
|
|
2753
|
-
).rejects.toMatchObject({ errors: ['Must be smaller or equal to 10'] }));
|
|
2754
|
-
});
|
|
2794
|
+
expect(validateForm({ tabs: '0' })).toBeUndefined();
|
|
2795
|
+
expect(validateForm({ tabs: '-10' })).toBeUndefined();
|
|
2755
2796
|
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
object()
|
|
2761
|
-
.shape({
|
|
2762
|
-
test: fields[0].schema,
|
|
2763
|
-
})
|
|
2764
|
-
.validate(assertObj)
|
|
2765
|
-
).resolves.toEqual(assertObj);
|
|
2797
|
+
expect(validateForm({ tabs: 1 })).toEqual({
|
|
2798
|
+
tabs: 'Must be smaller or equal to 0',
|
|
2799
|
+
});
|
|
2800
|
+
});
|
|
2766
2801
|
});
|
|
2767
2802
|
});
|
|
2768
|
-
});
|
|
2769
2803
|
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2804
|
+
describe('when a field has a maxLength of 10', () => {
|
|
2805
|
+
let fields;
|
|
2806
|
+
beforeEach(() => {
|
|
2807
|
+
const result = createHeadlessForm(
|
|
2808
|
+
buildJSONSchemaInput({
|
|
2809
|
+
presentationFields: { inputType: 'text' },
|
|
2810
|
+
inputFields: { maxLength: 10 },
|
|
2811
|
+
})
|
|
2812
|
+
);
|
|
2813
|
+
fields = result.fields;
|
|
2814
|
+
});
|
|
2815
|
+
describe('and value is greater than that', () => {
|
|
2816
|
+
it('should throw an error', async () =>
|
|
2817
|
+
expect(
|
|
2818
|
+
object()
|
|
2819
|
+
.shape({
|
|
2820
|
+
test: fields[0].schema,
|
|
2821
|
+
})
|
|
2822
|
+
.validate({ test: 'Hello Mr John Doe' })
|
|
2823
|
+
).rejects.toMatchObject({ errors: ['Please insert up to 10 characters'] }));
|
|
2824
|
+
});
|
|
2825
|
+
describe('and value is less than that', () => {
|
|
2826
|
+
it('should validate field', async () => {
|
|
2827
|
+
const assertObj = { test: 'Hello John' };
|
|
2828
|
+
return expect(
|
|
2829
|
+
object()
|
|
2830
|
+
.shape({
|
|
2831
|
+
test: fields[0].schema,
|
|
2832
|
+
})
|
|
2833
|
+
.validate(assertObj)
|
|
2834
|
+
).resolves.toEqual(assertObj);
|
|
2835
|
+
});
|
|
2801
2836
|
});
|
|
2802
2837
|
});
|
|
2803
|
-
});
|
|
2804
|
-
|
|
2805
|
-
describe('when a field has max file size', () => {
|
|
2806
|
-
let fields;
|
|
2807
|
-
beforeEach(() => {
|
|
2808
|
-
const result = createHeadlessForm(
|
|
2809
|
-
JSONSchemaBuilder().addInput({ fileInput: mockFileInput }).build()
|
|
2810
|
-
);
|
|
2811
|
-
fields = result.fields;
|
|
2812
|
-
});
|
|
2813
|
-
describe('and file is greater than that', () => {
|
|
2814
|
-
const file = new File([''], 'file.png');
|
|
2815
|
-
Object.defineProperty(file, 'size', { value: 1024 * 1024 * 1024 });
|
|
2816
|
-
|
|
2817
|
-
it('should throw an error', async () =>
|
|
2818
|
-
expect(
|
|
2819
|
-
object()
|
|
2820
|
-
.shape({
|
|
2821
|
-
fileInput: fields[0].schema,
|
|
2822
|
-
})
|
|
2823
|
-
.validate({ fileInput: [file] })
|
|
2824
|
-
).rejects.toMatchObject({ errors: ['File size too large. The limit is 20 MB.'] }));
|
|
2825
|
-
});
|
|
2826
|
-
describe('and file is smaller than that', () => {
|
|
2827
|
-
const file = new File([''], 'file.png');
|
|
2828
|
-
Object.defineProperty(file, 'size', { value: 1024 * 1024 });
|
|
2829
|
-
|
|
2830
|
-
const assertObj = { fileInput: [file] };
|
|
2831
|
-
it('should validate field', async () =>
|
|
2832
|
-
expect(
|
|
2833
|
-
object()
|
|
2834
|
-
.shape({
|
|
2835
|
-
fileInput: fields[0].schema,
|
|
2836
|
-
})
|
|
2837
|
-
.validate({ fileInput: [file] })
|
|
2838
|
-
).resolves.toEqual(assertObj));
|
|
2839
|
-
});
|
|
2840
|
-
});
|
|
2841
2838
|
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
object()
|
|
2850
|
-
.shape({
|
|
2851
|
-
fileInput: result.fields[0].schema,
|
|
2839
|
+
describe('when a field has a minLength of 2', () => {
|
|
2840
|
+
let fields;
|
|
2841
|
+
beforeEach(() => {
|
|
2842
|
+
const result = createHeadlessForm(
|
|
2843
|
+
buildJSONSchemaInput({
|
|
2844
|
+
presentationFields: { inputType: 'text' },
|
|
2845
|
+
inputFields: { minLength: 2 },
|
|
2852
2846
|
})
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
});
|
|
2856
|
-
|
|
2857
|
-
it('it validates missing file correctly', () => {
|
|
2858
|
-
const { handleValidation } = createHeadlessForm(
|
|
2859
|
-
JSONSchemaBuilder().addInput({ fileInput: mockFileInput }).build()
|
|
2860
|
-
);
|
|
2861
|
-
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
2862
|
-
|
|
2863
|
-
expect(validateForm({})).toBeUndefined();
|
|
2864
|
-
expect(validateForm({ fileInput: null })).toBeUndefined();
|
|
2865
|
-
});
|
|
2866
|
-
});
|
|
2867
|
-
|
|
2868
|
-
describe('when a field file is required', () => {
|
|
2869
|
-
it('it validates missing file correctly', () => {
|
|
2870
|
-
const { handleValidation } = createHeadlessForm(schemaInputTypeFile);
|
|
2871
|
-
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
2872
|
-
|
|
2873
|
-
expect(validateForm({})).toEqual({
|
|
2874
|
-
a_file: 'Required field',
|
|
2847
|
+
);
|
|
2848
|
+
fields = result.fields;
|
|
2875
2849
|
});
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2850
|
+
describe('and value is smaller than that', () => {
|
|
2851
|
+
it('should throw an error', async () =>
|
|
2852
|
+
expect(
|
|
2853
|
+
object()
|
|
2854
|
+
.shape({
|
|
2855
|
+
test: fields[0].schema,
|
|
2856
|
+
})
|
|
2857
|
+
.validate({ test: 'H' })
|
|
2858
|
+
).rejects.toMatchObject({ errors: ['Please insert at least 2 characters'] }));
|
|
2859
|
+
});
|
|
2860
|
+
describe('and value is greater than that', () => {
|
|
2861
|
+
it('should validate field', async () => {
|
|
2862
|
+
const assertObj = { test: 'Hello John' };
|
|
2863
|
+
return expect(
|
|
2864
|
+
object()
|
|
2865
|
+
.shape({
|
|
2866
|
+
test: fields[0].schema,
|
|
2867
|
+
})
|
|
2868
|
+
.validate(assertObj)
|
|
2869
|
+
).resolves.toEqual(assertObj);
|
|
2870
|
+
});
|
|
2883
2871
|
});
|
|
2884
2872
|
});
|
|
2885
|
-
});
|
|
2886
2873
|
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
type: 'text/plain',
|
|
2874
|
+
describe('when a field has a minimum of 0', () => {
|
|
2875
|
+
let fields;
|
|
2876
|
+
beforeEach(() => {
|
|
2877
|
+
const result = createHeadlessForm(
|
|
2878
|
+
buildJSONSchemaInput({
|
|
2879
|
+
presentationFields: { inputType: 'number' },
|
|
2880
|
+
inputFields: { minimum: 0 },
|
|
2881
|
+
})
|
|
2882
|
+
);
|
|
2883
|
+
fields = result.fields;
|
|
2898
2884
|
});
|
|
2899
2885
|
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
errors: ['
|
|
2909
|
-
}));
|
|
2910
|
-
});
|
|
2911
|
-
describe('and file is of correct format', () => {
|
|
2912
|
-
const file = new File(['foo'], 'file.png', {
|
|
2913
|
-
type: 'image/png',
|
|
2886
|
+
describe('and value is less than that', () => {
|
|
2887
|
+
it('should throw an error', async () =>
|
|
2888
|
+
expect(
|
|
2889
|
+
object()
|
|
2890
|
+
.shape({
|
|
2891
|
+
test: fields[0].schema,
|
|
2892
|
+
})
|
|
2893
|
+
.validate({ test: -1 })
|
|
2894
|
+
).rejects.toMatchObject({ errors: ['Must be greater or equal to 0'] }));
|
|
2914
2895
|
});
|
|
2915
|
-
Object.defineProperty(file, 'size', { value: 1024 * 1024 });
|
|
2916
2896
|
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
describe('and file is of correct but uppercase format ', () => {
|
|
2929
|
-
const file = new File(['foo'], 'file.PNG', {
|
|
2930
|
-
type: 'image/png',
|
|
2897
|
+
describe('and value is greater than that', () => {
|
|
2898
|
+
it('should validate field', async () => {
|
|
2899
|
+
const assertObj = { test: 4 };
|
|
2900
|
+
return expect(
|
|
2901
|
+
object()
|
|
2902
|
+
.shape({
|
|
2903
|
+
test: fields[0].schema,
|
|
2904
|
+
})
|
|
2905
|
+
.validate(assertObj)
|
|
2906
|
+
).resolves.toEqual(assertObj);
|
|
2907
|
+
});
|
|
2931
2908
|
});
|
|
2932
|
-
Object.defineProperty(file, 'size', { value: 1024 * 1024 });
|
|
2933
|
-
|
|
2934
|
-
const assertObj = { fileInput: [file] };
|
|
2935
|
-
it('should validate field', async () =>
|
|
2936
|
-
expect(
|
|
2937
|
-
object()
|
|
2938
|
-
.shape({
|
|
2939
|
-
fileInput: fields[0].schema,
|
|
2940
|
-
})
|
|
2941
|
-
.validate({ fileInput: [file] })
|
|
2942
|
-
).resolves.toEqual(assertObj));
|
|
2943
2909
|
});
|
|
2944
2910
|
|
|
2945
|
-
describe('
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
}
|
|
2952
|
-
|
|
2953
|
-
)
|
|
2911
|
+
describe('when a field has a maximum of 10', () => {
|
|
2912
|
+
let fields;
|
|
2913
|
+
beforeEach(() => {
|
|
2914
|
+
const result = createHeadlessForm(
|
|
2915
|
+
buildJSONSchemaInput({
|
|
2916
|
+
presentationFields: { inputType: 'number' },
|
|
2917
|
+
inputFields: { maximum: 10 },
|
|
2918
|
+
})
|
|
2919
|
+
);
|
|
2920
|
+
fields = result.fields;
|
|
2954
2921
|
});
|
|
2955
2922
|
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
errors: ['
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
it('should validate max size', async () =>
|
|
2968
|
-
expect(
|
|
2969
|
-
object()
|
|
2970
|
-
.shape({
|
|
2971
|
-
fileInput: fields[0].schema,
|
|
2972
|
-
})
|
|
2973
|
-
.validate({ fileInput: [{ name: 'foo.txt', size: 1024 * 1024 * 1024 }] })
|
|
2974
|
-
).rejects.toMatchObject({ errors: ['File size too large. The limit is 20 MB.'] }));
|
|
2923
|
+
describe('and value is greater than that', () => {
|
|
2924
|
+
it('should throw an error', async () =>
|
|
2925
|
+
expect(
|
|
2926
|
+
object()
|
|
2927
|
+
.shape({
|
|
2928
|
+
test: fields[0].schema,
|
|
2929
|
+
})
|
|
2930
|
+
.validate({ test: 11 })
|
|
2931
|
+
).rejects.toMatchObject({ errors: ['Must be smaller or equal to 10'] }));
|
|
2932
|
+
});
|
|
2975
2933
|
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2934
|
+
describe('and value is greater than that', () => {
|
|
2935
|
+
it('should validate field', async () => {
|
|
2936
|
+
const assertObj = { test: 4 };
|
|
2937
|
+
return expect(
|
|
2938
|
+
object()
|
|
2939
|
+
.shape({
|
|
2940
|
+
test: fields[0].schema,
|
|
2941
|
+
})
|
|
2942
|
+
.validate(assertObj)
|
|
2943
|
+
).resolves.toEqual(assertObj);
|
|
2944
|
+
});
|
|
2945
|
+
});
|
|
2984
2946
|
});
|
|
2985
|
-
});
|
|
2986
2947
|
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2948
|
+
describe('when a field has a pattern', () => {
|
|
2949
|
+
let fields;
|
|
2950
|
+
beforeEach(() => {
|
|
2951
|
+
const result = createHeadlessForm(
|
|
2952
|
+
buildJSONSchemaInput({
|
|
2953
|
+
presentationFields: { inputType: 'text' },
|
|
2954
|
+
inputFields: { pattern: '^[0-9]{3}-[0-9]{2}-(?!0{4})[0-9]{4}$' },
|
|
2955
|
+
})
|
|
2956
|
+
);
|
|
2957
|
+
fields = result.fields;
|
|
2958
|
+
});
|
|
2959
|
+
describe('and value does not match the pattern', () => {
|
|
2960
|
+
it('should throw an error', async () =>
|
|
2961
|
+
expect(
|
|
2962
|
+
object()
|
|
2963
|
+
.shape({
|
|
2964
|
+
test: fields[0].schema,
|
|
2965
|
+
})
|
|
2966
|
+
.validate({ test: 'Hello' })
|
|
2967
|
+
).rejects.toMatchObject({ errors: [expect.any(String)] }));
|
|
2968
|
+
});
|
|
2969
|
+
describe('and value matches the pattern', () => {
|
|
2970
|
+
it('should validate field', async () => {
|
|
2971
|
+
const assertObj = { test: '401-85-1950' };
|
|
2972
|
+
return expect(
|
|
2973
|
+
object()
|
|
2974
|
+
.shape({
|
|
2975
|
+
test: fields[0].schema,
|
|
2976
|
+
})
|
|
2977
|
+
.validate(assertObj)
|
|
2978
|
+
).resolves.toEqual(assertObj);
|
|
2979
|
+
});
|
|
2994
2980
|
});
|
|
2995
|
-
|
|
2996
|
-
expect(fields[0].statement.description).toBe(`<a href="">conditional statement markup</a>`);
|
|
2997
2981
|
});
|
|
2998
2982
|
});
|
|
2999
2983
|
|
|
3000
|
-
describe('
|
|
2984
|
+
describe('even more validations', () => {
|
|
3001
2985
|
describe('and all fields are optional', () => {
|
|
3002
2986
|
let handleValidation;
|
|
3003
2987
|
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
3004
2988
|
|
|
3005
2989
|
beforeEach(() => {
|
|
3006
|
-
const result =
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
2990
|
+
const result = {
|
|
2991
|
+
properties: {
|
|
2992
|
+
textInput: mockTextInput,
|
|
2993
|
+
numberInput: mockNumberInput,
|
|
2994
|
+
},
|
|
2995
|
+
};
|
|
3010
2996
|
const { handleValidation: handleValidationEach } = createHeadlessForm(result);
|
|
3011
2997
|
handleValidation = handleValidationEach;
|
|
3012
2998
|
});
|
|
@@ -3037,11 +3023,13 @@ describe('createHeadlessForm', () => {
|
|
|
3037
3023
|
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
3038
3024
|
|
|
3039
3025
|
beforeEach(() => {
|
|
3040
|
-
const result =
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3026
|
+
const result = {
|
|
3027
|
+
properties: {
|
|
3028
|
+
textInput: mockTextInput,
|
|
3029
|
+
numberInput: mockNumberInput,
|
|
3030
|
+
},
|
|
3031
|
+
required: ['numberInput', 'textInput'],
|
|
3032
|
+
};
|
|
3045
3033
|
const { handleValidation: handleValidationEach } = createHeadlessForm(result);
|
|
3046
3034
|
handleValidation = handleValidationEach;
|
|
3047
3035
|
});
|
|
@@ -3868,7 +3856,19 @@ describe('createHeadlessForm', () => {
|
|
|
3868
3856
|
});
|
|
3869
3857
|
});
|
|
3870
3858
|
|
|
3871
|
-
describe('
|
|
3859
|
+
describe('given default values', () => {
|
|
3860
|
+
describe('and a field with conditional presentation properties', () => {
|
|
3861
|
+
it('returns the nested properties when the conditional matches', () => {
|
|
3862
|
+
const { fields } = createHeadlessForm(schemaWithConditionalPresentationProperties, {
|
|
3863
|
+
initialValues: {
|
|
3864
|
+
// show the hidden statement
|
|
3865
|
+
mock_radio: 'no',
|
|
3866
|
+
},
|
|
3867
|
+
});
|
|
3868
|
+
|
|
3869
|
+
expect(fields[0].statement.description).toBe(`<a href="">conditional statement markup</a>`);
|
|
3870
|
+
});
|
|
3871
|
+
});
|
|
3872
3872
|
describe('and "fieldset" has scoped conditionals', () => {
|
|
3873
3873
|
it('should show conditionals fields when values fullfil conditions', () => {
|
|
3874
3874
|
const result = createHeadlessForm(schemaFieldsetScopedCondition, {
|