@truedat/df 8.2.4 → 8.3.1
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/package.json +4 -4
- package/src/components/SelectableDynamicForm.js +2 -2
- package/src/components/__tests__/SelectableDynamicForm.spec.js +44 -0
- package/src/components/__tests__/__snapshots__/SelectableDynamicForm.spec.js.snap +35 -0
- package/src/hooks/useTemplateRelations.js +43 -0
- package/src/templates/api.js +2 -1
- package/src/templates/components/templateForm/TemplateForm.js +17 -2
- package/src/templates/components/templateForm/TemplateRelationsForm.js +124 -0
- package/src/templates/components/templateForm/__tests__/TemplateForm.spec.js +156 -58
- package/src/templates/components/templateForm/__tests__/TemplateRelationsForm.spec.js +94 -0
- package/src/templates/components/templateForm/__tests__/__snapshots__/TemplateForm.spec.js.snap +747 -578
- package/src/templates/components/templateForm/__tests__/__snapshots__/TemplateRelationsForm.spec.js.snap +92 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/df",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.3.1",
|
|
4
4
|
"description": "Truedat Web Data Quality Module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"module": "src/index.js",
|
|
@@ -48,14 +48,14 @@
|
|
|
48
48
|
"@testing-library/jest-dom": "^6.6.3",
|
|
49
49
|
"@testing-library/react": "^16.3.0",
|
|
50
50
|
"@testing-library/user-event": "^14.6.1",
|
|
51
|
-
"@truedat/test": "8.
|
|
51
|
+
"@truedat/test": "8.3.1",
|
|
52
52
|
"identity-obj-proxy": "^3.0.0",
|
|
53
53
|
"jest": "^29.7.0",
|
|
54
54
|
"redux-saga-test-plan": "^4.0.6"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@apollo/client": "^3.13.8",
|
|
58
|
-
"@truedat/core": "8.
|
|
58
|
+
"@truedat/core": "8.3.1",
|
|
59
59
|
"axios": "^1.13.5",
|
|
60
60
|
"graphql": "^16.11.0",
|
|
61
61
|
"is-hotkey": "^0.2.0",
|
|
@@ -84,5 +84,5 @@
|
|
|
84
84
|
"semantic-ui-react": "^3.0.0-beta.2",
|
|
85
85
|
"swr": "^2.3.3"
|
|
86
86
|
},
|
|
87
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "59c8197b9eab936607c7d205ac25a378e6dd073e"
|
|
88
88
|
}
|
|
@@ -57,7 +57,7 @@ export default function SelectableDynamicForm({
|
|
|
57
57
|
|
|
58
58
|
return (
|
|
59
59
|
<>
|
|
60
|
-
{!actionKey || actionKey == "create" ? (
|
|
60
|
+
{(!actionKey || actionKey == "create") && !disableSelector ? (
|
|
61
61
|
<TemplateSelector
|
|
62
62
|
scope={scope}
|
|
63
63
|
domainIds={domainIds}
|
|
@@ -70,7 +70,7 @@ export default function SelectableDynamicForm({
|
|
|
70
70
|
required={required}
|
|
71
71
|
requiredError={requiredError}
|
|
72
72
|
selectedValue={template?.id}
|
|
73
|
-
disabled={disabled
|
|
73
|
+
disabled={disabled}
|
|
74
74
|
/>
|
|
75
75
|
) : null}
|
|
76
76
|
{!disabled && template ? (
|
|
@@ -175,4 +175,48 @@ describe("<SelectableDynamicForm />", () => {
|
|
|
175
175
|
expect(rendered.container).toMatchSnapshot();
|
|
176
176
|
});
|
|
177
177
|
});
|
|
178
|
+
|
|
179
|
+
describe("with disableSelector and selectedTemplate", () => {
|
|
180
|
+
const selectedTemplate = {
|
|
181
|
+
id: 1,
|
|
182
|
+
name: "template1",
|
|
183
|
+
content: [
|
|
184
|
+
{
|
|
185
|
+
name: "g1",
|
|
186
|
+
fields: [
|
|
187
|
+
{
|
|
188
|
+
name: "field1",
|
|
189
|
+
label: "field1",
|
|
190
|
+
type: "string",
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
it("does not render template selector when disableSelector is true", async () => {
|
|
198
|
+
const rendered = render(
|
|
199
|
+
<SelectableDynamicForm
|
|
200
|
+
{...props}
|
|
201
|
+
disableSelector
|
|
202
|
+
selectedTemplate={selectedTemplate}
|
|
203
|
+
/>
|
|
204
|
+
);
|
|
205
|
+
await waitForLoad(rendered);
|
|
206
|
+
expect(rendered.container.querySelector(".ui.search.selection.dropdown")).not.toBeInTheDocument();
|
|
207
|
+
expect(rendered.queryByText(/template\.selector\.placeholder/i)).not.toBeInTheDocument();
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("matches snapshot when disableSelector and selectedTemplate are set", async () => {
|
|
211
|
+
const rendered = render(
|
|
212
|
+
<SelectableDynamicForm
|
|
213
|
+
{...props}
|
|
214
|
+
disableSelector
|
|
215
|
+
selectedTemplate={selectedTemplate}
|
|
216
|
+
/>
|
|
217
|
+
);
|
|
218
|
+
await waitForLoad(rendered);
|
|
219
|
+
expect(rendered.container).toMatchSnapshot();
|
|
220
|
+
});
|
|
221
|
+
});
|
|
178
222
|
});
|
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
|
+
exports[`<SelectableDynamicForm /> with disableSelector and selectedTemplate matches snapshot when disableSelector and selectedTemplate are set 1`] = `
|
|
4
|
+
<div>
|
|
5
|
+
<div
|
|
6
|
+
class="ui segment"
|
|
7
|
+
>
|
|
8
|
+
<h4
|
|
9
|
+
class="ui header"
|
|
10
|
+
>
|
|
11
|
+
g1
|
|
12
|
+
</h4>
|
|
13
|
+
<div
|
|
14
|
+
class="field"
|
|
15
|
+
data-testid="form-field"
|
|
16
|
+
>
|
|
17
|
+
<label>
|
|
18
|
+
field1
|
|
19
|
+
</label>
|
|
20
|
+
<div
|
|
21
|
+
class="field"
|
|
22
|
+
>
|
|
23
|
+
<div
|
|
24
|
+
class="ui input"
|
|
25
|
+
>
|
|
26
|
+
<input
|
|
27
|
+
name="field1"
|
|
28
|
+
type="text"
|
|
29
|
+
value=""
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
`;
|
|
37
|
+
|
|
3
38
|
exports[`<SelectableDynamicForm /> with multiple templates matches error snapshot 1`] = `<div />`;
|
|
4
39
|
|
|
5
40
|
exports[`<SelectableDynamicForm /> with multiple templates matches the latest snapshot 1`] = `
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import useSWR from "swr";
|
|
2
|
+
import { apiJson } from "@truedat/core/services/api";
|
|
3
|
+
import { API_TEMPLATE_RELATIONS } from "@truedat/df/templates/api";
|
|
4
|
+
|
|
5
|
+
const buildTemplateRelationsUrl = ({
|
|
6
|
+
resourceType,
|
|
7
|
+
templateId,
|
|
8
|
+
resourceId,
|
|
9
|
+
listAll,
|
|
10
|
+
}) => {
|
|
11
|
+
const params = new URLSearchParams();
|
|
12
|
+
params.set("resource_type", resourceType);
|
|
13
|
+
if (templateId != null) params.set("template_id", String(templateId));
|
|
14
|
+
if (resourceId != null) params.set("resource_id", String(resourceId));
|
|
15
|
+
if (listAll) params.set("list_all", "true");
|
|
16
|
+
return `${API_TEMPLATE_RELATIONS}?${params.toString()}`;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const useTemplateRelations = (options = {}) => {
|
|
20
|
+
const { resourceType, templateId, resourceId, scope, listAll } = options;
|
|
21
|
+
const canFetch = !!resourceType;
|
|
22
|
+
const url = canFetch
|
|
23
|
+
? buildTemplateRelationsUrl({
|
|
24
|
+
resourceType,
|
|
25
|
+
templateId,
|
|
26
|
+
resourceId,
|
|
27
|
+
listAll,
|
|
28
|
+
})
|
|
29
|
+
: null;
|
|
30
|
+
const key = url && scope != null ? [url, scope] : url;
|
|
31
|
+
const fetcher = (keyOrArray) =>
|
|
32
|
+
apiJson(Array.isArray(keyOrArray) ? keyOrArray[0] : keyOrArray);
|
|
33
|
+
const { data, error, mutate } = useSWR(key, fetcher);
|
|
34
|
+
const response = data?.data ?? data;
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
default: response?.default ?? null,
|
|
38
|
+
resource: response?.resource ?? [],
|
|
39
|
+
error,
|
|
40
|
+
loading: !error && !data,
|
|
41
|
+
mutate,
|
|
42
|
+
};
|
|
43
|
+
};
|
package/src/templates/api.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
|
-
import { useState, useEffect } from "react";
|
|
2
|
+
import { useState, useEffect, useCallback } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import { connect } from "react-redux";
|
|
5
5
|
import { Header, Form, Grid, Label, Divider } from "semantic-ui-react";
|
|
6
6
|
import { useIntl, FormattedMessage } from "react-intl";
|
|
7
|
+
import { useWebContext } from "@truedat/core/webContext";
|
|
7
8
|
import GroupsList from "./GroupsList";
|
|
8
9
|
import ActiveGroupForm from "./ActiveGroupForm";
|
|
9
10
|
import TemplateFormActions from "./TemplateFormActions";
|
|
11
|
+
import TemplateRelationsForm from "./TemplateRelationsForm";
|
|
10
12
|
import { parseContentValidation } from "./contentValidation";
|
|
11
13
|
|
|
12
14
|
const scopeOptions = (formatMessage) =>
|
|
@@ -31,10 +33,12 @@ const scopeOptions = (formatMessage) =>
|
|
|
31
33
|
|
|
32
34
|
export const TemplateForm = ({ loading, template, onSubmit }) => {
|
|
33
35
|
const { formatMessage } = useIntl();
|
|
36
|
+
const { scopesWithRelations = [] } = useWebContext();
|
|
34
37
|
const [activeGroup, setActiveGroup] = useState(0);
|
|
35
38
|
const [editedTemplate, setEditedTemplate] = useState({
|
|
36
39
|
...template,
|
|
37
40
|
content: template?.content || [],
|
|
41
|
+
template_resource_relations: template?.template_resource_relations ?? [],
|
|
38
42
|
});
|
|
39
43
|
|
|
40
44
|
useEffect(() => {
|
|
@@ -61,6 +65,10 @@ export const TemplateForm = ({ loading, template, onSubmit }) => {
|
|
|
61
65
|
content: [...editedTemplate.content, { name: "", fields: [] }],
|
|
62
66
|
});
|
|
63
67
|
|
|
68
|
+
const handleRelationsChange = useCallback((relations) => {
|
|
69
|
+
setEditedTemplate((prev) => _.assoc("template_resource_relations", relations)(prev));
|
|
70
|
+
}, []);
|
|
71
|
+
|
|
64
72
|
const formattedFields = (fields) => _.flow(
|
|
65
73
|
_.map((field) => {
|
|
66
74
|
const fieldProperties = [
|
|
@@ -205,9 +213,16 @@ export const TemplateForm = ({ loading, template, onSubmit }) => {
|
|
|
205
213
|
label={formatMessage({ id: "template.form.subscope" })}
|
|
206
214
|
value={subscopeValue}
|
|
207
215
|
onChange={handleChange}
|
|
208
|
-
disabled={editedTemplate?.scope !== "bg" && editedTemplate?.scope !== "ri"}
|
|
216
|
+
disabled={editedTemplate?.scope !== "bg" && editedTemplate?.scope !== "ri"}
|
|
209
217
|
/>
|
|
210
218
|
</Form.Group>
|
|
219
|
+
{scopesWithRelations?.includes(editedTemplate.scope) && (
|
|
220
|
+
<TemplateRelationsForm
|
|
221
|
+
scope={editedTemplate.scope}
|
|
222
|
+
template_id={editedTemplate.id}
|
|
223
|
+
onRelationsChange={handleRelationsChange}
|
|
224
|
+
/>
|
|
225
|
+
)}
|
|
211
226
|
<Divider horizontal>
|
|
212
227
|
<Header as="h4">
|
|
213
228
|
<FormattedMessage id="template.form.fieldGroups" />
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
import _ from "lodash/fp";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { Form, Header, Divider } from "semantic-ui-react";
|
|
5
|
+
import { FormattedMessage, useIntl } from "react-intl";
|
|
6
|
+
import { useGrantableSystems } from "@truedat/dd/hooks/useSystems";
|
|
7
|
+
import { useTemplateRelations } from "@truedat/df/hooks/useTemplateRelations";
|
|
8
|
+
|
|
9
|
+
const scopeToResourceType = { gr: "system" };
|
|
10
|
+
|
|
11
|
+
const buildRelations = (resourceType, defaultTemplate, resourceRelations) => {
|
|
12
|
+
if (!resourceType) return [];
|
|
13
|
+
return [
|
|
14
|
+
...(defaultTemplate
|
|
15
|
+
? [{ resource_type: resourceType, resource_id: null }]
|
|
16
|
+
: []),
|
|
17
|
+
...(resourceRelations || []).map((resource_id) => ({
|
|
18
|
+
resource_type: resourceType,
|
|
19
|
+
resource_id,
|
|
20
|
+
})),
|
|
21
|
+
];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const TemplateRelationsForm = ({ scope, template_id, onRelationsChange }) => {
|
|
25
|
+
const { formatMessage } = useIntl();
|
|
26
|
+
const { data: grantableSystems } = useGrantableSystems();
|
|
27
|
+
const resourceType = scopeToResourceType[scope];
|
|
28
|
+
const {
|
|
29
|
+
default: defaultRelation,
|
|
30
|
+
resource: templateResourceRelations,
|
|
31
|
+
loading,
|
|
32
|
+
} = useTemplateRelations({
|
|
33
|
+
resourceType,
|
|
34
|
+
templateId: template_id,
|
|
35
|
+
scope,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const isServerDefault = defaultRelation?.template_id === template_id;
|
|
39
|
+
const [defaultTemplate, setDefaultTemplate] = useState(false);
|
|
40
|
+
const [resourceRelations, setResourceRelations] = useState([]);
|
|
41
|
+
|
|
42
|
+
const serverSnapshot = loading
|
|
43
|
+
? null
|
|
44
|
+
: [
|
|
45
|
+
isServerDefault,
|
|
46
|
+
(templateResourceRelations || []).map((r) => r.resource_id).join(","),
|
|
47
|
+
].join("|");
|
|
48
|
+
const lastSyncedRef = useRef(null);
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (serverSnapshot === null) return;
|
|
52
|
+
if (lastSyncedRef.current === serverSnapshot) return;
|
|
53
|
+
|
|
54
|
+
lastSyncedRef.current = serverSnapshot;
|
|
55
|
+
setDefaultTemplate(isServerDefault);
|
|
56
|
+
setResourceRelations(
|
|
57
|
+
_.map(({ resource_id }) => resource_id)(templateResourceRelations || []),
|
|
58
|
+
);
|
|
59
|
+
}, [serverSnapshot, isServerDefault, templateResourceRelations]);
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (typeof onRelationsChange !== "function" || !resourceType) return;
|
|
63
|
+
onRelationsChange(
|
|
64
|
+
buildRelations(resourceType, defaultTemplate, resourceRelations),
|
|
65
|
+
);
|
|
66
|
+
}, [resourceType, defaultTemplate, resourceRelations, onRelationsChange]);
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<>
|
|
70
|
+
<Divider horizontal>
|
|
71
|
+
<Header as="h4">
|
|
72
|
+
<FormattedMessage id="template.relations.header" />
|
|
73
|
+
</Header>
|
|
74
|
+
</Divider>
|
|
75
|
+
<Form.Group>
|
|
76
|
+
<Form.Checkbox
|
|
77
|
+
id="template_relation_default"
|
|
78
|
+
error={
|
|
79
|
+
!isServerDefault && defaultTemplate
|
|
80
|
+
? {
|
|
81
|
+
content: formatMessage({
|
|
82
|
+
id: "template.relations.default.content",
|
|
83
|
+
}),
|
|
84
|
+
pointing: "left",
|
|
85
|
+
}
|
|
86
|
+
: false
|
|
87
|
+
}
|
|
88
|
+
name="template_relation_default"
|
|
89
|
+
label={formatMessage({ id: "template.relations.default" })}
|
|
90
|
+
onChange={(_e, { checked }) => setDefaultTemplate(checked)}
|
|
91
|
+
checked={defaultTemplate}
|
|
92
|
+
/>
|
|
93
|
+
</Form.Group>
|
|
94
|
+
<Form.Group>
|
|
95
|
+
<Form.Dropdown
|
|
96
|
+
label={formatMessage({ id: "template.relations.related" })}
|
|
97
|
+
name="template_relation_resource"
|
|
98
|
+
placeholder={formatMessage({
|
|
99
|
+
id: "template.relations.systems.placeholder",
|
|
100
|
+
})}
|
|
101
|
+
search
|
|
102
|
+
selection
|
|
103
|
+
multiple
|
|
104
|
+
clearable
|
|
105
|
+
options={_.map(({ id, name }) => ({
|
|
106
|
+
key: id,
|
|
107
|
+
value: id,
|
|
108
|
+
text: name,
|
|
109
|
+
}))(grantableSystems?.data)}
|
|
110
|
+
value={resourceRelations}
|
|
111
|
+
onChange={(_e, { value }) => setResourceRelations(value)}
|
|
112
|
+
/>
|
|
113
|
+
</Form.Group>
|
|
114
|
+
</>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
TemplateRelationsForm.propTypes = {
|
|
119
|
+
scope: PropTypes.string.isRequired,
|
|
120
|
+
template_id: PropTypes.number,
|
|
121
|
+
onRelationsChange: PropTypes.func,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export default TemplateRelationsForm;
|
|
@@ -1,71 +1,169 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from "react";
|
|
2
|
+
import userEvent from "@testing-library/user-event";
|
|
3
|
+
import { waitFor } from "@testing-library/react";
|
|
4
|
+
import { render, waitForLoad } from "@truedat/test/render";
|
|
2
5
|
import TemplateForm from "../TemplateForm";
|
|
3
6
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
label: "",
|
|
8
|
-
scope: "",
|
|
9
|
-
content: [],
|
|
10
|
-
};
|
|
7
|
+
jest.mock("@truedat/core/webContext", () => ({
|
|
8
|
+
useWebContext: jest.fn(() => ({ scopesWithRelations: ["gr"] })),
|
|
9
|
+
}));
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
jest.mock("../TemplateRelationsForm", () => {
|
|
12
|
+
const React = require("react");
|
|
13
|
+
return {
|
|
14
|
+
__esModule: true,
|
|
15
|
+
default: ({ onRelationsChange }) => {
|
|
16
|
+
React.useEffect(() => {
|
|
17
|
+
if (typeof onRelationsChange === "function") {
|
|
18
|
+
onRelationsChange([
|
|
19
|
+
{ resource_type: "system", resource_id: null },
|
|
20
|
+
{ resource_type: "system", resource_id: 1 },
|
|
21
|
+
]);
|
|
22
|
+
}
|
|
23
|
+
}, [onRelationsChange]);
|
|
24
|
+
return <div data-testid="template-relations-form" />;
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
});
|
|
18
28
|
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
cardinality: "*",
|
|
25
|
-
default: {
|
|
26
|
-
origin: "default",
|
|
27
|
-
value: "",
|
|
28
|
-
},
|
|
29
|
-
label: "field",
|
|
30
|
-
name: "field",
|
|
31
|
-
subscribable: false,
|
|
32
|
-
type: "string",
|
|
33
|
-
values: null,
|
|
34
|
-
widget: "string",
|
|
35
|
-
disabledName: true,
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
name: "group",
|
|
39
|
-
},
|
|
40
|
-
];
|
|
41
|
-
|
|
42
|
-
const filledTemplate = {
|
|
43
|
-
...template,
|
|
44
|
-
content: templateContent,
|
|
29
|
+
const validTemplate = {
|
|
30
|
+
name: "Test Template",
|
|
31
|
+
label: "Test Label",
|
|
32
|
+
scope: "gr",
|
|
33
|
+
content: [{ name: "Group1", fields: [{ name: "field1", label: "Field 1", type: "string" }] }],
|
|
45
34
|
};
|
|
46
35
|
|
|
47
36
|
describe("<TemplateForm />", () => {
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
const { useWebContext } = require("@truedat/core/webContext");
|
|
39
|
+
useWebContext.mockReturnValue({ scopesWithRelations: ["gr"] });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("matches snapshot when scope has relations", async () => {
|
|
43
|
+
const renderOpts = {
|
|
44
|
+
state: {
|
|
45
|
+
templateDeleting: false,
|
|
46
|
+
templateSaving: false,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
const rendered = render(
|
|
50
|
+
<TemplateForm template={validTemplate} onSubmit={jest.fn()} loading={false} />,
|
|
51
|
+
renderOpts
|
|
52
|
+
);
|
|
53
|
+
await waitForLoad(rendered);
|
|
54
|
+
expect(rendered.container).toMatchSnapshot();
|
|
54
55
|
});
|
|
55
56
|
|
|
56
|
-
it("matches
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
|
|
57
|
+
it("matches snapshot when scope has no relations", async () => {
|
|
58
|
+
const { useWebContext } = require("@truedat/core/webContext");
|
|
59
|
+
useWebContext.mockReturnValue({ scopesWithRelations: [] });
|
|
60
|
+
const templateOtherScope = { ...validTemplate, scope: "dd" };
|
|
61
|
+
const renderOpts = {
|
|
62
|
+
state: {
|
|
63
|
+
templateDeleting: false,
|
|
64
|
+
templateSaving: false,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
const rendered = render(
|
|
68
|
+
<TemplateForm template={templateOtherScope} onSubmit={jest.fn()} loading={false} />,
|
|
69
|
+
renderOpts
|
|
70
|
+
);
|
|
71
|
+
await waitForLoad(rendered);
|
|
72
|
+
expect(rendered.container).toMatchSnapshot();
|
|
62
73
|
});
|
|
63
74
|
|
|
64
|
-
it("
|
|
65
|
-
const
|
|
66
|
-
const renderOpts = {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
75
|
+
it("includes template_resource_relations in submit payload when scope has relations", async () => {
|
|
76
|
+
const onSubmit = jest.fn();
|
|
77
|
+
const renderOpts = {
|
|
78
|
+
state: {
|
|
79
|
+
templateDeleting: false,
|
|
80
|
+
templateSaving: false,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
const rendered = render(
|
|
84
|
+
<TemplateForm template={validTemplate} onSubmit={onSubmit} loading={false} />,
|
|
85
|
+
renderOpts
|
|
86
|
+
);
|
|
87
|
+
await waitForLoad(rendered);
|
|
88
|
+
|
|
89
|
+
await waitFor(() => {
|
|
90
|
+
expect(rendered.getByTestId("template-relations-form")).toBeInTheDocument();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const user = userEvent.setup({ delay: null });
|
|
94
|
+
await user.click(rendered.getByRole("button", { name: /save/i }));
|
|
95
|
+
|
|
96
|
+
await waitFor(() => {
|
|
97
|
+
expect(onSubmit).toHaveBeenCalled();
|
|
98
|
+
});
|
|
99
|
+
const submittedPayload = onSubmit.mock.calls[0][0];
|
|
100
|
+
expect(submittedPayload.template.template_resource_relations).toEqual([
|
|
101
|
+
{ resource_type: "system", resource_id: null },
|
|
102
|
+
{ resource_type: "system", resource_id: 1 },
|
|
103
|
+
]);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("initializes template_resource_relations from template when provided", async () => {
|
|
107
|
+
const onSubmit = jest.fn();
|
|
108
|
+
const initialRelations = [
|
|
109
|
+
{ resource_type: "system", resource_id: null },
|
|
110
|
+
{ resource_type: "system", resource_id: 2 },
|
|
111
|
+
];
|
|
112
|
+
const templateWithRelations = {
|
|
113
|
+
...validTemplate,
|
|
114
|
+
template_resource_relations: initialRelations,
|
|
115
|
+
};
|
|
116
|
+
const renderOpts = {
|
|
117
|
+
state: {
|
|
118
|
+
templateDeleting: false,
|
|
119
|
+
templateSaving: false,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
const rendered = render(
|
|
123
|
+
<TemplateForm template={templateWithRelations} onSubmit={onSubmit} loading={false} />,
|
|
124
|
+
renderOpts
|
|
125
|
+
);
|
|
126
|
+
await waitForLoad(rendered);
|
|
127
|
+
|
|
128
|
+
const user = userEvent.setup({ delay: null });
|
|
129
|
+
await user.click(rendered.getByRole("button", { name: /save/i }));
|
|
130
|
+
|
|
131
|
+
await waitFor(() => {
|
|
132
|
+
expect(onSubmit).toHaveBeenCalled();
|
|
133
|
+
});
|
|
134
|
+
const submittedPayload = onSubmit.mock.calls[0][0];
|
|
135
|
+
expect(submittedPayload.template.template_resource_relations).toEqual([
|
|
136
|
+
{ resource_type: "system", resource_id: null },
|
|
137
|
+
{ resource_type: "system", resource_id: 1 },
|
|
138
|
+
]);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("does not render TemplateRelationsForm when scope is not in scopesWithRelations", async () => {
|
|
142
|
+
const { useWebContext } = require("@truedat/core/webContext");
|
|
143
|
+
useWebContext.mockReturnValue({ scopesWithRelations: [] });
|
|
144
|
+
const templateOtherScope = { ...validTemplate, scope: "dd" };
|
|
145
|
+
const onSubmit = jest.fn();
|
|
146
|
+
const renderOpts = {
|
|
147
|
+
state: {
|
|
148
|
+
templateDeleting: false,
|
|
149
|
+
templateSaving: false,
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
const rendered = render(
|
|
153
|
+
<TemplateForm template={templateOtherScope} onSubmit={onSubmit} loading={false} />,
|
|
154
|
+
renderOpts
|
|
155
|
+
);
|
|
156
|
+
await waitForLoad(rendered);
|
|
157
|
+
|
|
158
|
+
expect(rendered.queryByTestId("template-relations-form")).not.toBeInTheDocument();
|
|
159
|
+
|
|
160
|
+
const user = userEvent.setup({ delay: null });
|
|
161
|
+
await user.click(rendered.getByRole("button", { name: /save/i }));
|
|
162
|
+
|
|
163
|
+
await waitFor(() => {
|
|
164
|
+
expect(onSubmit).toHaveBeenCalled();
|
|
165
|
+
});
|
|
166
|
+
const submittedPayload = onSubmit.mock.calls[0][0];
|
|
167
|
+
expect(submittedPayload.template.template_resource_relations).toEqual([]);
|
|
70
168
|
});
|
|
71
169
|
});
|