@evoke-platform/ui-components 1.10.0-dev.30 → 1.10.0-dev.32
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.test.js +0 -2
- package/dist/published/components/custom/Form/FormComponents/DocumentComponent/Document.js +2 -1
- package/dist/published/components/custom/Form/tests/Form.test.js +0 -2
- 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/FormV2/FormRendererContainer.js +2 -3
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/Document.js +6 -0
- package/dist/published/components/custom/FormV2/tests/FormRenderer.test.js +58 -37
- package/dist/published/components/custom/FormV2/tests/FormRendererContainer.test.js +323 -5
- package/package.json +9 -7
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ExpandMore, InfoRounded } from '@mui/icons-material';
|
|
2
2
|
import { InputLabel, Autocomplete as MUIAutocomplete } from '@mui/material';
|
|
3
|
+
import { omit } from 'lodash';
|
|
3
4
|
import React from 'react';
|
|
4
5
|
import UIThemeProvider from '../../../theme';
|
|
5
6
|
import FieldError from '../FieldError';
|
|
@@ -37,6 +38,7 @@ const Autocomplete = (props) => {
|
|
|
37
38
|
return props.instructionText;
|
|
38
39
|
}
|
|
39
40
|
};
|
|
41
|
+
const muiAutocompleteProps = omit(props, 'sortBy', 'error', 'errorMessage', 'labelPlacement', 'instructionText');
|
|
40
42
|
if (!!props.label && props.labelPlacement === 'outside-top') {
|
|
41
43
|
return (React.createElement(UIThemeProvider, null,
|
|
42
44
|
React.createElement(InputLabel, { htmlFor: props.id ?? '', sx: { display: 'flex', paddingBottom: '0px', fontSize: '14px' } },
|
|
@@ -50,7 +52,7 @@ const Autocomplete = (props) => {
|
|
|
50
52
|
color: (theme) => theme.palette.text.secondary,
|
|
51
53
|
} })))),
|
|
52
54
|
renderInstructionText(),
|
|
53
|
-
React.createElement(MUIAutocomplete, { ...
|
|
55
|
+
React.createElement(MUIAutocomplete, { ...muiAutocompleteProps, sx: {
|
|
54
56
|
'& fieldset': { borderRadius: '8px', borderColor: props.error ? 'red' : undefined },
|
|
55
57
|
'& .MuiOutlinedInput-notchedOutline': {
|
|
56
58
|
border: props.readOnly ? 'none' : 'auto',
|
|
@@ -67,7 +69,7 @@ const Autocomplete = (props) => {
|
|
|
67
69
|
}
|
|
68
70
|
else {
|
|
69
71
|
return (React.createElement(UIThemeProvider, null,
|
|
70
|
-
React.createElement(MUIAutocomplete, { ...
|
|
72
|
+
React.createElement(MUIAutocomplete, { ...muiAutocompleteProps, sx: {
|
|
71
73
|
'& fieldset': { borderRadius: '8px', borderColor: props.error ? 'red' : undefined },
|
|
72
74
|
'& .MuiOutlinedInput-notchedOutline': {
|
|
73
75
|
border: props.readOnly ? 'none' : 'auto',
|
|
@@ -1,11 +1,120 @@
|
|
|
1
1
|
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
2
3
|
import React from 'react';
|
|
3
4
|
import { it } from 'vitest';
|
|
4
5
|
import TextField from '../TextField';
|
|
5
6
|
import Autocomplete from './Autocomplete';
|
|
6
|
-
const
|
|
7
|
+
const renderInputFactory = (label) => (params) => React.createElement(TextField, { ...params, label: label });
|
|
7
8
|
const options = [];
|
|
8
|
-
it('
|
|
9
|
-
render(React.createElement(Autocomplete, { id: "testinput", labelPlacement: "outside-top", label: "Title", renderInput:
|
|
9
|
+
it('should render with label outside outline', () => {
|
|
10
|
+
render(React.createElement(Autocomplete, { id: "testinput", labelPlacement: "outside-top", label: "Title", renderInput: renderInputFactory(), options: options }));
|
|
10
11
|
screen.getByRole('combobox', { name: 'Title' });
|
|
11
12
|
});
|
|
13
|
+
it('should render label outside outline with asterisk when required', () => {
|
|
14
|
+
render(React.createElement(Autocomplete, { id: "testinput", labelPlacement: "outside-top", label: "Title", renderInput: renderInputFactory(), options: options, required: true }));
|
|
15
|
+
screen.getByRole('combobox', { name: 'Title *' });
|
|
16
|
+
});
|
|
17
|
+
it('should render instruction text when provided when there is an outside-top label', () => {
|
|
18
|
+
render(React.createElement(Autocomplete, { id: "testinput", labelPlacement: "outside-top", label: "Title", instructionText: "This is an instruction", renderInput: renderInputFactory(), options: options }));
|
|
19
|
+
screen.getByText('This is an instruction');
|
|
20
|
+
});
|
|
21
|
+
it('should not render instruction text when there is not an outside-top label', () => {
|
|
22
|
+
render(React.createElement(Autocomplete, { id: "testinput", instructionText: "This is an instruction", renderInput: renderInputFactory(), options: options }));
|
|
23
|
+
const instructionText = screen.queryByText('This is an instruction');
|
|
24
|
+
expect(instructionText).not.toBeInTheDocument();
|
|
25
|
+
});
|
|
26
|
+
it('should render a tooltip if one is provided and there is an outside-top label', async () => {
|
|
27
|
+
const user = userEvent.setup();
|
|
28
|
+
render(React.createElement(Autocomplete, { id: "testinput", labelPlacement: "outside-top", label: "Title", tooltip: "This is a tooltip", renderInput: renderInputFactory(), options: options }));
|
|
29
|
+
expect(screen.queryByText('This is a tooltip')).not.toBeInTheDocument();
|
|
30
|
+
await user.hover(screen.getByLabelText('This is a tooltip'));
|
|
31
|
+
await screen.findByText('This is a tooltip');
|
|
32
|
+
});
|
|
33
|
+
it('should sort options in ascending order if sortBy is ASC', async () => {
|
|
34
|
+
const user = userEvent.setup();
|
|
35
|
+
const unsortedOptions = [
|
|
36
|
+
{ label: 'Banana', value: 1 },
|
|
37
|
+
{ label: 'Apple', value: 2 },
|
|
38
|
+
{ label: 'Cherry', value: 3 },
|
|
39
|
+
];
|
|
40
|
+
render(React.createElement(Autocomplete, { id: "testinput", sortBy: "ASC", renderInput: renderInputFactory('Fruits'), options: unsortedOptions }));
|
|
41
|
+
const comboBox = screen.getByRole('combobox', { name: 'Fruits' });
|
|
42
|
+
await user.click(comboBox);
|
|
43
|
+
const options = screen.getAllByRole('option');
|
|
44
|
+
const labels = options.map((option) => option.textContent);
|
|
45
|
+
expect(labels).toEqual(['Apple', 'Banana', 'Cherry']);
|
|
46
|
+
});
|
|
47
|
+
it('should sort options in descending order if sortBy is DESC', async () => {
|
|
48
|
+
const user = userEvent.setup();
|
|
49
|
+
const unsortedOptions = [
|
|
50
|
+
{ label: 'Banana', value: 1 },
|
|
51
|
+
{ label: 'Apple', value: 2 },
|
|
52
|
+
{ label: 'Cherry', value: 3 },
|
|
53
|
+
];
|
|
54
|
+
render(React.createElement(Autocomplete, { id: "testinput", sortBy: "DESC", renderInput: renderInputFactory('Fruits'), options: unsortedOptions }));
|
|
55
|
+
const comboBox = screen.getByRole('combobox', { name: 'Fruits' });
|
|
56
|
+
await user.click(comboBox);
|
|
57
|
+
const options = screen.getAllByRole('option');
|
|
58
|
+
const labels = options.map((option) => option.textContent);
|
|
59
|
+
expect(labels).toEqual(['Cherry', 'Banana', 'Apple']);
|
|
60
|
+
});
|
|
61
|
+
it('should not sort options if sortBy is NONE', async () => {
|
|
62
|
+
const user = userEvent.setup();
|
|
63
|
+
const unsortedOptions = [
|
|
64
|
+
{ label: 'Banana', value: 1 },
|
|
65
|
+
{ label: 'Apple', value: 2 },
|
|
66
|
+
{ label: 'Cherry', value: 3 },
|
|
67
|
+
];
|
|
68
|
+
render(React.createElement(Autocomplete, { id: "testinput", sortBy: "NONE", renderInput: renderInputFactory('Fruits'), options: unsortedOptions }));
|
|
69
|
+
const comboBox = screen.getByRole('combobox', { name: 'Fruits' });
|
|
70
|
+
await user.click(comboBox);
|
|
71
|
+
const options = screen.getAllByRole('option');
|
|
72
|
+
const labels = options.map((option) => option.textContent);
|
|
73
|
+
expect(labels).toEqual(['Banana', 'Apple', 'Cherry']);
|
|
74
|
+
});
|
|
75
|
+
it('should sort options in ascending order by default', async () => {
|
|
76
|
+
const user = userEvent.setup();
|
|
77
|
+
const unsortedOptions = [
|
|
78
|
+
{ label: 'Banana', value: 1 },
|
|
79
|
+
{ label: 'Apple', value: 2 },
|
|
80
|
+
{ label: 'Cherry', value: 3 },
|
|
81
|
+
];
|
|
82
|
+
render(React.createElement(Autocomplete, { id: "testinput", renderInput: renderInputFactory('Fruits'), options: unsortedOptions }));
|
|
83
|
+
const comboBox = screen.getByRole('combobox', { name: 'Fruits' });
|
|
84
|
+
await user.click(comboBox);
|
|
85
|
+
const options = screen.getAllByRole('option');
|
|
86
|
+
const labels = options.map((option) => option.textContent);
|
|
87
|
+
expect(labels).toEqual(['Apple', 'Banana', 'Cherry']);
|
|
88
|
+
});
|
|
89
|
+
it('should sort string options', async () => {
|
|
90
|
+
const user = userEvent.setup();
|
|
91
|
+
const unsortedOptions = ['Banana', 'Apple', 'Cherry'];
|
|
92
|
+
render(React.createElement(Autocomplete, { id: "testinput", sortBy: "ASC", renderInput: renderInputFactory('Fruit Options'), options: unsortedOptions }));
|
|
93
|
+
const comboBox = screen.getByRole('combobox', { name: 'Fruit Options' });
|
|
94
|
+
await user.click(comboBox);
|
|
95
|
+
const options = screen.getAllByRole('option');
|
|
96
|
+
const labels = options.map((option) => option.textContent);
|
|
97
|
+
expect(labels).toEqual(['Apple', 'Banana', 'Cherry']);
|
|
98
|
+
});
|
|
99
|
+
it('should render an error when error prop is true', () => {
|
|
100
|
+
render(React.createElement(Autocomplete, { id: "testinput", label: "Title", error: true, errorMessage: "This is an error", labelPlacement: "outside-top", renderInput: renderInputFactory(), options: options }));
|
|
101
|
+
screen.getByText('This is an error');
|
|
102
|
+
});
|
|
103
|
+
it('should show popupIcon when not disabled', () => {
|
|
104
|
+
render(React.createElement(Autocomplete, { id: "testinput", label: "Title", disabled: false, renderInput: renderInputFactory(), options: options }));
|
|
105
|
+
screen.getByTestId('ExpandMoreIcon');
|
|
106
|
+
});
|
|
107
|
+
it('should hide popupIcon when disabled', () => {
|
|
108
|
+
render(React.createElement(Autocomplete, { id: "testinput", label: "Title", disabled: true, renderInput: renderInputFactory(), options: options }));
|
|
109
|
+
const popupIcon = screen.queryByTestId('ExpandMoreIcon');
|
|
110
|
+
expect(popupIcon).not.toBeInTheDocument();
|
|
111
|
+
});
|
|
112
|
+
it('should hide popupIcon when readOnly', () => {
|
|
113
|
+
render(React.createElement(Autocomplete, { id: "testinput", label: "Title", readOnly: true, renderInput: renderInputFactory(), options: options }));
|
|
114
|
+
const popupIcon = screen.queryByTestId('ExpandMoreIcon');
|
|
115
|
+
expect(popupIcon).not.toBeInTheDocument();
|
|
116
|
+
});
|
|
117
|
+
it('should show custom popupIcon when provided', () => {
|
|
118
|
+
render(React.createElement(Autocomplete, { id: "testinput", label: "Title", popupIcon: React.createElement("span", { "data-testid": "custom-icon" }, "^"), renderInput: renderInputFactory(), options: options }));
|
|
119
|
+
screen.getByTestId('custom-icon');
|
|
120
|
+
});
|
|
@@ -36,7 +36,7 @@ const TextField = (props) => {
|
|
|
36
36
|
...props.sx,
|
|
37
37
|
} }),
|
|
38
38
|
error && React.createElement(FieldError, { required: required, label: errorMessage }))) : (React.createElement(React.Fragment, null,
|
|
39
|
-
React.createElement(MUITextField, { inputProps: { readOnly: readOnly, 'aria-readonly': !!readOnly, 'data-testid': 'label-inside' }, ...
|
|
39
|
+
React.createElement(MUITextField, { inputProps: { readOnly: readOnly, 'aria-readonly': !!readOnly, 'data-testid': 'label-inside' }, ...muiProps, sx: readOnly
|
|
40
40
|
? { ...readOnlyStyles, ...props.sx }
|
|
41
41
|
: { '& fieldset': { borderRadius: '8px' }, ...props.sx } }),
|
|
42
42
|
error && React.createElement(FieldError, { required: required, label: errorMessage })))));
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import * as matchers from '@testing-library/jest-dom/matchers';
|
|
2
1
|
import { render, screen } from '@testing-library/react';
|
|
3
2
|
import React from 'react';
|
|
4
3
|
import { expect, it } from 'vitest';
|
|
5
4
|
import TextField from './index';
|
|
6
|
-
expect.extend(matchers);
|
|
7
5
|
it('render TextField and check for data-testid === label-outside when labelPlacement === outside-top && variant === outlined', () => {
|
|
8
6
|
render(React.createElement(TextField, { id: "testinput", labelPlacement: "outside-top", variant: "outlined", label: "Title" }));
|
|
9
7
|
const textField = screen.getByRole('textbox', { name: 'Title' });
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import * as matchers from '@testing-library/jest-dom/matchers';
|
|
2
1
|
import { render, screen } from '@testing-library/react';
|
|
3
2
|
import userEvent from '@testing-library/user-event';
|
|
4
3
|
import React from 'react';
|
|
5
4
|
import { expect, it } from 'vitest';
|
|
6
5
|
import CriteriaBuilder from './CriteriaBuilder';
|
|
7
|
-
expect.extend(matchers);
|
|
8
6
|
const mockProperties = [
|
|
9
7
|
{
|
|
10
8
|
id: 'name',
|
|
@@ -42,7 +42,8 @@ export const Document = (props) => {
|
|
|
42
42
|
if (canUpdateProperty) {
|
|
43
43
|
apiServices
|
|
44
44
|
.get(getPrefixedUrl(`/objects/${objectId}/instances/${instance.id}/documents/checkAccess?action=update`))
|
|
45
|
-
.then((accessCheck) => setHasUpdatePermission(accessCheck.result))
|
|
45
|
+
.then((accessCheck) => setHasUpdatePermission(accessCheck.result))
|
|
46
|
+
.catch(() => setHasUpdatePermission(false));
|
|
46
47
|
}
|
|
47
48
|
};
|
|
48
49
|
const handleUpload = async (files) => {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ApiServices } from '@evoke-platform/context';
|
|
2
|
-
import * as matchers from '@testing-library/jest-dom/matchers';
|
|
3
2
|
import { render, screen, waitFor, within } from '@testing-library/react';
|
|
4
3
|
import userEvent from '@testing-library/user-event';
|
|
5
4
|
import axios from 'axios';
|
|
@@ -10,7 +9,6 @@ import React from 'react';
|
|
|
10
9
|
import { expect, it } from 'vitest';
|
|
11
10
|
import Form from '../Common/Form';
|
|
12
11
|
import { accessibility508Object, licenseObject, npLicense, npSpecialtyType1, npSpecialtyType2, rnLicense, rnSpecialtyType1, rnSpecialtyType2, specialtyObject, specialtyTypeObject, users, } from './test-data';
|
|
13
|
-
expect.extend(matchers);
|
|
14
12
|
const removePoppers = () => {
|
|
15
13
|
const portalSelectors = ['.MuiAutocomplete-popper'];
|
|
16
14
|
portalSelectors.forEach((selector) => {
|
package/dist/published/components/custom/FormField/InputFieldComponent/InputFieldComponent.test.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import * as matchers from '@testing-library/jest-dom/matchers';
|
|
2
1
|
import { render, screen } from '@testing-library/react';
|
|
3
2
|
import { userEvent } from '@testing-library/user-event';
|
|
4
3
|
import React from 'react';
|
|
5
4
|
import { describe, expect, it, vi } from 'vitest';
|
|
6
5
|
import InputField from './InputFieldComponent';
|
|
7
|
-
expect.extend(matchers);
|
|
8
6
|
describe('Free-text input', () => {
|
|
9
7
|
// Right now an object property is required for this to function, but eventually this should go
|
|
10
8
|
// away.
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import * as matchers from '@testing-library/jest-dom/matchers';
|
|
2
1
|
import { render, screen } from '@testing-library/react';
|
|
3
2
|
import { userEvent } from '@testing-library/user-event';
|
|
4
3
|
import React from 'react';
|
|
5
4
|
import { describe, expect, it, vi } from 'vitest';
|
|
6
5
|
import Select from './Select';
|
|
7
|
-
expect.extend(matchers);
|
|
8
6
|
describe('Single select', () => {
|
|
9
7
|
// Right now an object property is required for this to function, but eventually this should go
|
|
10
8
|
// away.
|
|
@@ -70,9 +70,8 @@ function FormRendererContainer(props) {
|
|
|
70
70
|
}
|
|
71
71
|
else {
|
|
72
72
|
if (instanceId) {
|
|
73
|
-
objectStore.getInstance(instanceId)
|
|
74
|
-
|
|
75
|
-
});
|
|
73
|
+
const instance = await objectStore.getInstance(instanceId);
|
|
74
|
+
setInstance(instance);
|
|
76
75
|
}
|
|
77
76
|
const object = await apiServices.get(getPrefixedUrl(`/objects/${form?.objectId || objectId}${instanceId ? `/instances/${instanceId}/object` : '/effective'}`), { params: { sanitizedVersion: true } });
|
|
78
77
|
setSanitizedObject(object);
|
package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/Document.js
CHANGED
|
@@ -42,6 +42,12 @@ export const Document = (props) => {
|
|
|
42
42
|
[`${id}UpdatePermission`]: accessCheck.result,
|
|
43
43
|
});
|
|
44
44
|
setHasUpdatePermission(accessCheck.result);
|
|
45
|
+
})
|
|
46
|
+
.catch(() => {
|
|
47
|
+
setFetchedOptions({
|
|
48
|
+
[`${id}UpdatePermission`]: false,
|
|
49
|
+
});
|
|
50
|
+
setHasUpdatePermission(false);
|
|
45
51
|
});
|
|
46
52
|
}
|
|
47
53
|
}, [canUpdateProperty, fetchedOptions, instance, object]);
|
|
@@ -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() { }
|
|
@@ -997,25 +995,25 @@ describe('FormRenderer', () => {
|
|
|
997
995
|
});
|
|
998
996
|
describe('when mode is default (allows both new and existing)', () => {
|
|
999
997
|
const form = {
|
|
1000
|
-
id: '
|
|
998
|
+
id: 'dropdownRelatedObjectTestForm',
|
|
1001
999
|
name: 'Related Object Test Form',
|
|
1002
1000
|
entries: [
|
|
1003
1001
|
{
|
|
1004
1002
|
type: 'input',
|
|
1005
|
-
parameterId: '
|
|
1003
|
+
parameterId: 'licenseType',
|
|
1006
1004
|
display: {
|
|
1007
|
-
label: '
|
|
1005
|
+
label: 'License Type',
|
|
1008
1006
|
relatedObjectDisplay: 'dropdown',
|
|
1009
1007
|
createActionId: '_create',
|
|
1010
1008
|
},
|
|
1011
1009
|
},
|
|
1012
1010
|
],
|
|
1013
1011
|
actionId: '_update',
|
|
1014
|
-
objectId: '
|
|
1012
|
+
objectId: 'dropdownRelatedTestObject',
|
|
1015
1013
|
};
|
|
1016
1014
|
beforeEach(() => {
|
|
1017
|
-
const
|
|
1018
|
-
id: '
|
|
1015
|
+
const dropdownRelatedTestObject = {
|
|
1016
|
+
id: 'dropdownRelatedTestObject',
|
|
1019
1017
|
name: 'Related Object Test Form',
|
|
1020
1018
|
actions: [
|
|
1021
1019
|
{
|
|
@@ -1024,10 +1022,10 @@ describe('FormRenderer', () => {
|
|
|
1024
1022
|
type: 'update',
|
|
1025
1023
|
parameters: [
|
|
1026
1024
|
{
|
|
1027
|
-
id: '
|
|
1025
|
+
id: 'licenseType',
|
|
1028
1026
|
name: 'Related Object',
|
|
1029
1027
|
type: 'object',
|
|
1030
|
-
objectId: '
|
|
1028
|
+
objectId: 'licenseType',
|
|
1031
1029
|
},
|
|
1032
1030
|
],
|
|
1033
1031
|
outputEvent: 'updated',
|
|
@@ -1035,45 +1033,61 @@ describe('FormRenderer', () => {
|
|
|
1035
1033
|
],
|
|
1036
1034
|
properties: [
|
|
1037
1035
|
{
|
|
1038
|
-
id: '
|
|
1036
|
+
id: 'licenseType',
|
|
1039
1037
|
name: 'Related Object',
|
|
1040
1038
|
type: 'object',
|
|
1039
|
+
objectId: 'licenseType',
|
|
1041
1040
|
},
|
|
1042
1041
|
],
|
|
1043
1042
|
};
|
|
1044
|
-
setupTestMocks(
|
|
1045
|
-
const
|
|
1046
|
-
id: '
|
|
1047
|
-
name: '
|
|
1043
|
+
setupTestMocks(dropdownRelatedTestObject, form);
|
|
1044
|
+
const licenseTypeObject = {
|
|
1045
|
+
id: 'licenseType',
|
|
1046
|
+
name: 'License Type',
|
|
1048
1047
|
actions: [
|
|
1049
1048
|
{
|
|
1050
1049
|
id: '_create',
|
|
1051
1050
|
name: 'Create',
|
|
1052
1051
|
type: 'create',
|
|
1053
|
-
parameters: [
|
|
1052
|
+
parameters: [
|
|
1053
|
+
{
|
|
1054
|
+
type: 'string',
|
|
1055
|
+
id: 'name',
|
|
1056
|
+
name: 'License Type Name',
|
|
1057
|
+
},
|
|
1058
|
+
],
|
|
1054
1059
|
outputEvent: 'created',
|
|
1055
|
-
defaultFormId: '
|
|
1060
|
+
defaultFormId: 'licenseTypeForm',
|
|
1061
|
+
},
|
|
1062
|
+
],
|
|
1063
|
+
properties: [
|
|
1064
|
+
{
|
|
1065
|
+
type: 'string',
|
|
1066
|
+
id: 'name',
|
|
1067
|
+
name: 'License Type Name',
|
|
1056
1068
|
},
|
|
1057
1069
|
],
|
|
1058
|
-
properties: [],
|
|
1059
1070
|
};
|
|
1060
|
-
const
|
|
1061
|
-
id: '
|
|
1062
|
-
name: '
|
|
1071
|
+
const licenseTypeForm = {
|
|
1072
|
+
id: 'licenseTypeForm',
|
|
1073
|
+
name: 'License Type Form',
|
|
1063
1074
|
entries: [
|
|
1064
1075
|
{
|
|
1065
|
-
type: '
|
|
1066
|
-
|
|
1076
|
+
type: 'input',
|
|
1077
|
+
parameterId: 'name',
|
|
1078
|
+
display: {
|
|
1079
|
+
label: 'License Type Name',
|
|
1080
|
+
},
|
|
1067
1081
|
},
|
|
1068
1082
|
],
|
|
1069
1083
|
actionId: '_create',
|
|
1070
|
-
objectId: '
|
|
1084
|
+
objectId: 'licenseType',
|
|
1071
1085
|
};
|
|
1072
|
-
setupTestMocks(
|
|
1086
|
+
setupTestMocks(licenseTypeObject, licenseTypeForm, [
|
|
1073
1087
|
{
|
|
1074
|
-
id: '
|
|
1075
|
-
name: '
|
|
1076
|
-
objectId: '
|
|
1088
|
+
id: 'licenseType1',
|
|
1089
|
+
name: 'License Type #1',
|
|
1090
|
+
objectId: 'licenseType',
|
|
1077
1091
|
},
|
|
1078
1092
|
]);
|
|
1079
1093
|
});
|
|
@@ -1081,27 +1095,34 @@ describe('FormRenderer', () => {
|
|
|
1081
1095
|
const user = userEvent.setup();
|
|
1082
1096
|
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
1083
1097
|
// Navigate to and open dropdown
|
|
1084
|
-
const dropdown = await screen.findByRole('combobox', { name: '
|
|
1098
|
+
const dropdown = await screen.findByRole('combobox', { name: 'License Type' });
|
|
1085
1099
|
await user.click(dropdown);
|
|
1086
|
-
await
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
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' }));
|
|
1090
1111
|
await screen.findByRole('dialog');
|
|
1091
|
-
await screen.
|
|
1112
|
+
await screen.findByRole('textbox', { name: 'License Type Name' });
|
|
1092
1113
|
});
|
|
1093
1114
|
it('allows related object instance selection', async () => {
|
|
1094
1115
|
const user = userEvent.setup();
|
|
1095
1116
|
render(React.createElement(FormRenderer, { form: form, onChange: () => { } }));
|
|
1096
1117
|
// Navigate to and open dropdown
|
|
1097
|
-
const dropdown = await screen.findByRole('combobox', { name: '
|
|
1118
|
+
const dropdown = await screen.findByRole('combobox', { name: 'License Type' });
|
|
1098
1119
|
await user.click(dropdown);
|
|
1099
|
-
const option = await screen.findByRole('option', { name: '
|
|
1120
|
+
const option = await screen.findByRole('option', { name: 'License Type #1' });
|
|
1100
1121
|
await user.click(option);
|
|
1101
1122
|
// Verify option has been removed from the document
|
|
1102
1123
|
expect(option).not.toBeInTheDocument();
|
|
1103
1124
|
// Verify selection
|
|
1104
|
-
screen.getByText('
|
|
1125
|
+
screen.getByText('License Type #1');
|
|
1105
1126
|
});
|
|
1106
1127
|
});
|
|
1107
1128
|
});
|
|
@@ -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 { isEqual } from 'lodash';
|
|
@@ -9,7 +8,6 @@ import { MemoryRouter } from 'react-router-dom';
|
|
|
9
8
|
import { expect, it } from 'vitest';
|
|
10
9
|
import FormRendererContainer from '../FormRendererContainer';
|
|
11
10
|
import { createSpecialtyForm, licenseForm, licenseObject, npLicense, npSpecialtyType1, npSpecialtyType2, rnLicense, rnSpecialtyType1, rnSpecialtyType2, specialtyObject, specialtyTypeObject, } from './test-data';
|
|
12
|
-
expect.extend(matchers);
|
|
13
11
|
// Mock ResizeObserver
|
|
14
12
|
global.ResizeObserver = class ResizeObserver {
|
|
15
13
|
observe() { }
|
|
@@ -78,10 +76,11 @@ describe('FormRendererContainer', () => {
|
|
|
78
76
|
return HttpResponse.json(createSpecialtyForm);
|
|
79
77
|
}));
|
|
80
78
|
render(React.createElement(FormRendererContainer, { objectId: 'specialty', formId: 'specialtyForm', dataType: 'objectInstances', actionId: '_create', associatedObject: { propertyId: 'license', instanceId: 'rnLicense' } }));
|
|
79
|
+
// Give the form renderer some time to load
|
|
80
|
+
const specialtyType = await screen.findByRole('combobox', { name: 'Specialty Type' }, { timeout: 3000 });
|
|
81
81
|
// Validate that the license field is hidden
|
|
82
82
|
await waitFor(() => expect(screen.queryByRole('combobox', { name: 'License' })).not.toBeInTheDocument());
|
|
83
83
|
// Validate that specialty type dropdown is only rendering specialty types that are associated with the selected license.
|
|
84
|
-
const specialtyType = await screen.findByRole('combobox', { name: 'Specialty Type' });
|
|
85
84
|
await user.click(specialtyType);
|
|
86
85
|
const openAutocomplete = await screen.findByRole('listbox');
|
|
87
86
|
await within(openAutocomplete).findByRole('option', { name: 'RN Specialty Type #1' });
|
|
@@ -331,7 +330,7 @@ describe('FormRendererContainer', () => {
|
|
|
331
330
|
await waitFor(() => {
|
|
332
331
|
expect(autosaveActionSpy).toHaveBeenCalled();
|
|
333
332
|
});
|
|
334
|
-
const lastCall = autosaveActionSpy.mock.lastCall[0];
|
|
333
|
+
const lastCall = autosaveActionSpy.mock.lastCall?.[0];
|
|
335
334
|
expect(lastCall).toEqual(expect.objectContaining({
|
|
336
335
|
input: expect.objectContaining({
|
|
337
336
|
address: expect.objectContaining({
|
|
@@ -456,7 +455,7 @@ describe('FormRendererContainer', () => {
|
|
|
456
455
|
// The autosave is triggered twice when selecting the autocomplete option,
|
|
457
456
|
// once by the selection and once by the onBlur event. We want to verify the last call
|
|
458
457
|
// has the correct data.
|
|
459
|
-
const lastCall = autosaveActionSpy.mock.lastCall[0];
|
|
458
|
+
const lastCall = autosaveActionSpy.mock.lastCall?.[0];
|
|
460
459
|
expect(lastCall).toEqual(expect.objectContaining({
|
|
461
460
|
input: expect.objectContaining({
|
|
462
461
|
address: expect.objectContaining({
|
|
@@ -632,6 +631,325 @@ describe('FormRendererContainer', () => {
|
|
|
632
631
|
await user.click(discardButton);
|
|
633
632
|
await waitFor(() => expect(firstNameInput).toHaveValue(''));
|
|
634
633
|
});
|
|
634
|
+
it('should show a not found error if the instance cannot be found', async () => {
|
|
635
|
+
const form = {
|
|
636
|
+
id: 'simpleForm',
|
|
637
|
+
name: 'Simple Form',
|
|
638
|
+
entries: [
|
|
639
|
+
{
|
|
640
|
+
type: 'inputField',
|
|
641
|
+
input: {
|
|
642
|
+
id: 'name',
|
|
643
|
+
type: 'string',
|
|
644
|
+
},
|
|
645
|
+
display: {
|
|
646
|
+
label: 'Name',
|
|
647
|
+
},
|
|
648
|
+
},
|
|
649
|
+
],
|
|
650
|
+
actionId: '_update',
|
|
651
|
+
objectId: 'simpleObject',
|
|
652
|
+
};
|
|
653
|
+
const simpleObject = {
|
|
654
|
+
id: 'simpleObject',
|
|
655
|
+
name: 'Simple Object',
|
|
656
|
+
actions: [
|
|
657
|
+
{
|
|
658
|
+
id: '_update',
|
|
659
|
+
name: 'Update',
|
|
660
|
+
type: 'update',
|
|
661
|
+
parameters: [
|
|
662
|
+
{
|
|
663
|
+
id: 'name',
|
|
664
|
+
name: 'Name',
|
|
665
|
+
type: 'string',
|
|
666
|
+
},
|
|
667
|
+
],
|
|
668
|
+
outputEvent: 'updated',
|
|
669
|
+
},
|
|
670
|
+
],
|
|
671
|
+
properties: [
|
|
672
|
+
{
|
|
673
|
+
id: 'name',
|
|
674
|
+
name: 'Name',
|
|
675
|
+
type: 'string',
|
|
676
|
+
},
|
|
677
|
+
],
|
|
678
|
+
};
|
|
679
|
+
server.use(http.get(`/api/data/objects/simpleObject/effective`, () => HttpResponse.json(simpleObject)), http.get(`/api/data/forms/simpleForm`, () => HttpResponse.json(form)), http.get('/api/data/objects/simpleObject/instances/123', () => HttpResponse.json({
|
|
680
|
+
message: 'Not Found',
|
|
681
|
+
}, { status: 404 })), http.get('/api/data/objects/simpleObject/instances/123/object', () => HttpResponse.json({
|
|
682
|
+
message: 'Not Found',
|
|
683
|
+
}, { status: 404 })));
|
|
684
|
+
render(React.createElement(FormRendererContainer, { formId: form.id, actionId: "_update", objectId: "simpleObject", instanceId: '123', dataType: "objectInstances" }));
|
|
685
|
+
await screen.findByText('The requested content could not be found.');
|
|
686
|
+
});
|
|
687
|
+
it('should show an unauthorized error if the instance access is unauthorized', async () => {
|
|
688
|
+
const form = {
|
|
689
|
+
id: 'simpleForm',
|
|
690
|
+
name: 'Simple Form',
|
|
691
|
+
entries: [
|
|
692
|
+
{
|
|
693
|
+
type: 'inputField',
|
|
694
|
+
input: {
|
|
695
|
+
id: 'name',
|
|
696
|
+
type: 'string',
|
|
697
|
+
},
|
|
698
|
+
display: {
|
|
699
|
+
label: 'Name',
|
|
700
|
+
},
|
|
701
|
+
},
|
|
702
|
+
],
|
|
703
|
+
actionId: '_create',
|
|
704
|
+
objectId: 'simpleObject',
|
|
705
|
+
};
|
|
706
|
+
const simpleObject = {
|
|
707
|
+
id: 'simpleObject',
|
|
708
|
+
name: 'Simple Object',
|
|
709
|
+
actions: [
|
|
710
|
+
{
|
|
711
|
+
id: '_create',
|
|
712
|
+
name: 'Create',
|
|
713
|
+
type: 'create',
|
|
714
|
+
parameters: [
|
|
715
|
+
{
|
|
716
|
+
id: 'name',
|
|
717
|
+
name: 'Name',
|
|
718
|
+
type: 'string',
|
|
719
|
+
},
|
|
720
|
+
],
|
|
721
|
+
outputEvent: 'created',
|
|
722
|
+
},
|
|
723
|
+
],
|
|
724
|
+
properties: [
|
|
725
|
+
{
|
|
726
|
+
id: 'name',
|
|
727
|
+
name: 'Name',
|
|
728
|
+
type: 'string',
|
|
729
|
+
},
|
|
730
|
+
],
|
|
731
|
+
};
|
|
732
|
+
server.use(http.get(`/api/data/objects/simpleObject/effective`, () => HttpResponse.json(simpleObject)), http.get(`/api/data/forms/simpleForm`, () => HttpResponse.json(form)), http.get('/api/data/objects/simpleObject/instances/123', () => HttpResponse.json({
|
|
733
|
+
message: 'Unauthorized',
|
|
734
|
+
}, { status: 403 })), http.get('/api/data/objects/simpleObject/instances/123/object', () => HttpResponse.json({
|
|
735
|
+
message: 'Unauthorized',
|
|
736
|
+
}, { status: 403 })));
|
|
737
|
+
render(React.createElement(FormRendererContainer, { formId: form.id, actionId: "_create", objectId: "simpleObject", instanceId: '123', dataType: "objectInstances" }));
|
|
738
|
+
await screen.findByText('You do not have permission to view this content.');
|
|
739
|
+
});
|
|
740
|
+
it('should show a misconfiguration error when action with actionId does not exist', async () => {
|
|
741
|
+
const simpleObject = {
|
|
742
|
+
id: 'simpleObject',
|
|
743
|
+
name: 'Simple Object',
|
|
744
|
+
actions: [],
|
|
745
|
+
properties: [],
|
|
746
|
+
};
|
|
747
|
+
server.use(http.get(`/api/data/objects/simpleObject/effective`, () => HttpResponse.json(simpleObject)));
|
|
748
|
+
render(React.createElement(FormRendererContainer, { objectId: "simpleObject", actionId: "_create", dataType: "objectInstances" }));
|
|
749
|
+
await screen.findByText('It looks like something is missing.');
|
|
750
|
+
});
|
|
751
|
+
it('should show a not found error when object cannot be found', async () => {
|
|
752
|
+
server.use(http.get(`/api/data/objects/simpleObject/effective`, () => HttpResponse.json({ error: 'Not Found' }, { status: 404 })));
|
|
753
|
+
render(React.createElement(FormRendererContainer, { objectId: "simpleObject", dataType: "objectInstances" }));
|
|
754
|
+
await screen.findByText('The requested content could not be found.');
|
|
755
|
+
});
|
|
756
|
+
describe('when trying to show a specific form', () => {
|
|
757
|
+
it("should not show the action's default form", async () => {
|
|
758
|
+
const form = {
|
|
759
|
+
id: 'simpleForm',
|
|
760
|
+
name: 'Simple Form',
|
|
761
|
+
entries: [],
|
|
762
|
+
actionId: '_create',
|
|
763
|
+
objectId: 'simpleObject',
|
|
764
|
+
};
|
|
765
|
+
const simpleObject = {
|
|
766
|
+
id: 'simpleObject',
|
|
767
|
+
name: 'Simple Object',
|
|
768
|
+
actions: [
|
|
769
|
+
{
|
|
770
|
+
id: '_create',
|
|
771
|
+
name: 'Create',
|
|
772
|
+
type: 'create',
|
|
773
|
+
parameters: [],
|
|
774
|
+
outputEvent: 'created',
|
|
775
|
+
defaultFormId: 'notSimpleForm',
|
|
776
|
+
},
|
|
777
|
+
],
|
|
778
|
+
properties: [],
|
|
779
|
+
};
|
|
780
|
+
server.use(http.get(`/api/data/objects/simpleObject/effective`, () => HttpResponse.json(simpleObject)), http.get(`/api/data/forms/simpleForm`, () => HttpResponse.json(form)));
|
|
781
|
+
render(React.createElement(FormRendererContainer, { formId: form.id, objectId: "simpleObject", dataType: "objectInstances" }));
|
|
782
|
+
await screen.findByText('Simple Form');
|
|
783
|
+
});
|
|
784
|
+
it('should show a not found error when the form cannot be found', async () => {
|
|
785
|
+
const simpleObject = {
|
|
786
|
+
id: 'simpleObject',
|
|
787
|
+
name: 'Simple Object',
|
|
788
|
+
actions: [
|
|
789
|
+
{
|
|
790
|
+
id: '_create',
|
|
791
|
+
name: 'Create',
|
|
792
|
+
type: 'create',
|
|
793
|
+
parameters: [],
|
|
794
|
+
outputEvent: 'created',
|
|
795
|
+
},
|
|
796
|
+
],
|
|
797
|
+
properties: [],
|
|
798
|
+
};
|
|
799
|
+
server.use(http.get(`/api/data/objects/simpleObject/effective`, () => HttpResponse.json(simpleObject)), http.get(`/api/data/forms/notAForm`, () => HttpResponse.json({ error: 'Not Found' }, { status: 404 })));
|
|
800
|
+
render(React.createElement(FormRendererContainer, { formId: 'notAForm', objectId: "simpleObject", dataType: "objectInstances" }));
|
|
801
|
+
await screen.findByText('The requested content could not be found.');
|
|
802
|
+
});
|
|
803
|
+
it("should show a misconfiguration error when the form's action does not exist", async () => {
|
|
804
|
+
const form = {
|
|
805
|
+
id: 'simpleForm',
|
|
806
|
+
name: 'Simple Form',
|
|
807
|
+
entries: [],
|
|
808
|
+
actionId: '_create',
|
|
809
|
+
objectId: 'simpleObject',
|
|
810
|
+
};
|
|
811
|
+
const simpleObject = {
|
|
812
|
+
id: 'simpleObject',
|
|
813
|
+
name: 'Simple Object',
|
|
814
|
+
actions: [
|
|
815
|
+
{
|
|
816
|
+
id: 'notTheRightAction',
|
|
817
|
+
name: 'Create',
|
|
818
|
+
type: 'create',
|
|
819
|
+
parameters: [],
|
|
820
|
+
outputEvent: 'created',
|
|
821
|
+
},
|
|
822
|
+
],
|
|
823
|
+
properties: [],
|
|
824
|
+
};
|
|
825
|
+
server.use(http.get(`/api/data/objects/simpleObject/effective`, () => HttpResponse.json(simpleObject)), http.get(`/api/data/forms/simpleForm`, () => HttpResponse.json(form)));
|
|
826
|
+
render(React.createElement(FormRendererContainer, { formId: form.id, objectId: "simpleObject", dataType: "objectInstances" }));
|
|
827
|
+
await screen.findByText('It looks like something is missing.');
|
|
828
|
+
});
|
|
829
|
+
it("should show a misconfiguration error when actionId doesn't match form's action id", async () => {
|
|
830
|
+
const form = {
|
|
831
|
+
id: 'simpleForm',
|
|
832
|
+
name: 'Simple Form',
|
|
833
|
+
entries: [],
|
|
834
|
+
actionId: '_notCreate',
|
|
835
|
+
objectId: 'simpleObject',
|
|
836
|
+
};
|
|
837
|
+
const simpleObject = {
|
|
838
|
+
id: 'simpleObject',
|
|
839
|
+
name: 'Simple Object',
|
|
840
|
+
actions: [
|
|
841
|
+
{
|
|
842
|
+
id: '_create',
|
|
843
|
+
name: 'Create',
|
|
844
|
+
type: 'create',
|
|
845
|
+
parameters: [],
|
|
846
|
+
outputEvent: 'created',
|
|
847
|
+
},
|
|
848
|
+
],
|
|
849
|
+
properties: [],
|
|
850
|
+
};
|
|
851
|
+
server.use(http.get(`/api/data/objects/simpleObject/effective`, () => HttpResponse.json(simpleObject)), http.get(`/api/data/forms/simpleForm`, () => HttpResponse.json(form)));
|
|
852
|
+
render(React.createElement(FormRendererContainer, { formId: form.id, objectId: "simpleObject", actionId: "_create", dataType: "objectInstances" }));
|
|
853
|
+
await screen.findByText('It looks like something is missing.');
|
|
854
|
+
});
|
|
855
|
+
});
|
|
856
|
+
describe('when trying to show a default form', () => {
|
|
857
|
+
// object id and action id are provided, but form id is not => use default form
|
|
858
|
+
it('should use the default form when provided with an object and action with a default form id', async () => {
|
|
859
|
+
const form = {
|
|
860
|
+
id: 'simpleForm',
|
|
861
|
+
name: 'Simple Form',
|
|
862
|
+
entries: [],
|
|
863
|
+
actionId: '_create',
|
|
864
|
+
objectId: 'simpleObject',
|
|
865
|
+
};
|
|
866
|
+
const simpleObject = {
|
|
867
|
+
id: 'simpleObject',
|
|
868
|
+
name: 'Simple Object',
|
|
869
|
+
actions: [
|
|
870
|
+
{
|
|
871
|
+
id: '_create',
|
|
872
|
+
name: 'Create',
|
|
873
|
+
type: 'create',
|
|
874
|
+
parameters: [],
|
|
875
|
+
outputEvent: 'created',
|
|
876
|
+
defaultFormId: 'simpleForm',
|
|
877
|
+
},
|
|
878
|
+
],
|
|
879
|
+
properties: [],
|
|
880
|
+
};
|
|
881
|
+
server.use(http.get(`/api/data/objects/simpleObject/effective`, () => HttpResponse.json(simpleObject)), http.get(`/api/data/forms/simpleForm`, () => HttpResponse.json(form)));
|
|
882
|
+
render(React.createElement(FormRendererContainer, { objectId: "simpleObject", actionId: "_create", dataType: "objectInstances" }));
|
|
883
|
+
await screen.findByText('Simple Form');
|
|
884
|
+
});
|
|
885
|
+
// object id and action id are provided, and defaultFormId is defined but the form doesn't exist
|
|
886
|
+
it('should show a not found error when the default form cannot be found', async () => {
|
|
887
|
+
const simpleObject = {
|
|
888
|
+
id: 'simpleObject',
|
|
889
|
+
name: 'Simple Object',
|
|
890
|
+
actions: [
|
|
891
|
+
{
|
|
892
|
+
id: '_create',
|
|
893
|
+
name: 'Create',
|
|
894
|
+
type: 'create',
|
|
895
|
+
parameters: [],
|
|
896
|
+
outputEvent: 'created',
|
|
897
|
+
defaultFormId: 'notAForm',
|
|
898
|
+
},
|
|
899
|
+
],
|
|
900
|
+
properties: [],
|
|
901
|
+
};
|
|
902
|
+
server.use(http.get(`/api/data/objects/simpleObject/effective`, () => HttpResponse.json(simpleObject)), http.get(`/api/data/forms/notAForm`, () => HttpResponse.json({ error: 'Not Found' }, { status: 404 })));
|
|
903
|
+
render(React.createElement(FormRendererContainer, { objectId: "simpleObject", actionId: "_create", dataType: "objectInstances" }));
|
|
904
|
+
await screen.findByText('The requested content could not be found.');
|
|
905
|
+
});
|
|
906
|
+
it('should show a misconfiguration error when the default form is not defined', async () => {
|
|
907
|
+
const simpleObject = {
|
|
908
|
+
id: 'simpleObject',
|
|
909
|
+
name: 'Simple Object',
|
|
910
|
+
actions: [
|
|
911
|
+
{
|
|
912
|
+
id: '_create',
|
|
913
|
+
name: 'Create',
|
|
914
|
+
type: 'create',
|
|
915
|
+
parameters: [],
|
|
916
|
+
outputEvent: 'created',
|
|
917
|
+
},
|
|
918
|
+
],
|
|
919
|
+
properties: [],
|
|
920
|
+
};
|
|
921
|
+
server.use(http.get(`/api/data/objects/simpleObject/effective`, () => HttpResponse.json(simpleObject)));
|
|
922
|
+
render(React.createElement(FormRendererContainer, { objectId: "simpleObject", actionId: "_create", dataType: "objectInstances" }));
|
|
923
|
+
await screen.findByText('It looks like something is missing.');
|
|
924
|
+
});
|
|
925
|
+
it("should show a misconfiguration error if actionId doesn't match the form's actionId", async () => {
|
|
926
|
+
const form = {
|
|
927
|
+
id: 'simpleForm',
|
|
928
|
+
name: 'Simple Form',
|
|
929
|
+
entries: [],
|
|
930
|
+
actionId: 'notCreate',
|
|
931
|
+
objectId: 'simpleObject',
|
|
932
|
+
};
|
|
933
|
+
const simpleObject = {
|
|
934
|
+
id: 'simpleObject',
|
|
935
|
+
name: 'Simple Object',
|
|
936
|
+
actions: [
|
|
937
|
+
{
|
|
938
|
+
id: '_create',
|
|
939
|
+
name: 'Create',
|
|
940
|
+
type: 'create',
|
|
941
|
+
parameters: [],
|
|
942
|
+
outputEvent: 'created',
|
|
943
|
+
defaultFormId: 'simpleForm',
|
|
944
|
+
},
|
|
945
|
+
],
|
|
946
|
+
properties: [],
|
|
947
|
+
};
|
|
948
|
+
server.use(http.get(`/api/data/objects/simpleObject/effective`, () => HttpResponse.json(simpleObject)), http.get(`/api/data/forms/simpleForm`, () => HttpResponse.json(form)));
|
|
949
|
+
render(React.createElement(FormRendererContainer, { objectId: "simpleObject", actionId: "_create", dataType: "objectInstances" }));
|
|
950
|
+
await screen.findByText('It looks like something is missing.');
|
|
951
|
+
});
|
|
952
|
+
});
|
|
635
953
|
describe('when submitting a form with validation', () => {
|
|
636
954
|
const form = {
|
|
637
955
|
id: 'validationTestForm',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evoke-platform/ui-components",
|
|
3
|
-
"version": "1.10.0-dev.
|
|
3
|
+
"version": "1.10.0-dev.32",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/published/index.js",
|
|
6
6
|
"module": "dist/published/index.js",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"test": "vitest",
|
|
22
22
|
"test:ui": "vitest --ui",
|
|
23
23
|
"test:preview": "vitest-preview",
|
|
24
|
+
"coverage": "vitest run --coverage",
|
|
24
25
|
"copy-styles": "copyfiles -u 1 src/styles/*.css dist/published/",
|
|
25
26
|
"build": "rm -rf ./dist && tsc && npm run copy-styles",
|
|
26
27
|
"build:cjs": "tsc --module CommonJS --outDir dist/cjs",
|
|
@@ -52,22 +53,23 @@
|
|
|
52
53
|
"@storybook/react": "^7.6.20",
|
|
53
54
|
"@storybook/react-webpack5": "^7.6.20",
|
|
54
55
|
"@storybook/testing-library": "^0.0.11",
|
|
55
|
-
"@testing-library/jest-dom": "^6.
|
|
56
|
-
"@testing-library/react": "^
|
|
57
|
-
"@testing-library/user-event": "^14.
|
|
56
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
57
|
+
"@testing-library/react": "^16.3.0",
|
|
58
|
+
"@testing-library/user-event": "^14.6.1",
|
|
58
59
|
"@types/flat": "^5.0.5",
|
|
59
60
|
"@types/jest": "^28.1.4",
|
|
60
61
|
"@types/json-logic-js": "^2.0.8",
|
|
61
62
|
"@types/luxon": "^3.4.2",
|
|
62
63
|
"@types/nanoid-dictionary": "^4.2.3",
|
|
63
|
-
"@types/node": "^
|
|
64
|
+
"@types/node": "^24.10.0",
|
|
64
65
|
"@types/react": "^18.0.17",
|
|
65
66
|
"@types/react-dom": "^18.0.5",
|
|
66
67
|
"@types/react-input-mask": "^2.0.4",
|
|
67
68
|
"@typescript-eslint/eslint-plugin": "^5.52.0",
|
|
68
69
|
"@typescript-eslint/parser": "^5.35.1",
|
|
69
70
|
"@typescript-eslint/typescript-estree": "^5.35.1",
|
|
70
|
-
"@vitest/
|
|
71
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
72
|
+
"@vitest/ui": "^3.2.4",
|
|
71
73
|
"babel-jest": "^28.1.2",
|
|
72
74
|
"babel-loader": "^8.2.5",
|
|
73
75
|
"copyfiles": "^2.4.1",
|
|
@@ -88,7 +90,7 @@
|
|
|
88
90
|
"rimraf": "^3.0.2",
|
|
89
91
|
"storybook": "^7.6.20",
|
|
90
92
|
"typescript": "^4.7.3",
|
|
91
|
-
"vitest": "^
|
|
93
|
+
"vitest": "^3.2.4",
|
|
92
94
|
"vitest-preview": "^0.0.3",
|
|
93
95
|
"webpack": "^5.74.0",
|
|
94
96
|
"yalc": "^1.0.0-pre.53"
|