@truedat/dd 8.10.2 → 8.10.3
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 +3 -3
- package/src/components/Graphs.js +109 -0
- package/src/components/LineageDomainSelectorSkeleton.js +8 -0
- package/src/components/LineageDownloadButton.js +29 -6
- package/src/components/LineageEventsPanel.js +206 -0
- package/src/components/LineageForm.js +265 -144
- package/src/components/LineageGraph.js +0 -1
- package/src/components/LineageHeader.js +33 -0
- package/src/components/LineageResourceToggle.js +56 -0
- package/src/components/LineageRoutes.js +2 -31
- package/src/components/LineageSelectionPanel.js +165 -0
- package/src/components/__tests__/LineageForm.spec.js +343 -3
- package/src/components/__tests__/LineageRoutes.spec.js +62 -76
- package/src/components/__tests__/__snapshots__/LineageForm.spec.js.snap +291 -250
- package/src/components/__tests__/__snapshots__/LineageRoutes.spec.js.snap +19 -43
- package/src/components/index.js +12 -0
- package/src/components/lineageDomainCache.js +101 -0
- package/src/components/lineageEventHelpers.js +195 -0
- package/src/styles/lineageGraph.less +1213 -47
- package/src/components/Lineage.js +0 -20
- package/src/components/LineageSample.js +0 -20
- package/src/components/__tests__/Lineage.spec.js +0 -16
- package/src/components/__tests__/__snapshots__/Lineage.spec.js.snap +0 -163
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { connect } from "react-redux";
|
|
4
|
+
import { FormattedMessage, useIntl } from "react-intl";
|
|
5
|
+
import { Button, Icon } from "semantic-ui-react";
|
|
6
|
+
import { fetchLineageEvents } from "../routines";
|
|
7
|
+
import LineageForm from "./LineageForm";
|
|
8
|
+
import LineageEventsPanel from "./LineageEventsPanel";
|
|
9
|
+
import { groupLineageEvents } from "./lineageEventHelpers";
|
|
10
|
+
|
|
11
|
+
export const LineageSelectionPanel = ({
|
|
12
|
+
collapsed,
|
|
13
|
+
fetchLineageEvents,
|
|
14
|
+
onGraphLoad,
|
|
15
|
+
sidebarHintActive,
|
|
16
|
+
sidebarHintOn,
|
|
17
|
+
sidebarHintToken,
|
|
18
|
+
lineageEvents = [],
|
|
19
|
+
onToggle,
|
|
20
|
+
}) => {
|
|
21
|
+
const { formatMessage } = useIntl();
|
|
22
|
+
const [activeSidebarTab, setActiveSidebarTab] = useState("lineage");
|
|
23
|
+
const sidebarRef = useRef();
|
|
24
|
+
const toggleLabel = formatMessage({
|
|
25
|
+
id: collapsed ? "lineage.sidebar.expand" : "lineage.sidebar.collapse",
|
|
26
|
+
});
|
|
27
|
+
const activeRailLabel =
|
|
28
|
+
activeSidebarTab === "events"
|
|
29
|
+
? "lineage.sidebar.tabs.graphs"
|
|
30
|
+
: "lineage.sidebar.tabs.lineage";
|
|
31
|
+
const openTab = (tab) => {
|
|
32
|
+
setActiveSidebarTab(tab);
|
|
33
|
+
if (tab === "events") fetchLineageEvents();
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
fetchLineageEvents();
|
|
38
|
+
}, [fetchLineageEvents]);
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (collapsed) return;
|
|
42
|
+
|
|
43
|
+
const handleClickOutside = (e) => {
|
|
44
|
+
if (sidebarRef.current && !sidebarRef.current.contains(e.target)) {
|
|
45
|
+
onToggle();
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
50
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
51
|
+
}, [collapsed, onToggle]);
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<aside
|
|
55
|
+
className="lineage-view__sidebar"
|
|
56
|
+
aria-expanded={!collapsed}
|
|
57
|
+
ref={sidebarRef}
|
|
58
|
+
>
|
|
59
|
+
<div className="lineage-view__sidebar-panel" aria-hidden={collapsed}>
|
|
60
|
+
<div className="lineage-view__sidebar-header">
|
|
61
|
+
<div className="lineage-view__sidebar-tabs" role="tablist">
|
|
62
|
+
<button
|
|
63
|
+
aria-selected={activeSidebarTab === "lineage"}
|
|
64
|
+
className="lineage-view__sidebar-tab"
|
|
65
|
+
onClick={() => openTab("lineage")}
|
|
66
|
+
role="tab"
|
|
67
|
+
type="button"
|
|
68
|
+
>
|
|
69
|
+
<span className="lineage-view__sidebar-tab-icon">
|
|
70
|
+
<Icon name="sitemap" />
|
|
71
|
+
</span>
|
|
72
|
+
<span className="lineage-view__sidebar-tab-label">
|
|
73
|
+
<FormattedMessage
|
|
74
|
+
id="lineage.sidebar.tabs.lineage"
|
|
75
|
+
defaultMessage="Lineage"
|
|
76
|
+
/>
|
|
77
|
+
</span>
|
|
78
|
+
</button>
|
|
79
|
+
<button
|
|
80
|
+
aria-selected={activeSidebarTab === "events"}
|
|
81
|
+
className="lineage-view__sidebar-tab"
|
|
82
|
+
onClick={() => openTab("events")}
|
|
83
|
+
role="tab"
|
|
84
|
+
type="button"
|
|
85
|
+
>
|
|
86
|
+
<span className="lineage-view__sidebar-tab-icon">
|
|
87
|
+
<Icon name="history" />
|
|
88
|
+
</span>
|
|
89
|
+
<span className="lineage-view__sidebar-tab-label">
|
|
90
|
+
<FormattedMessage
|
|
91
|
+
id="lineage.sidebar.tabs.graphs"
|
|
92
|
+
defaultMessage="Graphs"
|
|
93
|
+
/>
|
|
94
|
+
</span>
|
|
95
|
+
<span className="lineage-view__sidebar-tab-count">
|
|
96
|
+
{groupLineageEvents(lineageEvents).length}
|
|
97
|
+
</span>
|
|
98
|
+
</button>
|
|
99
|
+
</div>
|
|
100
|
+
<Button
|
|
101
|
+
basic
|
|
102
|
+
icon
|
|
103
|
+
size="mini"
|
|
104
|
+
type="button"
|
|
105
|
+
aria-label={toggleLabel}
|
|
106
|
+
title={toggleLabel}
|
|
107
|
+
className="lineage-view__sidebar-toggle"
|
|
108
|
+
onClick={onToggle}
|
|
109
|
+
>
|
|
110
|
+
<Icon name="angle left" />
|
|
111
|
+
</Button>
|
|
112
|
+
</div>
|
|
113
|
+
<div
|
|
114
|
+
className={`lineage-view__sidebar-content lineage-view__sidebar-content--${activeSidebarTab}`}
|
|
115
|
+
>
|
|
116
|
+
{activeSidebarTab === "lineage" ? (
|
|
117
|
+
<LineageForm
|
|
118
|
+
autoCollapse={false}
|
|
119
|
+
collapsible={false}
|
|
120
|
+
onGraphSubmit={onGraphLoad}
|
|
121
|
+
showDownloadButton={false}
|
|
122
|
+
/>
|
|
123
|
+
) : (
|
|
124
|
+
<LineageEventsPanel onGraphLoad={onGraphLoad} />
|
|
125
|
+
)}
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
<Button
|
|
129
|
+
basic
|
|
130
|
+
icon
|
|
131
|
+
type="button"
|
|
132
|
+
aria-label={toggleLabel}
|
|
133
|
+
aria-hidden={!collapsed}
|
|
134
|
+
title={toggleLabel}
|
|
135
|
+
className={`lineage-view__sidebar-rail${
|
|
136
|
+
sidebarHintActive ? " lineage-view__sidebar-rail--hint" : ""
|
|
137
|
+
}${sidebarHintOn ? " lineage-view__sidebar-rail--hint-on" : ""}`}
|
|
138
|
+
key={`lineage-sidebar-rail-${sidebarHintToken}`}
|
|
139
|
+
onClick={onToggle}
|
|
140
|
+
>
|
|
141
|
+
<Icon name="angle right" />
|
|
142
|
+
<span>
|
|
143
|
+
<FormattedMessage id={activeRailLabel} />
|
|
144
|
+
</span>
|
|
145
|
+
</Button>
|
|
146
|
+
</aside>
|
|
147
|
+
);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
LineageSelectionPanel.propTypes = {
|
|
151
|
+
collapsed: PropTypes.bool.isRequired,
|
|
152
|
+
fetchLineageEvents: PropTypes.func,
|
|
153
|
+
lineageEvents: PropTypes.array,
|
|
154
|
+
onGraphLoad: PropTypes.func.isRequired,
|
|
155
|
+
onToggle: PropTypes.func.isRequired,
|
|
156
|
+
sidebarHintActive: PropTypes.bool,
|
|
157
|
+
sidebarHintOn: PropTypes.bool,
|
|
158
|
+
sidebarHintToken: PropTypes.number,
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const mapStateToProps = ({ lineageEvents }) => ({ lineageEvents });
|
|
162
|
+
|
|
163
|
+
export default connect(mapStateToProps, { fetchLineageEvents })(
|
|
164
|
+
LineageSelectionPanel,
|
|
165
|
+
);
|
|
@@ -1,7 +1,46 @@
|
|
|
1
|
+
import { waitFor } from "@testing-library/react";
|
|
1
2
|
import userEvent from "@testing-library/user-event";
|
|
2
3
|
import { render, waitForLoad } from "@truedat/test/render";
|
|
3
|
-
import {
|
|
4
|
+
import { DOMAINS_QUERY } from "@truedat/core/api/queries";
|
|
4
5
|
import { LineageForm } from "../LineageForm";
|
|
6
|
+
import { LINEAGE_DOMAIN_AVAILABILITY_CACHE_KEY } from "../lineageDomainCache";
|
|
7
|
+
|
|
8
|
+
const defaultDomains = [
|
|
9
|
+
{
|
|
10
|
+
__typename: "Domain",
|
|
11
|
+
name: "fooDomain",
|
|
12
|
+
id: "1",
|
|
13
|
+
externalId: "foo",
|
|
14
|
+
parentId: null,
|
|
15
|
+
actions: null,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
__typename: "Domain",
|
|
19
|
+
name: "barDomain",
|
|
20
|
+
id: "2",
|
|
21
|
+
externalId: "bar",
|
|
22
|
+
parentId: null,
|
|
23
|
+
actions: null,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
__typename: "Domain",
|
|
27
|
+
name: "bazDomain",
|
|
28
|
+
id: "3",
|
|
29
|
+
externalId: "baz",
|
|
30
|
+
parentId: null,
|
|
31
|
+
actions: null,
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const lineageDomainsMock = (domains = defaultDomains) => ({
|
|
36
|
+
request: {
|
|
37
|
+
query: DOMAINS_QUERY,
|
|
38
|
+
variables: { action: "viewLineage" },
|
|
39
|
+
},
|
|
40
|
+
result: {
|
|
41
|
+
data: { domains },
|
|
42
|
+
},
|
|
43
|
+
});
|
|
5
44
|
|
|
6
45
|
describe("<LineageForm />", () => {
|
|
7
46
|
const fetchNodes = jest.fn();
|
|
@@ -15,6 +54,9 @@ describe("<LineageForm />", () => {
|
|
|
15
54
|
const props = {
|
|
16
55
|
createGraph: jest.fn(),
|
|
17
56
|
clearNodes: jest.fn(),
|
|
57
|
+
domainAvailabilityChecker: jest.fn(async (domains) =>
|
|
58
|
+
domains.map(({ id }) => [`${id}`, true]),
|
|
59
|
+
),
|
|
18
60
|
graph: {},
|
|
19
61
|
groupOptions,
|
|
20
62
|
resourceOptions,
|
|
@@ -28,15 +70,105 @@ describe("<LineageForm />", () => {
|
|
|
28
70
|
};
|
|
29
71
|
|
|
30
72
|
const renderOpts = {
|
|
31
|
-
mocks: [
|
|
73
|
+
mocks: [lineageDomainsMock()],
|
|
32
74
|
};
|
|
33
75
|
|
|
76
|
+
beforeEach(() => {
|
|
77
|
+
localStorage.clear();
|
|
78
|
+
});
|
|
79
|
+
|
|
34
80
|
it("matches the latest snapshot", async () => {
|
|
35
81
|
const rendered = render(<LineageForm {...props} />, renderOpts);
|
|
36
82
|
await waitForLoad(rendered);
|
|
37
83
|
expect(rendered.container).toMatchSnapshot();
|
|
38
84
|
});
|
|
39
85
|
|
|
86
|
+
it("uses the form loading state while lineage options are loading", async () => {
|
|
87
|
+
const rendered = render(
|
|
88
|
+
<LineageForm {...props} collapsible={false} loading />,
|
|
89
|
+
renderOpts,
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
expect(
|
|
93
|
+
rendered.container.querySelector(".lineage-toolbar__form.loading"),
|
|
94
|
+
).toBeInTheDocument();
|
|
95
|
+
expect(
|
|
96
|
+
rendered.queryByText("lineage.graph.loading"),
|
|
97
|
+
).not.toBeInTheDocument();
|
|
98
|
+
expect(
|
|
99
|
+
rendered.container.querySelector(
|
|
100
|
+
".lineage-events-panel__empty .circle.notched.loading.icon",
|
|
101
|
+
),
|
|
102
|
+
).not.toBeInTheDocument();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("renders a domain dropdown skeleton while lineage domains are loading", async () => {
|
|
106
|
+
const rendered = render(<LineageForm {...props} collapsible={false} />, {
|
|
107
|
+
mocks: [
|
|
108
|
+
{
|
|
109
|
+
...lineageDomainsMock(),
|
|
110
|
+
delay: 100,
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
expect(
|
|
116
|
+
rendered.container.querySelector(".lineage-domain-selector-skeleton"),
|
|
117
|
+
).toBeInTheDocument();
|
|
118
|
+
|
|
119
|
+
await waitFor(() => {
|
|
120
|
+
expect(
|
|
121
|
+
rendered.queryByText("domain.selector.placeholder"),
|
|
122
|
+
).toBeInTheDocument();
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("uses cached lineage domain availability while it is valid", async () => {
|
|
127
|
+
const domainAvailabilityChecker = jest.fn();
|
|
128
|
+
localStorage.setItem(
|
|
129
|
+
LINEAGE_DOMAIN_AVAILABILITY_CACHE_KEY,
|
|
130
|
+
JSON.stringify({
|
|
131
|
+
checks: [
|
|
132
|
+
["1", true],
|
|
133
|
+
["2", false],
|
|
134
|
+
["3", true],
|
|
135
|
+
],
|
|
136
|
+
domainIds: ["1", "2", "3"],
|
|
137
|
+
expiresAt: Date.now() + 60000,
|
|
138
|
+
}),
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const rendered = render(
|
|
142
|
+
<LineageForm
|
|
143
|
+
{...props}
|
|
144
|
+
domainAvailabilityChecker={domainAvailabilityChecker}
|
|
145
|
+
/>,
|
|
146
|
+
renderOpts,
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
await waitFor(() => {
|
|
150
|
+
expect(
|
|
151
|
+
rendered.queryByText("domain.selector.placeholder"),
|
|
152
|
+
).toBeInTheDocument();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(domainAvailabilityChecker).not.toHaveBeenCalled();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("renders the lineage sidebar header with the same panel layout as my graphs", async () => {
|
|
159
|
+
const rendered = render(
|
|
160
|
+
<LineageForm {...props} collapsible={false} resourceOptions={[]} />,
|
|
161
|
+
renderOpts,
|
|
162
|
+
);
|
|
163
|
+
await waitForLoad(rendered);
|
|
164
|
+
const header = rendered
|
|
165
|
+
.getByText("lineage.form.panel.header")
|
|
166
|
+
.closest("div");
|
|
167
|
+
|
|
168
|
+
expect(header).toHaveClass("lineage-events-panel__header");
|
|
169
|
+
expect(header.querySelector(".sitemap.icon")).toBeInTheDocument();
|
|
170
|
+
});
|
|
171
|
+
|
|
40
172
|
it("selecting group will call selectGroup function", async () => {
|
|
41
173
|
const selectGroup = jest.fn();
|
|
42
174
|
const rendered = render(
|
|
@@ -55,7 +187,14 @@ describe("<LineageForm />", () => {
|
|
|
55
187
|
it("selecting resources will call selectResources function", async () => {
|
|
56
188
|
const selectResources = jest.fn();
|
|
57
189
|
const rendered = render(
|
|
58
|
-
<LineageForm
|
|
190
|
+
<LineageForm
|
|
191
|
+
{...props}
|
|
192
|
+
resourceOptions={[
|
|
193
|
+
{ key: "res1", text: "res1", value: "res1" },
|
|
194
|
+
{ key: "res2", text: "res2", value: "res2" },
|
|
195
|
+
]}
|
|
196
|
+
selectResources={selectResources}
|
|
197
|
+
/>,
|
|
59
198
|
renderOpts,
|
|
60
199
|
);
|
|
61
200
|
await waitForLoad(rendered);
|
|
@@ -68,13 +207,105 @@ describe("<LineageForm />", () => {
|
|
|
68
207
|
expect(selectResources).toHaveBeenCalledWith(["res1"]);
|
|
69
208
|
});
|
|
70
209
|
|
|
210
|
+
it("selects all resources from the icon toggle", async () => {
|
|
211
|
+
const selectResources = jest.fn();
|
|
212
|
+
const rendered = render(
|
|
213
|
+
<LineageForm
|
|
214
|
+
{...props}
|
|
215
|
+
resourceOptions={[
|
|
216
|
+
{ key: "res1", text: "res1", value: "res1" },
|
|
217
|
+
{ key: "res2", text: "res2", value: "res2" },
|
|
218
|
+
]}
|
|
219
|
+
selectResources={selectResources}
|
|
220
|
+
selectedResources={[]}
|
|
221
|
+
/>,
|
|
222
|
+
renderOpts,
|
|
223
|
+
);
|
|
224
|
+
await waitForLoad(rendered);
|
|
225
|
+
const user = userEvent.setup({ delay: null });
|
|
226
|
+
|
|
227
|
+
await user.click(
|
|
228
|
+
rendered.getByRole("button", { name: /lineage.resources.add_all/i }),
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
expect(selectResources).toHaveBeenCalledWith(["res1", "res2"]);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("clears all resources from the icon toggle", async () => {
|
|
235
|
+
const selectResources = jest.fn();
|
|
236
|
+
const rendered = render(
|
|
237
|
+
<LineageForm
|
|
238
|
+
{...props}
|
|
239
|
+
resourceOptions={[
|
|
240
|
+
{ key: "res1", text: "res1", value: "res1" },
|
|
241
|
+
{ key: "res2", text: "res2", value: "res2" },
|
|
242
|
+
]}
|
|
243
|
+
selectResources={selectResources}
|
|
244
|
+
selectedResources={["res1", "res2"]}
|
|
245
|
+
/>,
|
|
246
|
+
renderOpts,
|
|
247
|
+
);
|
|
248
|
+
await waitForLoad(rendered);
|
|
249
|
+
const user = userEvent.setup({ delay: null });
|
|
250
|
+
|
|
251
|
+
await user.click(
|
|
252
|
+
rendered.getByRole("button", { name: /lineage.resources.remove_all/i }),
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
expect(selectResources).toHaveBeenCalledWith([]);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it("selects the next single group option automatically", async () => {
|
|
259
|
+
const selectGroup = jest.fn();
|
|
260
|
+
render(
|
|
261
|
+
<LineageForm
|
|
262
|
+
{...props}
|
|
263
|
+
groupOptions={[[{ key: "grp1", text: "grp1", value: "grp1" }]]}
|
|
264
|
+
resourceOptions={[]}
|
|
265
|
+
selectGroup={selectGroup}
|
|
266
|
+
/>,
|
|
267
|
+
renderOpts,
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
await waitFor(() => {
|
|
271
|
+
expect(selectGroup).toHaveBeenCalledWith({
|
|
272
|
+
id: "grp1",
|
|
273
|
+
domain_id: null,
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it("does not skip a previous group dropdown with multiple options", async () => {
|
|
279
|
+
const selectGroup = jest.fn();
|
|
280
|
+
const rendered = render(
|
|
281
|
+
<LineageForm
|
|
282
|
+
{...props}
|
|
283
|
+
groupOptions={[
|
|
284
|
+
[
|
|
285
|
+
{ key: "grp1", text: "grp1", value: "grp1" },
|
|
286
|
+
{ key: "grp2", text: "grp2", value: "grp2" },
|
|
287
|
+
],
|
|
288
|
+
[{ key: "subgrp1", text: "subgrp1", value: "subgrp1" }],
|
|
289
|
+
]}
|
|
290
|
+
resourceOptions={[]}
|
|
291
|
+
selectGroup={selectGroup}
|
|
292
|
+
/>,
|
|
293
|
+
renderOpts,
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
await waitForLoad(rendered);
|
|
297
|
+
expect(selectGroup).not.toHaveBeenCalled();
|
|
298
|
+
});
|
|
299
|
+
|
|
71
300
|
it("handle submit action", async () => {
|
|
72
301
|
const selectedResources = ["id1", "id2"];
|
|
73
302
|
const createGraph = jest.fn();
|
|
303
|
+
const onGraphSubmit = jest.fn();
|
|
74
304
|
const rendered = render(
|
|
75
305
|
<LineageForm
|
|
76
306
|
{...props}
|
|
77
307
|
createGraph={createGraph}
|
|
308
|
+
onGraphSubmit={onGraphSubmit}
|
|
78
309
|
selectedResources={selectedResources}
|
|
79
310
|
/>,
|
|
80
311
|
renderOpts,
|
|
@@ -96,6 +327,72 @@ describe("<LineageForm />", () => {
|
|
|
96
327
|
levels: 4,
|
|
97
328
|
isRedirected: true,
|
|
98
329
|
});
|
|
330
|
+
expect(onGraphSubmit).toHaveBeenCalledTimes(1);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it("notifies graph submit when requesting impact", async () => {
|
|
334
|
+
const createGraph = jest.fn();
|
|
335
|
+
const onGraphSubmit = jest.fn();
|
|
336
|
+
const rendered = render(
|
|
337
|
+
<LineageForm
|
|
338
|
+
{...props}
|
|
339
|
+
createGraph={createGraph}
|
|
340
|
+
onGraphSubmit={onGraphSubmit}
|
|
341
|
+
selectedResources={["id1"]}
|
|
342
|
+
/>,
|
|
343
|
+
renderOpts,
|
|
344
|
+
);
|
|
345
|
+
await waitForLoad(rendered);
|
|
346
|
+
const user = userEvent.setup({ delay: null });
|
|
347
|
+
|
|
348
|
+
await user.click(
|
|
349
|
+
rendered.getByRole("button", {
|
|
350
|
+
name: /navigation.lineage.impact/i,
|
|
351
|
+
}),
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
expect(createGraph).toHaveBeenCalledWith({
|
|
355
|
+
ids: ["id1"],
|
|
356
|
+
type: "impact",
|
|
357
|
+
levels: 4,
|
|
358
|
+
isRedirected: true,
|
|
359
|
+
});
|
|
360
|
+
expect(onGraphSubmit).toHaveBeenCalledTimes(1);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it("clears the whole lineage form including the selected domain", async () => {
|
|
364
|
+
const clearNodes = jest.fn();
|
|
365
|
+
const fetchNodes = jest.fn();
|
|
366
|
+
const selectResources = jest.fn();
|
|
367
|
+
const rendered = render(
|
|
368
|
+
<LineageForm
|
|
369
|
+
{...props}
|
|
370
|
+
clearNodes={clearNodes}
|
|
371
|
+
fetchNodes={fetchNodes}
|
|
372
|
+
selectResources={selectResources}
|
|
373
|
+
selectedGroups={["grp1"]}
|
|
374
|
+
selectedResources={["res1"]}
|
|
375
|
+
/>,
|
|
376
|
+
renderOpts,
|
|
377
|
+
);
|
|
378
|
+
await waitForLoad(rendered);
|
|
379
|
+
const user = userEvent.setup({ delay: null });
|
|
380
|
+
|
|
381
|
+
await user.click(rendered.getByText(/foodomain/i));
|
|
382
|
+
await waitFor(() => {
|
|
383
|
+
expect(fetchNodes).toHaveBeenCalledWith({ domain_id: "1" });
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
await user.click(
|
|
387
|
+
rendered.getByRole("button", { name: /navigation.lineage.clean/i }),
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
expect(clearNodes).toHaveBeenCalledTimes(1);
|
|
391
|
+
expect(selectResources).toHaveBeenCalledWith([]);
|
|
392
|
+
expect(fetchNodes).not.toHaveBeenCalledWith({});
|
|
393
|
+
expect(
|
|
394
|
+
rendered.getByText("domain.selector.placeholder"),
|
|
395
|
+
).toBeInTheDocument();
|
|
99
396
|
});
|
|
100
397
|
|
|
101
398
|
it("calls clearNodes when component unmounts but not when it mounts", async () => {
|
|
@@ -119,4 +416,47 @@ describe("<LineageForm />", () => {
|
|
|
119
416
|
await user.click(rendered.getByRole("option", { name: /foodomain/i }));
|
|
120
417
|
expect(fetchNodes).toHaveBeenCalledWith({ domain_id: "1" });
|
|
121
418
|
});
|
|
419
|
+
|
|
420
|
+
it("loads nodes automatically when a single lineage domain is available", async () => {
|
|
421
|
+
const fetchNodes = jest.fn();
|
|
422
|
+
const rendered = render(
|
|
423
|
+
<LineageForm {...props} fetchNodes={fetchNodes} />,
|
|
424
|
+
{
|
|
425
|
+
mocks: [lineageDomainsMock([defaultDomains[0]])],
|
|
426
|
+
},
|
|
427
|
+
);
|
|
428
|
+
await waitForLoad(rendered);
|
|
429
|
+
|
|
430
|
+
await waitFor(() => {
|
|
431
|
+
expect(fetchNodes).toHaveBeenCalledWith({ domain_id: "1" });
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it("disables domains without lineage", async () => {
|
|
436
|
+
const fetchNodes = jest.fn();
|
|
437
|
+
const rendered = render(
|
|
438
|
+
<LineageForm
|
|
439
|
+
{...props}
|
|
440
|
+
domainAvailabilityChecker={jest.fn(async () => [
|
|
441
|
+
["1", true],
|
|
442
|
+
["2", false],
|
|
443
|
+
])}
|
|
444
|
+
fetchNodes={fetchNodes}
|
|
445
|
+
/>,
|
|
446
|
+
{
|
|
447
|
+
mocks: [lineageDomainsMock([defaultDomains[0], defaultDomains[1]])],
|
|
448
|
+
},
|
|
449
|
+
);
|
|
450
|
+
await waitForLoad(rendered);
|
|
451
|
+
const user = userEvent.setup({ delay: null });
|
|
452
|
+
|
|
453
|
+
await waitFor(() => {
|
|
454
|
+
expect(rendered.getByRole("option", { name: /bardomain/i })).toHaveClass(
|
|
455
|
+
"disabled",
|
|
456
|
+
);
|
|
457
|
+
});
|
|
458
|
+
await user.click(rendered.getByRole("option", { name: /bardomain/i }));
|
|
459
|
+
|
|
460
|
+
expect(fetchNodes).not.toHaveBeenCalledWith({ domain_id: "2" });
|
|
461
|
+
});
|
|
122
462
|
});
|