@remoteoss/json-schema-form 0.11.9-dev.20241213082826 → 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 +5 -5
- package/dist/index.js +5 -5
- package/dist/standalone.js +5 -5
- package/package.json +2 -2
- package/src/tests/checkIfConditionMatches.test.js +57 -51
- package/src/tests/conditions.test.js +204 -42
- package/src/tests/createHeadlessForm.customValidations.test.js +2 -1
- package/src/tests/createHeadlessForm.test.js +1077 -1074
- 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({
|
|
@@ -2117,7 +2241,7 @@ describe('createHeadlessForm', () => {
|
|
|
2117
2241
|
expect(fieldValidator.isValidSync(false)).toBe(true);
|
|
2118
2242
|
expect(fieldValidator.isValidSync(undefined)).toBe(true);
|
|
2119
2243
|
expect(() => fieldValidator.validateSync('foo')).toThrowError(
|
|
2120
|
-
'
|
|
2244
|
+
'The value must be a boolean, but received "foo"'
|
|
2121
2245
|
);
|
|
2122
2246
|
});
|
|
2123
2247
|
|
|
@@ -2145,6 +2269,27 @@ describe('createHeadlessForm', () => {
|
|
|
2145
2269
|
default: true,
|
|
2146
2270
|
});
|
|
2147
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
|
+
});
|
|
2148
2293
|
});
|
|
2149
2294
|
});
|
|
2150
2295
|
|
|
@@ -2266,43 +2411,12 @@ describe('createHeadlessForm', () => {
|
|
|
2266
2411
|
'x-jsf-order': ['pets'],
|
|
2267
2412
|
});
|
|
2268
2413
|
|
|
2269
|
-
const fieldValidator = result.fields[0].schema;
|
|
2270
|
-
|
|
2271
|
-
expect(fieldValidator.isValidSync(0)).toBe(true);
|
|
2272
|
-
expect(fieldValidator.isValidSync(1)).toBe(true);
|
|
2273
|
-
expect(() => fieldValidator.validateSync('2')).toThrowError('The option "2" is not valid.');
|
|
2274
|
-
expect(fieldValidator.isValidSync(null)).toBe(true);
|
|
2275
|
-
});
|
|
2276
|
-
|
|
2277
|
-
describe('x-jsf-presentation attribute', () => {
|
|
2278
|
-
it('support field with "x-jsf-presentation.statement"', () => {
|
|
2279
|
-
const result = createHeadlessForm(schemaInputWithStatement);
|
|
2280
|
-
|
|
2281
|
-
expect(result).toMatchObject({
|
|
2282
|
-
fields: [
|
|
2283
|
-
{
|
|
2284
|
-
name: 'bonus',
|
|
2285
|
-
label: 'Bonus',
|
|
2286
|
-
type: 'text',
|
|
2287
|
-
statement: {
|
|
2288
|
-
description: 'This is a custom statement message.',
|
|
2289
|
-
inputType: 'statement',
|
|
2290
|
-
severity: 'info',
|
|
2291
|
-
},
|
|
2292
|
-
},
|
|
2293
|
-
{
|
|
2294
|
-
name: 'role',
|
|
2295
|
-
label: 'Role',
|
|
2296
|
-
type: 'text',
|
|
2297
|
-
statement: {
|
|
2298
|
-
description: 'This is another statement message, but more severe.',
|
|
2299
|
-
inputType: 'statement',
|
|
2300
|
-
severity: 'warning',
|
|
2301
|
-
},
|
|
2302
|
-
},
|
|
2303
|
-
],
|
|
2304
|
-
});
|
|
2305
|
-
});
|
|
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);
|
|
2306
2420
|
});
|
|
2307
2421
|
|
|
2308
2422
|
describe('property misc attributes', () => {
|
|
@@ -2364,27 +2478,93 @@ describe('createHeadlessForm', () => {
|
|
|
2364
2478
|
});
|
|
2365
2479
|
});
|
|
2366
2480
|
|
|
2367
|
-
it('pass "description"
|
|
2368
|
-
const
|
|
2481
|
+
it('pass both root level "description" and "x-jsf-presentation.description"', () => {
|
|
2482
|
+
const resultsWithRootDescription = createHeadlessForm({
|
|
2369
2483
|
properties: {
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
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': {
|
|
2380
2496
|
inputType: 'text',
|
|
2497
|
+
// should override the root level description
|
|
2498
|
+
description: 'a different description with <span>markup</span>',
|
|
2381
2499
|
},
|
|
2382
2500
|
},
|
|
2383
2501
|
},
|
|
2502
|
+
required: ['username'],
|
|
2384
2503
|
});
|
|
2385
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
|
+
|
|
2386
2545
|
expect(result).toMatchObject({
|
|
2387
|
-
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
|
+
],
|
|
2388
2568
|
});
|
|
2389
2569
|
});
|
|
2390
2570
|
|
|
@@ -2457,7 +2637,7 @@ describe('createHeadlessForm', () => {
|
|
|
2457
2637
|
});
|
|
2458
2638
|
});
|
|
2459
2639
|
|
|
2460
|
-
it('
|
|
2640
|
+
it('pass scopedJsonSchema to each field', () => {
|
|
2461
2641
|
const { fields } = createHeadlessForm(schemaWithoutInputTypes, {
|
|
2462
2642
|
strictInputType: false,
|
|
2463
2643
|
});
|
|
@@ -2522,7 +2702,7 @@ describe('createHeadlessForm', () => {
|
|
|
2522
2702
|
expect(fieldsetByName).toEqual(['line_one', 'number', 'postal_code']);
|
|
2523
2703
|
});
|
|
2524
2704
|
|
|
2525
|
-
it('sorts fields based on original properties (
|
|
2705
|
+
it('sorts fields based on original properties (without x-jsf-order)', () => {
|
|
2526
2706
|
// Assert the sample schema has x-jsf-order
|
|
2527
2707
|
expect(schemaWithOrderKeyword['x-jsf-order']).toBeDefined();
|
|
2528
2708
|
|
|
@@ -2543,467 +2723,276 @@ describe('createHeadlessForm', () => {
|
|
|
2543
2723
|
});
|
|
2544
2724
|
});
|
|
2545
2725
|
|
|
2546
|
-
describe('
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
describe('and value is empty', () => {
|
|
2555
|
-
it('should throw an error', async () =>
|
|
2556
|
-
expect(
|
|
2557
|
-
object()
|
|
2558
|
-
.shape({
|
|
2559
|
-
test: fields[0].schema,
|
|
2560
|
-
})
|
|
2561
|
-
.validate({ test: '' })
|
|
2562
|
-
).rejects.toMatchObject({ errors: ['Required field'] }));
|
|
2563
|
-
});
|
|
2564
|
-
describe('and value is defined', () => {
|
|
2565
|
-
it('should validate field', async () => {
|
|
2566
|
-
const assertObj = { test: 'Hello' };
|
|
2567
|
-
return expect(
|
|
2568
|
-
object()
|
|
2569
|
-
.shape({
|
|
2570
|
-
test: fields[0].schema,
|
|
2571
|
-
})
|
|
2572
|
-
.validate(assertObj)
|
|
2573
|
-
).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;
|
|
2574
2734
|
});
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
fields = result.fields;
|
|
2585
|
-
});
|
|
2586
|
-
describe('and value is a string', () => {
|
|
2587
|
-
it('should throw an error', async () =>
|
|
2588
|
-
expect(
|
|
2589
|
-
object()
|
|
2590
|
-
.shape({
|
|
2591
|
-
test: fields[0].schema,
|
|
2592
|
-
})
|
|
2593
|
-
.validate({ test: 'Hello' })
|
|
2594
|
-
).rejects.toThrow());
|
|
2595
|
-
});
|
|
2596
|
-
describe('and value is a number', () => {
|
|
2597
|
-
it('should validate field', async () => {
|
|
2598
|
-
const assertObj = { test: 3 };
|
|
2599
|
-
return expect(
|
|
2600
|
-
object()
|
|
2601
|
-
.shape({
|
|
2602
|
-
test: fields[0].schema,
|
|
2603
|
-
})
|
|
2604
|
-
.validate(assertObj)
|
|
2605
|
-
).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'] }));
|
|
2606
2744
|
});
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
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);
|
|
2618
2755
|
});
|
|
2619
2756
|
});
|
|
2620
2757
|
});
|
|
2621
|
-
});
|
|
2622
2758
|
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
})
|
|
2631
|
-
);
|
|
2632
|
-
fields = result.fields;
|
|
2633
|
-
});
|
|
2634
|
-
describe('and value is greater than that', () => {
|
|
2635
|
-
it('should throw an error', async () =>
|
|
2636
|
-
expect(
|
|
2637
|
-
object()
|
|
2638
|
-
.shape({
|
|
2639
|
-
test: fields[0].schema,
|
|
2640
|
-
})
|
|
2641
|
-
.validate({ test: 'Hello Mr John Doe' })
|
|
2642
|
-
).rejects.toMatchObject({ errors: ['Please insert up to 10 characters'] }));
|
|
2643
|
-
});
|
|
2644
|
-
describe('and value is less than that', () => {
|
|
2645
|
-
it('should validate field', async () => {
|
|
2646
|
-
const assertObj = { test: 'Hello John' };
|
|
2647
|
-
return expect(
|
|
2648
|
-
object()
|
|
2649
|
-
.shape({
|
|
2650
|
-
test: fields[0].schema,
|
|
2651
|
-
})
|
|
2652
|
-
.validate(assertObj)
|
|
2653
|
-
).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;
|
|
2654
2766
|
});
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
inputFields: { minLength: 2 },
|
|
2665
|
-
})
|
|
2666
|
-
);
|
|
2667
|
-
fields = result.fields;
|
|
2668
|
-
});
|
|
2669
|
-
describe('and value is smaller than that', () => {
|
|
2670
|
-
it('should throw an error', async () =>
|
|
2671
|
-
expect(
|
|
2672
|
-
object()
|
|
2673
|
-
.shape({
|
|
2674
|
-
test: fields[0].schema,
|
|
2675
|
-
})
|
|
2676
|
-
.validate({ test: 'H' })
|
|
2677
|
-
).rejects.toMatchObject({ errors: ['Please insert at least 2 characters'] }));
|
|
2678
|
-
});
|
|
2679
|
-
describe('and value is greater than that', () => {
|
|
2680
|
-
it('should validate field', async () => {
|
|
2681
|
-
const assertObj = { test: 'Hello John' };
|
|
2682
|
-
return expect(
|
|
2683
|
-
object()
|
|
2684
|
-
.shape({
|
|
2685
|
-
test: fields[0].schema,
|
|
2686
|
-
})
|
|
2687
|
-
.validate(assertObj)
|
|
2688
|
-
).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());
|
|
2689
2776
|
});
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
})
|
|
2701
|
-
);
|
|
2702
|
-
fields = result.fields;
|
|
2703
|
-
});
|
|
2704
|
-
|
|
2705
|
-
describe('and value is less than that', () => {
|
|
2706
|
-
it('should throw an error', async () =>
|
|
2707
|
-
expect(
|
|
2708
|
-
object()
|
|
2709
|
-
.shape({
|
|
2710
|
-
test: fields[0].schema,
|
|
2711
|
-
})
|
|
2712
|
-
.validate({ test: -1 })
|
|
2713
|
-
).rejects.toMatchObject({ errors: ['Must be greater or equal to 0'] }));
|
|
2714
|
-
});
|
|
2715
|
-
|
|
2716
|
-
describe('and value is greater than that', () => {
|
|
2717
|
-
it('should validate field', async () => {
|
|
2718
|
-
const assertObj = { test: 4 };
|
|
2719
|
-
return expect(
|
|
2720
|
-
object()
|
|
2721
|
-
.shape({
|
|
2722
|
-
test: fields[0].schema,
|
|
2723
|
-
})
|
|
2724
|
-
.validate(assertObj)
|
|
2725
|
-
).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
|
+
});
|
|
2726
2788
|
});
|
|
2727
|
-
|
|
2728
|
-
|
|
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));
|
|
2729
2793
|
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
beforeEach(() => {
|
|
2733
|
-
const result = createHeadlessForm(
|
|
2734
|
-
buildJSONSchemaInput({
|
|
2735
|
-
presentationFields: { inputType: 'number' },
|
|
2736
|
-
inputFields: { maximum: 10 },
|
|
2737
|
-
})
|
|
2738
|
-
);
|
|
2739
|
-
fields = result.fields;
|
|
2740
|
-
});
|
|
2741
|
-
|
|
2742
|
-
describe('and value is greater than that', () => {
|
|
2743
|
-
it('should throw an error', async () =>
|
|
2744
|
-
expect(
|
|
2745
|
-
object()
|
|
2746
|
-
.shape({
|
|
2747
|
-
test: fields[0].schema,
|
|
2748
|
-
})
|
|
2749
|
-
.validate({ test: 11 })
|
|
2750
|
-
).rejects.toMatchObject({ errors: ['Must be smaller or equal to 10'] }));
|
|
2751
|
-
});
|
|
2794
|
+
expect(validateForm({ tabs: '0' })).toBeUndefined();
|
|
2795
|
+
expect(validateForm({ tabs: '-10' })).toBeUndefined();
|
|
2752
2796
|
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
object()
|
|
2758
|
-
.shape({
|
|
2759
|
-
test: fields[0].schema,
|
|
2760
|
-
})
|
|
2761
|
-
.validate(assertObj)
|
|
2762
|
-
).resolves.toEqual(assertObj);
|
|
2797
|
+
expect(validateForm({ tabs: 1 })).toEqual({
|
|
2798
|
+
tabs: 'Must be smaller or equal to 0',
|
|
2799
|
+
});
|
|
2800
|
+
});
|
|
2763
2801
|
});
|
|
2764
2802
|
});
|
|
2765
|
-
});
|
|
2766
2803
|
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
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
|
-
|
|
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
|
+
});
|
|
2798
2836
|
});
|
|
2799
2837
|
});
|
|
2800
|
-
});
|
|
2801
|
-
|
|
2802
|
-
describe('when a field has max file size', () => {
|
|
2803
|
-
let fields;
|
|
2804
|
-
beforeEach(() => {
|
|
2805
|
-
const result = createHeadlessForm(
|
|
2806
|
-
JSONSchemaBuilder().addInput({ fileInput: mockFileInput }).build()
|
|
2807
|
-
);
|
|
2808
|
-
fields = result.fields;
|
|
2809
|
-
});
|
|
2810
|
-
describe('and file is greater than that', () => {
|
|
2811
|
-
const file = new File([''], 'file.png');
|
|
2812
|
-
Object.defineProperty(file, 'size', { value: 1024 * 1024 * 1024 });
|
|
2813
|
-
|
|
2814
|
-
it('should throw an error', async () =>
|
|
2815
|
-
expect(
|
|
2816
|
-
object()
|
|
2817
|
-
.shape({
|
|
2818
|
-
fileInput: fields[0].schema,
|
|
2819
|
-
})
|
|
2820
|
-
.validate({ fileInput: [file] })
|
|
2821
|
-
).rejects.toMatchObject({ errors: ['File size too large. The limit is 20 MB.'] }));
|
|
2822
|
-
});
|
|
2823
|
-
describe('and file is smaller than that', () => {
|
|
2824
|
-
const file = new File([''], 'file.png');
|
|
2825
|
-
Object.defineProperty(file, 'size', { value: 1024 * 1024 });
|
|
2826
|
-
|
|
2827
|
-
const assertObj = { fileInput: [file] };
|
|
2828
|
-
it('should validate field', async () =>
|
|
2829
|
-
expect(
|
|
2830
|
-
object()
|
|
2831
|
-
.shape({
|
|
2832
|
-
fileInput: fields[0].schema,
|
|
2833
|
-
})
|
|
2834
|
-
.validate({ fileInput: [file] })
|
|
2835
|
-
).resolves.toEqual(assertObj));
|
|
2836
|
-
});
|
|
2837
|
-
});
|
|
2838
2838
|
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
object()
|
|
2847
|
-
.shape({
|
|
2848
|
-
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 },
|
|
2849
2846
|
})
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
});
|
|
2853
|
-
|
|
2854
|
-
it('it validates missing file correctly', () => {
|
|
2855
|
-
const { handleValidation } = createHeadlessForm(
|
|
2856
|
-
JSONSchemaBuilder().addInput({ fileInput: mockFileInput }).build()
|
|
2857
|
-
);
|
|
2858
|
-
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
2859
|
-
|
|
2860
|
-
expect(validateForm({})).toBeUndefined();
|
|
2861
|
-
expect(validateForm({ fileInput: null })).toBeUndefined();
|
|
2862
|
-
});
|
|
2863
|
-
});
|
|
2864
|
-
|
|
2865
|
-
describe('when a field file is required', () => {
|
|
2866
|
-
it('it validates missing file correctly', () => {
|
|
2867
|
-
const { handleValidation } = createHeadlessForm(schemaInputTypeFile);
|
|
2868
|
-
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
2869
|
-
|
|
2870
|
-
expect(validateForm({})).toEqual({
|
|
2871
|
-
a_file: 'Required field',
|
|
2847
|
+
);
|
|
2848
|
+
fields = result.fields;
|
|
2872
2849
|
});
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
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
|
+
});
|
|
2880
2871
|
});
|
|
2881
2872
|
});
|
|
2882
|
-
});
|
|
2883
2873
|
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
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;
|
|
2895
2884
|
});
|
|
2896
2885
|
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
errors: ['
|
|
2906
|
-
}));
|
|
2907
|
-
});
|
|
2908
|
-
describe('and file is of correct format', () => {
|
|
2909
|
-
const file = new File(['foo'], 'file.png', {
|
|
2910
|
-
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'] }));
|
|
2911
2895
|
});
|
|
2912
|
-
Object.defineProperty(file, 'size', { value: 1024 * 1024 });
|
|
2913
2896
|
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
describe('and file is of correct but uppercase format ', () => {
|
|
2926
|
-
const file = new File(['foo'], 'file.PNG', {
|
|
2927
|
-
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
|
+
});
|
|
2928
2908
|
});
|
|
2929
|
-
Object.defineProperty(file, 'size', { value: 1024 * 1024 });
|
|
2930
|
-
|
|
2931
|
-
const assertObj = { fileInput: [file] };
|
|
2932
|
-
it('should validate field', async () =>
|
|
2933
|
-
expect(
|
|
2934
|
-
object()
|
|
2935
|
-
.shape({
|
|
2936
|
-
fileInput: fields[0].schema,
|
|
2937
|
-
})
|
|
2938
|
-
.validate({ fileInput: [file] })
|
|
2939
|
-
).resolves.toEqual(assertObj));
|
|
2940
2909
|
});
|
|
2941
2910
|
|
|
2942
|
-
describe('
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
}
|
|
2949
|
-
|
|
2950
|
-
)
|
|
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;
|
|
2951
2921
|
});
|
|
2952
2922
|
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
errors: ['
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
it('should validate max size', async () =>
|
|
2965
|
-
expect(
|
|
2966
|
-
object()
|
|
2967
|
-
.shape({
|
|
2968
|
-
fileInput: fields[0].schema,
|
|
2969
|
-
})
|
|
2970
|
-
.validate({ fileInput: [{ name: 'foo.txt', size: 1024 * 1024 * 1024 }] })
|
|
2971
|
-
).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
|
+
});
|
|
2972
2933
|
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
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
|
+
});
|
|
2981
2946
|
});
|
|
2982
|
-
});
|
|
2983
2947
|
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
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
|
+
});
|
|
2991
2980
|
});
|
|
2992
|
-
|
|
2993
|
-
expect(fields[0].statement.description).toBe(`<a href="">conditional statement markup</a>`);
|
|
2994
2981
|
});
|
|
2995
2982
|
});
|
|
2996
2983
|
|
|
2997
|
-
describe('
|
|
2984
|
+
describe('even more validations', () => {
|
|
2998
2985
|
describe('and all fields are optional', () => {
|
|
2999
2986
|
let handleValidation;
|
|
3000
2987
|
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
3001
2988
|
|
|
3002
2989
|
beforeEach(() => {
|
|
3003
|
-
const result =
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
2990
|
+
const result = {
|
|
2991
|
+
properties: {
|
|
2992
|
+
textInput: mockTextInput,
|
|
2993
|
+
numberInput: mockNumberInput,
|
|
2994
|
+
},
|
|
2995
|
+
};
|
|
3007
2996
|
const { handleValidation: handleValidationEach } = createHeadlessForm(result);
|
|
3008
2997
|
handleValidation = handleValidationEach;
|
|
3009
2998
|
});
|
|
@@ -3034,11 +3023,13 @@ describe('createHeadlessForm', () => {
|
|
|
3034
3023
|
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
3035
3024
|
|
|
3036
3025
|
beforeEach(() => {
|
|
3037
|
-
const result =
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3026
|
+
const result = {
|
|
3027
|
+
properties: {
|
|
3028
|
+
textInput: mockTextInput,
|
|
3029
|
+
numberInput: mockNumberInput,
|
|
3030
|
+
},
|
|
3031
|
+
required: ['numberInput', 'textInput'],
|
|
3032
|
+
};
|
|
3042
3033
|
const { handleValidation: handleValidationEach } = createHeadlessForm(result);
|
|
3043
3034
|
handleValidation = handleValidationEach;
|
|
3044
3035
|
});
|
|
@@ -3865,7 +3856,19 @@ describe('createHeadlessForm', () => {
|
|
|
3865
3856
|
});
|
|
3866
3857
|
});
|
|
3867
3858
|
|
|
3868
|
-
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
|
+
});
|
|
3869
3872
|
describe('and "fieldset" has scoped conditionals', () => {
|
|
3870
3873
|
it('should show conditionals fields when values fullfil conditions', () => {
|
|
3871
3874
|
const result = createHeadlessForm(schemaFieldsetScopedCondition, {
|