@evoke-platform/ui-components 1.10.0-dev.3 → 1.10.0-dev.31
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/dist/published/components/core/Autocomplete/Autocomplete.js +4 -2
- package/dist/published/components/core/Autocomplete/Autocomplete.test.js +112 -3
- package/dist/published/components/core/TextField/TextField.js +1 -1
- package/dist/published/components/core/TextField/TextField.test.js +0 -2
- package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.js +1 -1
- package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.test.d.ts +1 -0
- package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.test.js +428 -0
- package/dist/published/components/custom/CriteriaBuilder/ValueEditor.js +19 -6
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableField.js +1 -1
- package/dist/published/components/custom/Form/tests/Form.test.js +0 -2
- package/dist/published/components/custom/Form/utils.js +1 -0
- package/dist/published/components/custom/FormField/DatePickerSelect/DatePickerSelect.js +14 -1
- package/dist/published/components/custom/FormField/DateTimePickerSelect/DateTimePickerSelect.js +14 -1
- package/dist/published/components/custom/FormField/InputFieldComponent/InputFieldComponent.test.js +0 -2
- package/dist/published/components/custom/FormField/Select/Select.test.js +0 -2
- package/dist/published/components/custom/FormField/TimePickerSelect/TimePickerSelect.js +14 -1
- package/dist/published/components/custom/FormV2/FormRenderer.d.ts +2 -1
- package/dist/published/components/custom/FormV2/FormRenderer.js +19 -7
- package/dist/published/components/custom/FormV2/FormRendererContainer.js +117 -74
- package/dist/published/components/custom/FormV2/components/AccordionSections.js +7 -2
- package/dist/published/components/custom/FormV2/components/Body.d.ts +1 -1
- package/dist/published/components/custom/FormV2/components/FieldWrapper.js +1 -1
- package/dist/published/components/custom/FormV2/components/Footer.d.ts +1 -0
- package/dist/published/components/custom/FormV2/components/Footer.js +8 -5
- package/dist/published/components/custom/FormV2/components/FormContext.d.ts +3 -2
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/AddressFields.d.ts +9 -0
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/AddressFields.js +32 -15
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/ActionDialog.js +2 -2
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/RepeatableField.d.ts +0 -3
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/RepeatableField.js +36 -49
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/Criteria.js +16 -3
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/Document.js +16 -4
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/DocumentList.d.ts +2 -1
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/DocumentList.js +16 -3
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/Image.js +31 -5
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/UserProperty.js +15 -3
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/ObjectPropertyInput.js +109 -81
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/RelatedObjectInstance.js +38 -16
- package/dist/published/components/custom/FormV2/components/Header.d.ts +5 -3
- package/dist/published/components/custom/FormV2/components/Header.js +47 -9
- package/dist/published/components/custom/FormV2/components/RecursiveEntryRenderer.js +46 -35
- package/dist/published/components/custom/FormV2/components/ValidationFiles/ValidationErrors.js +1 -1
- package/dist/published/components/custom/FormV2/components/types.d.ts +1 -0
- package/dist/published/components/custom/FormV2/components/utils.d.ts +4 -4
- package/dist/published/components/custom/FormV2/components/utils.js +13 -16
- package/dist/published/components/custom/FormV2/tests/FormRenderer.test.js +289 -45
- package/dist/published/components/custom/FormV2/tests/FormRendererContainer.test.js +664 -16
- package/dist/published/components/custom/FormV2/tests/test-data.d.ts +1 -0
- package/dist/published/components/custom/FormV2/tests/test-data.js +140 -0
- package/dist/published/components/custom/ViewDetailsV2/InstanceEntryRenderer.d.ts +3 -0
- package/dist/published/components/custom/ViewDetailsV2/InstanceEntryRenderer.js +155 -0
- package/dist/published/components/custom/ViewDetailsV2/ViewDetailsV2Container.d.ts +13 -0
- package/dist/published/components/custom/ViewDetailsV2/ViewDetailsV2Container.js +144 -0
- package/dist/published/components/custom/ViewDetailsV2/index.d.ts +3 -0
- package/dist/published/components/custom/ViewDetailsV2/index.js +2 -0
- package/dist/published/components/custom/index.d.ts +2 -0
- package/dist/published/components/custom/index.js +1 -0
- package/dist/published/index.d.ts +6 -6
- package/dist/published/index.js +1 -1
- package/dist/published/stories/FormRenderer.stories.d.ts +8 -4
- package/dist/published/stories/FormRendererContainer.stories.d.ts +26 -0
- package/dist/published/stories/FormRendererContainer.stories.js +5 -0
- package/dist/published/stories/FormRendererData.d.ts +12 -0
- package/dist/published/stories/FormRendererData.js +29 -44
- package/dist/published/stories/ViewDetailsV2Container.stories.d.ts +26 -0
- package/dist/published/stories/ViewDetailsV2Container.stories.js +37 -0
- package/dist/published/stories/ViewDetailsV2Data.d.ts +4 -0
- package/dist/published/stories/ViewDetailsV2Data.js +203 -0
- package/dist/published/stories/sharedMswHandlers.js +49 -10
- package/dist/published/theme/hooks.d.ts +4 -3
- package/package.json +12 -8
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as matchers from '@testing-library/jest-dom/matchers';
|
|
2
1
|
import { render as baseRender, screen, waitFor, within } from '@testing-library/react';
|
|
3
2
|
import userEvent from '@testing-library/user-event';
|
|
4
3
|
import { isEmpty, isEqual, set } from 'lodash';
|
|
@@ -9,7 +8,6 @@ import { MemoryRouter } from 'react-router-dom';
|
|
|
9
8
|
import { expect, it } from 'vitest';
|
|
10
9
|
import FormRenderer from '../FormRenderer';
|
|
11
10
|
import { accessibility508Object, createSpecialtyForm, jsonLogicDisplayTestSpecialtyForm, licenseObject, npLicense, npSpecialtyType1, npSpecialtyType2, rnLicense, rnSpecialtyType1, rnSpecialtyType2, simpleConditionDisplayTestSpecialtyForm, specialtyObject, specialtyTypeObject, UpdateAccessibilityFormOne, UpdateAccessibilityFormTwo, users, } from './test-data';
|
|
12
|
-
expect.extend(matchers);
|
|
13
11
|
// Mock ResizeObserver
|
|
14
12
|
global.ResizeObserver = class ResizeObserver {
|
|
15
13
|
observe() { }
|
|
@@ -20,7 +18,7 @@ const WithProviders = ({ children }) => {
|
|
|
20
18
|
return React.createElement(MemoryRouter, null, children);
|
|
21
19
|
};
|
|
22
20
|
const render = (ui, options) => baseRender(ui, { wrapper: WithProviders, ...options });
|
|
23
|
-
describe('
|
|
21
|
+
describe('FormRenderer', () => {
|
|
24
22
|
let server;
|
|
25
23
|
beforeAll(() => {
|
|
26
24
|
server = setupServer(http.get('/api/data/objects/specialtyType/effective', () => HttpResponse.json(specialtyTypeObject)), http.get('/api/data/objects/specialtyType/effective', (req) => {
|
|
@@ -59,9 +57,9 @@ describe('Form component', () => {
|
|
|
59
57
|
npSpecialtyType1,
|
|
60
58
|
npSpecialtyType2,
|
|
61
59
|
]);
|
|
62
|
-
else if (isEqual(whereFilter, {
|
|
60
|
+
else if (isEqual(whereFilter, { 'licenseType.id': 'rnLicenseType' }))
|
|
63
61
|
return HttpResponse.json([rnSpecialtyType1, rnSpecialtyType2]);
|
|
64
|
-
else if (isEqual(whereFilter, {
|
|
62
|
+
else if (isEqual(whereFilter, { 'licenseType.id': 'npLicenseType' }))
|
|
65
63
|
return HttpResponse.json([npSpecialtyType1, npSpecialtyType2]);
|
|
66
64
|
}
|
|
67
65
|
}), http.get('/api/accessManagement/users', () => HttpResponse.json(users)));
|
|
@@ -650,13 +648,19 @@ describe('Form component', () => {
|
|
|
650
648
|
parameterId: 'specialtyType',
|
|
651
649
|
display: {
|
|
652
650
|
label: 'Speciality Type',
|
|
651
|
+
createActionId: '_create',
|
|
653
652
|
},
|
|
654
653
|
},
|
|
655
654
|
],
|
|
656
655
|
actionId: '_update',
|
|
657
656
|
objectId: 'relatedObjectTestForm',
|
|
658
657
|
};
|
|
658
|
+
let scrollIntoViewMock;
|
|
659
|
+
let originalScrollIntoView;
|
|
659
660
|
beforeEach(async () => {
|
|
661
|
+
scrollIntoViewMock = vitest.fn();
|
|
662
|
+
originalScrollIntoView = Element.prototype.scrollIntoView;
|
|
663
|
+
Element.prototype.scrollIntoView = scrollIntoViewMock;
|
|
660
664
|
const relatedObjectTestFormObject = {
|
|
661
665
|
id: 'relatedObjectTestForm',
|
|
662
666
|
name: 'Related Object Test Form',
|
|
@@ -693,9 +697,20 @@ describe('Form component', () => {
|
|
|
693
697
|
type: 'content',
|
|
694
698
|
html: '<div>Specialty Type Form Content</div>',
|
|
695
699
|
},
|
|
700
|
+
{
|
|
701
|
+
type: 'input',
|
|
702
|
+
parameterId: 'requiredField',
|
|
703
|
+
display: {
|
|
704
|
+
label: 'Required Field',
|
|
705
|
+
required: true,
|
|
706
|
+
},
|
|
707
|
+
},
|
|
696
708
|
],
|
|
697
709
|
actionId: '_create',
|
|
698
710
|
objectId: 'specialtyType',
|
|
711
|
+
display: {
|
|
712
|
+
submitLabel: 'Create Specialty Type',
|
|
713
|
+
},
|
|
699
714
|
};
|
|
700
715
|
const specialtyTypeObject = {
|
|
701
716
|
id: 'specialtyType',
|
|
@@ -705,7 +720,14 @@ describe('Form component', () => {
|
|
|
705
720
|
id: '_create',
|
|
706
721
|
name: 'Create',
|
|
707
722
|
type: 'create',
|
|
708
|
-
parameters: [
|
|
723
|
+
parameters: [
|
|
724
|
+
{
|
|
725
|
+
id: 'requiredField',
|
|
726
|
+
name: 'Required Field',
|
|
727
|
+
type: 'string',
|
|
728
|
+
required: true,
|
|
729
|
+
},
|
|
730
|
+
],
|
|
709
731
|
outputEvent: 'created',
|
|
710
732
|
defaultFormId: 'specialtyTypeForm',
|
|
711
733
|
},
|
|
@@ -721,6 +743,9 @@ describe('Form component', () => {
|
|
|
721
743
|
};
|
|
722
744
|
setupTestMocks(specialtyTypeObject, specialtyTypeForm);
|
|
723
745
|
});
|
|
746
|
+
afterEach(() => {
|
|
747
|
+
Element.prototype.scrollIntoView = originalScrollIntoView;
|
|
748
|
+
});
|
|
724
749
|
it('displays an add button for related object fields', async () => {
|
|
725
750
|
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
726
751
|
await screen.findByRole('button', { name: 'Add' });
|
|
@@ -813,6 +838,63 @@ describe('Form component', () => {
|
|
|
813
838
|
await user.click(newRecordButton);
|
|
814
839
|
await screen.findByText(/not found/i);
|
|
815
840
|
});
|
|
841
|
+
it('should show validation errors in record creation mode', async () => {
|
|
842
|
+
const user = userEvent.setup();
|
|
843
|
+
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
844
|
+
await user.click(await screen.findByRole('button', { name: 'Add' }));
|
|
845
|
+
const newRecordButton = await screen.findByRole('radio', { name: /new/i });
|
|
846
|
+
await user.click(newRecordButton);
|
|
847
|
+
const createSpecialtyTypeButton = await screen.findByRole('button', {
|
|
848
|
+
name: /create specialty type/i,
|
|
849
|
+
});
|
|
850
|
+
await user.click(createSpecialtyTypeButton);
|
|
851
|
+
const errorMessage = await screen.findByRole('listitem');
|
|
852
|
+
expect(errorMessage).toHaveTextContent('Required Field is required');
|
|
853
|
+
});
|
|
854
|
+
it('should clear validation errors after they have been resolved', async () => {
|
|
855
|
+
const user = userEvent.setup();
|
|
856
|
+
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
857
|
+
await user.click(await screen.findByRole('button', { name: 'Add' }));
|
|
858
|
+
const newRecordButton = await screen.findByRole('radio', { name: /new/i });
|
|
859
|
+
await user.click(newRecordButton);
|
|
860
|
+
const createSpecialtyTypeButton = await screen.findByRole('button', {
|
|
861
|
+
name: /create specialty type/i,
|
|
862
|
+
});
|
|
863
|
+
await user.click(createSpecialtyTypeButton);
|
|
864
|
+
// Make sure error elements appear
|
|
865
|
+
screen.getByRole('listitem');
|
|
866
|
+
const requiredField = screen.getByRole('textbox', { name: /Required Field */i });
|
|
867
|
+
await user.type(requiredField, 'Some content here...');
|
|
868
|
+
expect(screen.queryByRole('listitem')).not.toBeInTheDocument();
|
|
869
|
+
});
|
|
870
|
+
it('should scroll to validation errors after submission', async () => {
|
|
871
|
+
const user = userEvent.setup();
|
|
872
|
+
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
873
|
+
await user.click(await screen.findByRole('button', { name: 'Add' }));
|
|
874
|
+
const newRecordButton = await screen.findByRole('radio', { name: /new/i });
|
|
875
|
+
await user.click(newRecordButton);
|
|
876
|
+
const createSpecialtyTypeButton = await screen.findByRole('button', {
|
|
877
|
+
name: /create specialty type/i,
|
|
878
|
+
});
|
|
879
|
+
await user.click(createSpecialtyTypeButton);
|
|
880
|
+
expect(scrollIntoViewMock).toHaveBeenCalled();
|
|
881
|
+
});
|
|
882
|
+
it('should not scroll to validation errors if there are none', async () => async () => {
|
|
883
|
+
const user = userEvent.setup();
|
|
884
|
+
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
885
|
+
await user.click(await screen.findByRole('button', { name: 'Add' }));
|
|
886
|
+
const newRecordButton = await screen.findByRole('radio', { name: /new/i });
|
|
887
|
+
await user.click(newRecordButton);
|
|
888
|
+
// Make sure error elements appear
|
|
889
|
+
screen.getByRole('listitem');
|
|
890
|
+
const requiredField = await screen.findByRole('textbox', { name: /Required Field */i });
|
|
891
|
+
await user.type(requiredField, 'Some content here...');
|
|
892
|
+
const createSpecialtyTypeButton = await screen.findByRole('button', {
|
|
893
|
+
name: /create specialty type/i,
|
|
894
|
+
});
|
|
895
|
+
await user.click(createSpecialtyTypeButton);
|
|
896
|
+
expect(scrollIntoViewMock).not.toHaveBeenCalled();
|
|
897
|
+
});
|
|
816
898
|
});
|
|
817
899
|
});
|
|
818
900
|
describe('when in dropdown view', () => {
|
|
@@ -913,24 +995,25 @@ describe('Form component', () => {
|
|
|
913
995
|
});
|
|
914
996
|
describe('when mode is default (allows both new and existing)', () => {
|
|
915
997
|
const form = {
|
|
916
|
-
id: '
|
|
998
|
+
id: 'dropdownRelatedObjectTestForm',
|
|
917
999
|
name: 'Related Object Test Form',
|
|
918
1000
|
entries: [
|
|
919
1001
|
{
|
|
920
1002
|
type: 'input',
|
|
921
|
-
parameterId: '
|
|
1003
|
+
parameterId: 'licenseType',
|
|
922
1004
|
display: {
|
|
923
|
-
label: '
|
|
1005
|
+
label: 'License Type',
|
|
924
1006
|
relatedObjectDisplay: 'dropdown',
|
|
1007
|
+
createActionId: '_create',
|
|
925
1008
|
},
|
|
926
1009
|
},
|
|
927
1010
|
],
|
|
928
1011
|
actionId: '_update',
|
|
929
|
-
objectId: '
|
|
1012
|
+
objectId: 'dropdownRelatedTestObject',
|
|
930
1013
|
};
|
|
931
1014
|
beforeEach(() => {
|
|
932
|
-
const
|
|
933
|
-
id: '
|
|
1015
|
+
const dropdownRelatedTestObject = {
|
|
1016
|
+
id: 'dropdownRelatedTestObject',
|
|
934
1017
|
name: 'Related Object Test Form',
|
|
935
1018
|
actions: [
|
|
936
1019
|
{
|
|
@@ -939,10 +1022,10 @@ describe('Form component', () => {
|
|
|
939
1022
|
type: 'update',
|
|
940
1023
|
parameters: [
|
|
941
1024
|
{
|
|
942
|
-
id: '
|
|
1025
|
+
id: 'licenseType',
|
|
943
1026
|
name: 'Related Object',
|
|
944
1027
|
type: 'object',
|
|
945
|
-
objectId: '
|
|
1028
|
+
objectId: 'licenseType',
|
|
946
1029
|
},
|
|
947
1030
|
],
|
|
948
1031
|
outputEvent: 'updated',
|
|
@@ -950,45 +1033,61 @@ describe('Form component', () => {
|
|
|
950
1033
|
],
|
|
951
1034
|
properties: [
|
|
952
1035
|
{
|
|
953
|
-
id: '
|
|
1036
|
+
id: 'licenseType',
|
|
954
1037
|
name: 'Related Object',
|
|
955
1038
|
type: 'object',
|
|
1039
|
+
objectId: 'licenseType',
|
|
956
1040
|
},
|
|
957
1041
|
],
|
|
958
1042
|
};
|
|
959
|
-
setupTestMocks(
|
|
960
|
-
const
|
|
961
|
-
id: '
|
|
962
|
-
name: '
|
|
1043
|
+
setupTestMocks(dropdownRelatedTestObject, form);
|
|
1044
|
+
const licenseTypeObject = {
|
|
1045
|
+
id: 'licenseType',
|
|
1046
|
+
name: 'License Type',
|
|
963
1047
|
actions: [
|
|
964
1048
|
{
|
|
965
1049
|
id: '_create',
|
|
966
1050
|
name: 'Create',
|
|
967
1051
|
type: 'create',
|
|
968
|
-
parameters: [
|
|
1052
|
+
parameters: [
|
|
1053
|
+
{
|
|
1054
|
+
type: 'string',
|
|
1055
|
+
id: 'name',
|
|
1056
|
+
name: 'License Type Name',
|
|
1057
|
+
},
|
|
1058
|
+
],
|
|
969
1059
|
outputEvent: 'created',
|
|
970
|
-
defaultFormId: '
|
|
1060
|
+
defaultFormId: 'licenseTypeForm',
|
|
1061
|
+
},
|
|
1062
|
+
],
|
|
1063
|
+
properties: [
|
|
1064
|
+
{
|
|
1065
|
+
type: 'string',
|
|
1066
|
+
id: 'name',
|
|
1067
|
+
name: 'License Type Name',
|
|
971
1068
|
},
|
|
972
1069
|
],
|
|
973
|
-
properties: [],
|
|
974
1070
|
};
|
|
975
|
-
const
|
|
976
|
-
id: '
|
|
977
|
-
name: '
|
|
1071
|
+
const licenseTypeForm = {
|
|
1072
|
+
id: 'licenseTypeForm',
|
|
1073
|
+
name: 'License Type Form',
|
|
978
1074
|
entries: [
|
|
979
1075
|
{
|
|
980
|
-
type: '
|
|
981
|
-
|
|
1076
|
+
type: 'input',
|
|
1077
|
+
parameterId: 'name',
|
|
1078
|
+
display: {
|
|
1079
|
+
label: 'License Type Name',
|
|
1080
|
+
},
|
|
982
1081
|
},
|
|
983
1082
|
],
|
|
984
1083
|
actionId: '_create',
|
|
985
|
-
objectId: '
|
|
1084
|
+
objectId: 'licenseType',
|
|
986
1085
|
};
|
|
987
|
-
setupTestMocks(
|
|
1086
|
+
setupTestMocks(licenseTypeObject, licenseTypeForm, [
|
|
988
1087
|
{
|
|
989
|
-
id: '
|
|
990
|
-
name: '
|
|
991
|
-
objectId: '
|
|
1088
|
+
id: 'licenseType1',
|
|
1089
|
+
name: 'License Type #1',
|
|
1090
|
+
objectId: 'licenseType',
|
|
992
1091
|
},
|
|
993
1092
|
]);
|
|
994
1093
|
});
|
|
@@ -996,27 +1095,34 @@ describe('Form component', () => {
|
|
|
996
1095
|
const user = userEvent.setup();
|
|
997
1096
|
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
998
1097
|
// Navigate to and open dropdown
|
|
999
|
-
const dropdown = await screen.findByRole('combobox', { name: '
|
|
1098
|
+
const dropdown = await screen.findByRole('combobox', { name: 'License Type' });
|
|
1000
1099
|
await user.click(dropdown);
|
|
1001
|
-
await
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1100
|
+
await screen.findByRole('listbox');
|
|
1101
|
+
await user.click(await screen.findByRole('option', { name: '+ Add New' }));
|
|
1102
|
+
});
|
|
1103
|
+
it('opens create related object instance form in dialog when add new is clicked', async () => {
|
|
1104
|
+
const user = userEvent.setup();
|
|
1105
|
+
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
1106
|
+
// Navigate to and open dropdown
|
|
1107
|
+
const dropdown = await screen.findByRole('combobox', { name: 'License Type' });
|
|
1108
|
+
await user.click(dropdown);
|
|
1109
|
+
await screen.findByRole('listbox');
|
|
1110
|
+
await user.click(await screen.findByRole('option', { name: '+ Add New' }));
|
|
1005
1111
|
await screen.findByRole('dialog');
|
|
1006
|
-
await screen.
|
|
1112
|
+
await screen.findByRole('textbox', { name: 'License Type Name' });
|
|
1007
1113
|
});
|
|
1008
1114
|
it('allows related object instance selection', async () => {
|
|
1009
1115
|
const user = userEvent.setup();
|
|
1010
1116
|
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
1011
1117
|
// Navigate to and open dropdown
|
|
1012
|
-
const dropdown = await screen.findByRole('combobox', { name: '
|
|
1118
|
+
const dropdown = await screen.findByRole('combobox', { name: 'License Type' });
|
|
1013
1119
|
await user.click(dropdown);
|
|
1014
|
-
const option = await screen.findByRole('option', { name: '
|
|
1120
|
+
const option = await screen.findByRole('option', { name: 'License Type #1' });
|
|
1015
1121
|
await user.click(option);
|
|
1016
1122
|
// Verify option has been removed from the document
|
|
1017
1123
|
expect(option).not.toBeInTheDocument();
|
|
1018
1124
|
// Verify selection
|
|
1019
|
-
screen.getByText('
|
|
1125
|
+
screen.getByText('License Type #1');
|
|
1020
1126
|
});
|
|
1021
1127
|
});
|
|
1022
1128
|
});
|
|
@@ -1041,13 +1147,19 @@ describe('Form component', () => {
|
|
|
1041
1147
|
},
|
|
1042
1148
|
display: {
|
|
1043
1149
|
label: 'Collection',
|
|
1150
|
+
createActionId: '_create',
|
|
1044
1151
|
},
|
|
1045
1152
|
},
|
|
1046
1153
|
],
|
|
1047
1154
|
actionId: '_update',
|
|
1048
1155
|
objectId: 'testObjectForCollections',
|
|
1049
1156
|
};
|
|
1157
|
+
let scrollIntoViewMock;
|
|
1158
|
+
let originalScrollIntoView;
|
|
1050
1159
|
beforeEach(() => {
|
|
1160
|
+
scrollIntoViewMock = vitest.fn();
|
|
1161
|
+
originalScrollIntoView = Element.prototype.scrollIntoView;
|
|
1162
|
+
Element.prototype.scrollIntoView = scrollIntoViewMock;
|
|
1051
1163
|
const collectionFormObject = {
|
|
1052
1164
|
id: 'testObjectForCollections',
|
|
1053
1165
|
name: 'Object for one-to-many collections tests',
|
|
@@ -1105,6 +1217,7 @@ describe('Form component', () => {
|
|
|
1105
1217
|
objectId: 'testObjectForCollections',
|
|
1106
1218
|
},
|
|
1107
1219
|
],
|
|
1220
|
+
defaultFormId: 'collectionObjectForm',
|
|
1108
1221
|
},
|
|
1109
1222
|
],
|
|
1110
1223
|
};
|
|
@@ -1117,6 +1230,7 @@ describe('Form component', () => {
|
|
|
1117
1230
|
parameterId: 'name',
|
|
1118
1231
|
display: {
|
|
1119
1232
|
label: 'Name',
|
|
1233
|
+
required: true,
|
|
1120
1234
|
},
|
|
1121
1235
|
},
|
|
1122
1236
|
{
|
|
@@ -1130,9 +1244,15 @@ describe('Form component', () => {
|
|
|
1130
1244
|
],
|
|
1131
1245
|
actionId: '_create',
|
|
1132
1246
|
objectId: 'collectionObject',
|
|
1247
|
+
display: {
|
|
1248
|
+
submitLabel: 'Create Collection Item',
|
|
1249
|
+
},
|
|
1133
1250
|
};
|
|
1134
1251
|
setupTestMocks(collectionObject, collectionObjectForm);
|
|
1135
1252
|
});
|
|
1253
|
+
afterEach(() => {
|
|
1254
|
+
Element.prototype.scrollIntoView = originalScrollIntoView;
|
|
1255
|
+
});
|
|
1136
1256
|
it('should render collection field', async () => {
|
|
1137
1257
|
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
1138
1258
|
await screen.findByText('Collection');
|
|
@@ -1191,7 +1311,7 @@ describe('Form component', () => {
|
|
|
1191
1311
|
const user = userEvent.setup();
|
|
1192
1312
|
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
1193
1313
|
await user.click(await screen.findByRole('button', { name: 'Add' }));
|
|
1194
|
-
await screen.findByRole('button', { name: '
|
|
1314
|
+
await screen.findByRole('button', { name: 'Create Collection Item' });
|
|
1195
1315
|
});
|
|
1196
1316
|
it('should hide related object field in collection item form', async () => {
|
|
1197
1317
|
const user = userEvent.setup();
|
|
@@ -1200,7 +1320,7 @@ describe('Form component', () => {
|
|
|
1200
1320
|
await user.click(addButton);
|
|
1201
1321
|
await screen.findByRole('dialog');
|
|
1202
1322
|
// Make sure other form entry is present
|
|
1203
|
-
await screen.findByRole('textbox', { name: 'Name' });
|
|
1323
|
+
await screen.findByRole('textbox', { name: 'Name *' });
|
|
1204
1324
|
const relatedObjectField = screen.queryByRole('textbox', { name: 'Related Object' });
|
|
1205
1325
|
expect(relatedObjectField).not.toBeInTheDocument();
|
|
1206
1326
|
});
|
|
@@ -1219,12 +1339,136 @@ describe('Form component', () => {
|
|
|
1219
1339
|
const addButton = await screen.findByRole('button', { name: /add/i });
|
|
1220
1340
|
await user.click(addButton);
|
|
1221
1341
|
await screen.findByRole('dialog');
|
|
1222
|
-
const nameField = screen.getByRole('textbox', { name: 'Name' });
|
|
1342
|
+
const nameField = screen.getByRole('textbox', { name: 'Name *' });
|
|
1223
1343
|
await user.type(nameField, 'New Collection Item');
|
|
1224
|
-
const submitButton = screen.getByRole('button', { name: '
|
|
1344
|
+
const submitButton = screen.getByRole('button', { name: 'Create Collection Item' });
|
|
1225
1345
|
await user.click(submitButton);
|
|
1226
1346
|
await screen.findByRole('columnheader', { name: 'Name' });
|
|
1227
1347
|
screen.getByRole('cell', { name: 'New Collection Item' });
|
|
1228
1348
|
});
|
|
1349
|
+
it('should show validation errors', async () => {
|
|
1350
|
+
const user = userEvent.setup();
|
|
1351
|
+
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
1352
|
+
const addButton = await screen.findByRole('button', { name: /add/i });
|
|
1353
|
+
await user.click(addButton);
|
|
1354
|
+
await screen.findByRole('dialog');
|
|
1355
|
+
const submitButton = screen.getByRole('button', { name: 'Create Collection Item' });
|
|
1356
|
+
await user.click(submitButton);
|
|
1357
|
+
const errorMessage = await screen.findByRole('listitem');
|
|
1358
|
+
expect(errorMessage).toHaveTextContent('Name is required');
|
|
1359
|
+
});
|
|
1360
|
+
it('should hide validation errors after they have been resolved', async () => {
|
|
1361
|
+
const user = userEvent.setup();
|
|
1362
|
+
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
1363
|
+
const addButton = await screen.findByRole('button', { name: /add/i });
|
|
1364
|
+
await user.click(addButton);
|
|
1365
|
+
await screen.findByRole('dialog');
|
|
1366
|
+
const submitButton = screen.getByRole('button', { name: 'Create Collection Item' });
|
|
1367
|
+
await user.click(submitButton);
|
|
1368
|
+
// Make sure error elements appear
|
|
1369
|
+
screen.getByRole('listitem');
|
|
1370
|
+
const requiredField = screen.getByRole('textbox', { name: /Name */i });
|
|
1371
|
+
await user.type(requiredField, 'Some content here...');
|
|
1372
|
+
expect(screen.queryByRole('listitem')).not.toBeInTheDocument();
|
|
1373
|
+
});
|
|
1374
|
+
it('should scroll to validation errors on submit', async () => {
|
|
1375
|
+
const user = userEvent.setup();
|
|
1376
|
+
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
1377
|
+
const addButton = await screen.findByRole('button', { name: /add/i });
|
|
1378
|
+
await user.click(addButton);
|
|
1379
|
+
await screen.findByRole('dialog');
|
|
1380
|
+
const submitButton = screen.getByRole('button', { name: 'Create Collection Item' });
|
|
1381
|
+
await user.click(submitButton);
|
|
1382
|
+
expect(scrollIntoViewMock).toHaveBeenCalled();
|
|
1383
|
+
});
|
|
1384
|
+
it('should not scroll to validation errors if there are none', async () => async () => {
|
|
1385
|
+
const user = userEvent.setup();
|
|
1386
|
+
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
1387
|
+
const addButton = await screen.findByRole('button', { name: /add/i });
|
|
1388
|
+
await user.click(addButton);
|
|
1389
|
+
await screen.findByRole('dialog');
|
|
1390
|
+
const requiredField = await screen.findByRole('textbox', { name: /Name */i });
|
|
1391
|
+
await user.type(requiredField, 'Some content here...');
|
|
1392
|
+
const submitButton = screen.getByRole('button', { name: 'Create Collection Item' });
|
|
1393
|
+
await user.click(submitButton);
|
|
1394
|
+
expect(scrollIntoViewMock).not.toHaveBeenCalled();
|
|
1395
|
+
});
|
|
1396
|
+
});
|
|
1397
|
+
describe('when passed a text field entry', () => {
|
|
1398
|
+
it('should render text field', async () => {
|
|
1399
|
+
const form = {
|
|
1400
|
+
id: 'textFieldTestForm',
|
|
1401
|
+
name: 'Text Field Test Form',
|
|
1402
|
+
entries: [
|
|
1403
|
+
{
|
|
1404
|
+
type: 'inputField',
|
|
1405
|
+
input: {
|
|
1406
|
+
id: 'textField',
|
|
1407
|
+
type: 'string',
|
|
1408
|
+
},
|
|
1409
|
+
display: {
|
|
1410
|
+
label: 'Text Field',
|
|
1411
|
+
},
|
|
1412
|
+
},
|
|
1413
|
+
],
|
|
1414
|
+
actionId: '_update',
|
|
1415
|
+
objectId: 'textFieldTestObject',
|
|
1416
|
+
};
|
|
1417
|
+
const textFieldTestObject = {
|
|
1418
|
+
id: 'textFieldTestObject',
|
|
1419
|
+
name: 'Text Field Test Object',
|
|
1420
|
+
actions: [
|
|
1421
|
+
{
|
|
1422
|
+
id: '_update',
|
|
1423
|
+
name: 'Update',
|
|
1424
|
+
type: 'update',
|
|
1425
|
+
outputEvent: 'updated',
|
|
1426
|
+
},
|
|
1427
|
+
],
|
|
1428
|
+
properties: [],
|
|
1429
|
+
};
|
|
1430
|
+
server.use(http.get(`/api/data/objects/${textFieldTestObject.id}/effective`, () => HttpResponse.json(textFieldTestObject)));
|
|
1431
|
+
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
1432
|
+
await screen.findByRole('textbox', { name: 'Text Field' });
|
|
1433
|
+
});
|
|
1434
|
+
it('should allow text input in text field', async () => {
|
|
1435
|
+
const user = userEvent.setup();
|
|
1436
|
+
const form = {
|
|
1437
|
+
id: 'textFieldTestForm',
|
|
1438
|
+
name: 'Text Field Test Form',
|
|
1439
|
+
entries: [
|
|
1440
|
+
{
|
|
1441
|
+
type: 'inputField',
|
|
1442
|
+
input: {
|
|
1443
|
+
id: 'textField',
|
|
1444
|
+
type: 'string',
|
|
1445
|
+
},
|
|
1446
|
+
display: {
|
|
1447
|
+
label: 'Text Field',
|
|
1448
|
+
},
|
|
1449
|
+
},
|
|
1450
|
+
],
|
|
1451
|
+
actionId: '_update',
|
|
1452
|
+
objectId: 'textFieldTestObject',
|
|
1453
|
+
};
|
|
1454
|
+
const textFieldTestObject = {
|
|
1455
|
+
id: 'textFieldTestObject',
|
|
1456
|
+
name: 'Text Field Test Object',
|
|
1457
|
+
actions: [
|
|
1458
|
+
{
|
|
1459
|
+
id: '_update',
|
|
1460
|
+
name: 'Update',
|
|
1461
|
+
type: 'update',
|
|
1462
|
+
outputEvent: 'updated',
|
|
1463
|
+
},
|
|
1464
|
+
],
|
|
1465
|
+
properties: [],
|
|
1466
|
+
};
|
|
1467
|
+
server.use(http.get(`/api/data/objects/${textFieldTestObject.id}/effective`, () => HttpResponse.json(textFieldTestObject)));
|
|
1468
|
+
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
1469
|
+
const textField = await screen.findByRole('textbox', { name: 'Text Field' });
|
|
1470
|
+
await user.type(textField, 'Test Input');
|
|
1471
|
+
expect(textField).toHaveValue('Test Input');
|
|
1472
|
+
});
|
|
1229
1473
|
});
|
|
1230
1474
|
});
|