@truedat/dq 7.11.0 → 7.11.2
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/api.js +12 -0
- package/src/components/ImplementationSearchResults.js +24 -42
- package/src/components/ImplementationUploadJobBreadcrumbs.js +25 -0
- package/src/components/Implementations.js +31 -17
- package/src/components/ImplementationsRoutes.js +9 -0
- package/src/components/ImplementationsUploadButton.js +38 -50
- package/src/components/ImplementationsUploadJob.js +217 -0
- package/src/components/ImplementationsUploadJobs.js +128 -0
- package/src/components/RuleFormImplementations.js +29 -10
- package/src/components/RuleImplementationActions.js +10 -20
- package/src/components/RuleImplementationsActions.js +15 -37
- package/src/components/RuleImplementationsDownload.js +26 -31
- package/src/components/RuleImplementationsDownloadXlsx.js +47 -0
- package/src/components/RuleImplementationsLabelResults.js +30 -39
- package/src/components/RuleImplementationsOptions.js +5 -3
- package/src/components/RuleImplementationsTable.js +7 -3
- package/src/components/RuleRoutes.js +1 -4
- package/src/components/SimpleRuleImplementationsTable.js +68 -0
- package/src/components/__tests__/ImplementationSearchResults.spec.js +32 -4
- package/src/components/__tests__/ImplementationUploadJobBreadcrumbs.spec.js +28 -0
- package/src/components/__tests__/Implementations.spec.js +43 -0
- package/src/components/__tests__/ImplementationsUploadButton.spec.js +67 -40
- package/src/components/__tests__/ImplementationsUploadJob.spec.js +112 -0
- package/src/components/__tests__/ImplementationsUploadJobs.spec.js +60 -0
- package/src/components/__tests__/RuleImplementationsActions.spec.js +71 -56
- package/src/components/__tests__/RuleImplementationsOptions.spec.js +28 -3
- package/src/components/__tests__/RuleImplementationsTable.spec.js +24 -0
- package/src/components/__tests__/__snapshots__/ImplementationSearchResults.spec.js.snap +113 -46
- package/src/components/__tests__/__snapshots__/ImplementationUploadJobBreadcrumbs.spec.js.snap +42 -0
- package/src/components/__tests__/__snapshots__/Implementations.spec.js.snap +125 -24
- package/src/components/__tests__/__snapshots__/RuleImplementationsActions.spec.js.snap +4 -8
- package/src/components/__tests__/__snapshots__/RuleImplementationsOptions.spec.js.snap +5 -8
- package/src/components/__tests__/implementationsUploadJobParser.spec.js +105 -0
- package/src/components/implementationsUploadJobParser.js +276 -0
- package/src/components/index.js +0 -2
- package/src/hooks/useImplementations.js +80 -0
- package/src/reducers/index.js +2 -0
- package/src/reducers/ruleImplementationSelectedFilter.js +1 -1
- package/src/reducers/ruleImplementationsDownloadingXlsx.js +14 -0
- package/src/routines.js +3 -0
- package/src/sagas/downloadRuleImplementationsXlsx.js +52 -0
- package/src/sagas/index.js +3 -0
- package/src/components/RuleImplementationFilters.js +0 -25
- package/src/components/RuleImplementationSelectedFilters.js +0 -99
- package/src/components/RuleImplementationsFromRuleLoader.js +0 -60
- package/src/components/RuleImplementationsPagination.js +0 -18
- package/src/components/RuleImplementationsSearch.js +0 -39
- package/src/components/__tests__/RuleImplementationsFromRuleLoader.spec.js +0 -63
- package/src/components/__tests__/RuleImplementationsSearch.spec.js +0 -29
- package/src/components/__tests__/__snapshots__/RuleImplementationsFromRuleLoader.spec.js.snap +0 -3
- package/src/components/__tests__/__snapshots__/RuleImplementationsSearch.spec.js.snap +0 -50
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { Table, Header, Icon } from "semantic-ui-react";
|
|
4
|
+
import { useIntl } from "react-intl";
|
|
5
|
+
import RuleImplementationRow from "./RuleImplementationRow";
|
|
6
|
+
|
|
7
|
+
export const SimpleRuleImplementationsTable = ({
|
|
8
|
+
ruleImplementations,
|
|
9
|
+
columns,
|
|
10
|
+
}) => {
|
|
11
|
+
const { formatMessage } = useIntl();
|
|
12
|
+
|
|
13
|
+
const validColumns = _.reject(
|
|
14
|
+
({ hideOn }) => _.isFunction(hideOn) && hideOn(ruleImplementations)
|
|
15
|
+
)(columns);
|
|
16
|
+
return (
|
|
17
|
+
<>
|
|
18
|
+
{!_.isEmpty(ruleImplementations) ? (
|
|
19
|
+
<div className="implementations-table-overflow">
|
|
20
|
+
<Table sortable>
|
|
21
|
+
<Table.Header>
|
|
22
|
+
<Table.Row>
|
|
23
|
+
{validColumns
|
|
24
|
+
? validColumns.map((column, key) => (
|
|
25
|
+
<Table.HeaderCell
|
|
26
|
+
key={key}
|
|
27
|
+
width={column.width}
|
|
28
|
+
content={formatMessage({
|
|
29
|
+
id: `ruleImplementations.props.${
|
|
30
|
+
column.header || column.name
|
|
31
|
+
}`,
|
|
32
|
+
})}
|
|
33
|
+
className="disabled"
|
|
34
|
+
/>
|
|
35
|
+
))
|
|
36
|
+
: null}
|
|
37
|
+
</Table.Row>
|
|
38
|
+
</Table.Header>
|
|
39
|
+
<Table.Body>
|
|
40
|
+
{ruleImplementations.map((r, i) => (
|
|
41
|
+
<RuleImplementationRow
|
|
42
|
+
key={i}
|
|
43
|
+
ruleImplementation={r}
|
|
44
|
+
columns={validColumns}
|
|
45
|
+
/>
|
|
46
|
+
))}
|
|
47
|
+
</Table.Body>
|
|
48
|
+
</Table>
|
|
49
|
+
</div>
|
|
50
|
+
) : null}
|
|
51
|
+
{_.isEmpty(ruleImplementations) ? (
|
|
52
|
+
<Header as="h4">
|
|
53
|
+
<Icon name="search" />
|
|
54
|
+
<Header.Content>
|
|
55
|
+
{formatMessage({ id: "ruleImplementations.search.results.empty" })}
|
|
56
|
+
</Header.Content>
|
|
57
|
+
</Header>
|
|
58
|
+
) : null}
|
|
59
|
+
</>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
SimpleRuleImplementationsTable.propTypes = {
|
|
64
|
+
ruleImplementations: PropTypes.array,
|
|
65
|
+
columns: PropTypes.array,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export default SimpleRuleImplementationsTable;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import userEvent from "@testing-library/user-event";
|
|
1
2
|
import { render, waitForLoad } from "@truedat/test/render";
|
|
3
|
+
import { useSearchContext } from "@truedat/core/search/SearchContext";
|
|
2
4
|
import { ImplementationSearchResults } from "../ImplementationSearchResults";
|
|
3
5
|
|
|
4
6
|
jest.mock("@truedat/core/hooks", () => ({
|
|
@@ -8,7 +10,29 @@ jest.mock("@truedat/core/hooks", () => ({
|
|
|
8
10
|
),
|
|
9
11
|
}));
|
|
10
12
|
|
|
13
|
+
jest.mock("@truedat/core/search/SearchContext", () => {
|
|
14
|
+
const originalModule = jest.requireActual(
|
|
15
|
+
"@truedat/core/search/SearchContext"
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
__esModule: true,
|
|
20
|
+
...originalModule,
|
|
21
|
+
useSearchContext: jest.fn(),
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
|
|
11
25
|
describe("<ImplementationSearchResults />", () => {
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
useSearchContext.mockReturnValue({
|
|
28
|
+
searchData: { data: [{ id: 1 }], _actions: { execute: {} } },
|
|
29
|
+
count: 1,
|
|
30
|
+
searchMust: {},
|
|
31
|
+
toggleHiddenFilterValue: jest.fn(),
|
|
32
|
+
setOnSearchChange: jest.fn(),
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
12
36
|
it("matches the latest snapshot", async () => {
|
|
13
37
|
const props = {
|
|
14
38
|
loading: false,
|
|
@@ -19,13 +43,17 @@ describe("<ImplementationSearchResults />", () => {
|
|
|
19
43
|
});
|
|
20
44
|
|
|
21
45
|
it("renders executions on when executionEnabled is true", async () => {
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
implementationQuery: { filters: { executable: [true] } },
|
|
25
|
-
};
|
|
46
|
+
const user = userEvent.setup({ delay: null });
|
|
47
|
+
const props = { loading: false };
|
|
26
48
|
const rendered = render(<ImplementationSearchResults {...props} />);
|
|
27
49
|
await waitForLoad(rendered);
|
|
28
50
|
|
|
51
|
+
const updatedCheckbox =
|
|
52
|
+
rendered.container.querySelector("#execute_checkbox");
|
|
53
|
+
|
|
54
|
+
await user.click(updatedCheckbox);
|
|
55
|
+
expect(updatedCheckbox).toBeChecked();
|
|
56
|
+
|
|
29
57
|
expect(rendered.container).toMatchSnapshot();
|
|
30
58
|
|
|
31
59
|
expect(
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { render, waitForLoad } from "@truedat/test/render";
|
|
2
|
+
import { ImplementationUploadJobBreadcrumbs } from "../ImplementationUploadJobBreadcrumbs";
|
|
3
|
+
|
|
4
|
+
describe("ImplementationUploadJobBreadcrumbs", () => {
|
|
5
|
+
it("renders breadcrumbs without filename", async () => {
|
|
6
|
+
const rendered = render(<ImplementationUploadJobBreadcrumbs />);
|
|
7
|
+
await waitForLoad(rendered);
|
|
8
|
+
|
|
9
|
+
expect(
|
|
10
|
+
rendered.getByText(/sidemenu.implementations_upload_jobs/i)
|
|
11
|
+
).toBeInTheDocument();
|
|
12
|
+
expect(rendered.container).toMatchSnapshot();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("renders breadcrumbs with filename", async () => {
|
|
16
|
+
const filename = "test.csv";
|
|
17
|
+
const rendered = render(
|
|
18
|
+
<ImplementationUploadJobBreadcrumbs filename={filename} />
|
|
19
|
+
);
|
|
20
|
+
await waitForLoad(rendered);
|
|
21
|
+
|
|
22
|
+
expect(
|
|
23
|
+
rendered.getByText(/sidemenu.implementations_upload_jobs/i)
|
|
24
|
+
).toBeInTheDocument();
|
|
25
|
+
expect(rendered.getByText(filename)).toBeInTheDocument();
|
|
26
|
+
expect(rendered.container).toMatchSnapshot();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { render, waitForLoad } from "@truedat/test/render";
|
|
2
2
|
import Implementations from "../Implementations";
|
|
3
3
|
|
|
4
|
+
jest.mock("@truedat/core/search/SearchContext", () => {
|
|
5
|
+
const originalModule = jest.requireActual(
|
|
6
|
+
"@truedat/core/search/SearchContext"
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
__esModule: true,
|
|
11
|
+
...originalModule,
|
|
12
|
+
useSearchContext: jest.fn(),
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const { useSearchContext } = require("@truedat/core/search/SearchContext");
|
|
17
|
+
|
|
4
18
|
const props = {
|
|
5
19
|
defaultFilters: { status: ["baz", "bar"] },
|
|
6
20
|
};
|
|
@@ -14,6 +28,35 @@ const renderOpts = {
|
|
|
14
28
|
};
|
|
15
29
|
|
|
16
30
|
describe("<Implementations />", () => {
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
useSearchContext.mockReturnValue({
|
|
33
|
+
searchData: {
|
|
34
|
+
data: [
|
|
35
|
+
{
|
|
36
|
+
deleted_at: null,
|
|
37
|
+
df_content: {},
|
|
38
|
+
df_name: "fooDomain",
|
|
39
|
+
domain_id: 1,
|
|
40
|
+
id: 1330,
|
|
41
|
+
implementation_ref: 1330,
|
|
42
|
+
implementation_key: "bar_impl",
|
|
43
|
+
implementation_type: "basic",
|
|
44
|
+
goal: 20,
|
|
45
|
+
minimum: 10,
|
|
46
|
+
result_type: "percentage",
|
|
47
|
+
results: [],
|
|
48
|
+
rule_id: null,
|
|
49
|
+
status: "draft",
|
|
50
|
+
version: 1,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
scroll_id: null,
|
|
54
|
+
},
|
|
55
|
+
searchMust: { status: ["pending"] },
|
|
56
|
+
setOnSearchChange: jest.fn(),
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
17
60
|
it("matches the latest snapshot", async () => {
|
|
18
61
|
const rendered = render(<Implementations {...props} />, renderOpts);
|
|
19
62
|
await waitForLoad(rendered);
|
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
import { waitFor, fireEvent } from "@testing-library/react";
|
|
2
2
|
import userEvent from "@testing-library/user-event";
|
|
3
3
|
import { render, waitForLoad } from "@truedat/test/render";
|
|
4
|
+
import { useSearchContext } from "@truedat/core/search/SearchContext";
|
|
5
|
+
|
|
6
|
+
import { useImplementationsUpload } from "../../hooks/useImplementations";
|
|
4
7
|
import { ImplementationsUploadButton } from "../ImplementationsUploadButton";
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
jest.mock("../../hooks/useImplementations", () => ({
|
|
10
|
+
useImplementationsUpload: jest.fn(),
|
|
11
|
+
}));
|
|
12
|
+
jest.mock("@truedat/core/search/SearchContext", () => {
|
|
13
|
+
const originalModule = jest.requireActual(
|
|
14
|
+
"@truedat/core/search/SearchContext"
|
|
15
|
+
);
|
|
16
|
+
return {
|
|
17
|
+
__esModule: true,
|
|
18
|
+
...originalModule,
|
|
19
|
+
useSearchContext: jest.fn(),
|
|
11
20
|
};
|
|
12
|
-
|
|
21
|
+
});
|
|
13
22
|
|
|
23
|
+
describe("<ImplementationsUploadButton />", () => {
|
|
24
|
+
const user = userEvent.setup({ delay: null });
|
|
25
|
+
const uploadImplementationsMock = jest.fn(() => ({
|
|
26
|
+
then: jest.fn(),
|
|
27
|
+
}));
|
|
14
28
|
// See https://react-dropzone.js.org/ "Testing" section
|
|
15
29
|
const mockData = (files) => {
|
|
16
30
|
return {
|
|
@@ -26,52 +40,77 @@ describe.skip("<ImplementationsUploadButton />", () => {
|
|
|
26
40
|
};
|
|
27
41
|
};
|
|
28
42
|
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
jest.clearAllMocks();
|
|
45
|
+
|
|
46
|
+
useImplementationsUpload.mockReturnValue({
|
|
47
|
+
trigger: uploadImplementationsMock,
|
|
48
|
+
});
|
|
49
|
+
useSearchContext.mockReturnValue({
|
|
50
|
+
searchData: {
|
|
51
|
+
_actions: {
|
|
52
|
+
autoPublish: true,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
29
58
|
it("shows the modal", async () => {
|
|
30
|
-
const rendered = render(
|
|
31
|
-
<ImplementationsUploadButton {...{ ...props, canAutoPublish: true }} />
|
|
32
|
-
);
|
|
59
|
+
const rendered = render(<ImplementationsUploadButton />);
|
|
33
60
|
await waitForLoad(rendered);
|
|
34
61
|
|
|
35
62
|
await user.click(
|
|
36
|
-
rendered.getByRole("option", {
|
|
63
|
+
rendered.getByRole("option", {
|
|
64
|
+
name: /ruleimplementations.actions.upload.tooltip/i,
|
|
65
|
+
})
|
|
37
66
|
);
|
|
38
67
|
|
|
39
68
|
const uploadButton = rendered.getByRole("button", {
|
|
40
|
-
name: /
|
|
69
|
+
name: /uploadmodal.accept.update/i,
|
|
41
70
|
});
|
|
42
71
|
expect(uploadButton).toBeDisabled();
|
|
43
72
|
const publishButton = rendered.getByRole("button", {
|
|
44
|
-
name: /
|
|
73
|
+
name: /uploadmodal.accept.publish/i,
|
|
45
74
|
});
|
|
46
75
|
expect(publishButton).toBeDisabled();
|
|
47
76
|
|
|
48
|
-
expect(
|
|
77
|
+
expect(
|
|
78
|
+
rendered.getByText(/ruleimplementations.actions.upload.tooltip/i)
|
|
79
|
+
).toBeInTheDocument();
|
|
49
80
|
expect(
|
|
50
81
|
rendered.getByText(/uploadModal.actions.upload.confirmation.content/i)
|
|
51
82
|
).toBeInTheDocument();
|
|
52
83
|
});
|
|
53
84
|
|
|
54
85
|
it("false canAutoPublish makes the modal not show the publish button; update using an implementations CSV", async () => {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
86
|
+
useSearchContext.mockReturnValue({
|
|
87
|
+
searchData: {
|
|
88
|
+
_actions: {
|
|
89
|
+
autoPublish: false,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const rendered = render(<ImplementationsUploadButton />);
|
|
58
95
|
await waitForLoad(rendered);
|
|
59
96
|
|
|
60
97
|
await user.click(
|
|
61
|
-
rendered.getByRole("option", {
|
|
98
|
+
rendered.getByRole("option", {
|
|
99
|
+
name: /ruleimplementations.actions.upload.tooltip/i,
|
|
100
|
+
})
|
|
62
101
|
);
|
|
63
102
|
|
|
64
103
|
const updateButton = rendered.getByRole("button", {
|
|
65
|
-
name: /
|
|
104
|
+
name: /uploadmodal.accept.update/i,
|
|
66
105
|
});
|
|
67
106
|
expect(updateButton).toBeDisabled();
|
|
68
107
|
|
|
69
108
|
const publishButton = rendered.queryByRole("button", {
|
|
70
|
-
name: /
|
|
109
|
+
name: /uploadmodal.accept.publish/i,
|
|
71
110
|
});
|
|
72
111
|
expect(publishButton).not.toBeInTheDocument();
|
|
73
112
|
|
|
74
|
-
const fakeFile = new File(["implementations"], "implementations.
|
|
113
|
+
const fakeFile = new File(["implementations"], "implementations.xslx", {
|
|
75
114
|
type: "text/csv",
|
|
76
115
|
});
|
|
77
116
|
const formData = new FormData();
|
|
@@ -91,32 +130,26 @@ describe.skip("<ImplementationsUploadButton />", () => {
|
|
|
91
130
|
|
|
92
131
|
await user.click(updateButton);
|
|
93
132
|
|
|
94
|
-
expect(uploadImplementationsMock).
|
|
95
|
-
action: "upload",
|
|
96
|
-
formData,
|
|
97
|
-
lang: "en",
|
|
98
|
-
href: "/api/rule_implementations/upload",
|
|
99
|
-
method: "POST",
|
|
100
|
-
});
|
|
133
|
+
expect(uploadImplementationsMock).toHaveBeenCalled();
|
|
101
134
|
});
|
|
102
135
|
|
|
103
136
|
it("true canAutoPublish makes the modal show the publish button; publishing an implementations CSV puts auto_publish FormData to true", async () => {
|
|
104
|
-
const rendered = render(
|
|
105
|
-
<ImplementationsUploadButton {...{ ...props, canAutoPublish: true }} />
|
|
106
|
-
);
|
|
137
|
+
const rendered = render(<ImplementationsUploadButton />);
|
|
107
138
|
await waitForLoad(rendered);
|
|
108
139
|
|
|
109
140
|
await user.click(
|
|
110
|
-
rendered.getByRole("option", {
|
|
141
|
+
rendered.getByRole("option", {
|
|
142
|
+
name: /ruleimplementations.actions.upload.tooltip/i,
|
|
143
|
+
})
|
|
111
144
|
);
|
|
112
145
|
|
|
113
146
|
const updateButton = rendered.getByRole("button", {
|
|
114
|
-
name: /
|
|
147
|
+
name: /uploadmodal.accept.update/i,
|
|
115
148
|
});
|
|
116
149
|
expect(updateButton).toBeDisabled();
|
|
117
150
|
|
|
118
151
|
const publishButton = rendered.getByRole("button", {
|
|
119
|
-
name: /
|
|
152
|
+
name: /uploadmodal.accept.publish/i,
|
|
120
153
|
});
|
|
121
154
|
expect(updateButton).toBeDisabled();
|
|
122
155
|
|
|
@@ -142,12 +175,6 @@ describe.skip("<ImplementationsUploadButton />", () => {
|
|
|
142
175
|
|
|
143
176
|
await user.click(publishButton);
|
|
144
177
|
|
|
145
|
-
expect(uploadImplementationsMock).
|
|
146
|
-
action: "upload",
|
|
147
|
-
formData,
|
|
148
|
-
lang: "en",
|
|
149
|
-
href: "/api/rule_implementations/upload",
|
|
150
|
-
method: "POST",
|
|
151
|
-
});
|
|
178
|
+
expect(uploadImplementationsMock).toHaveBeenCalled();
|
|
152
179
|
});
|
|
153
180
|
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { render, waitForLoad } from "@truedat/test/render";
|
|
2
|
+
import userEvent from "@testing-library/user-event";
|
|
3
|
+
import { waitFor } from "@testing-library/react";
|
|
4
|
+
|
|
5
|
+
import { useImplementationsUploadJob } from "../../hooks/useImplementations";
|
|
6
|
+
import ImplementationsUploadJob from "../ImplementationsUploadJob";
|
|
7
|
+
|
|
8
|
+
jest.mock("../../hooks/useImplementations", () => ({
|
|
9
|
+
useImplementationsUploadJob: jest.fn(),
|
|
10
|
+
}));
|
|
11
|
+
jest.mock("react-router", () => ({
|
|
12
|
+
...jest.requireActual("react-router"),
|
|
13
|
+
useParams: () => ({ id: "123" }),
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
describe("<ImplementationsUploadJob />", () => {
|
|
17
|
+
const user = userEvent.setup({ delay: null });
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
useImplementationsUploadJob.mockReset();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("renders loading state", async () => {
|
|
24
|
+
useImplementationsUploadJob.mockReturnValue({
|
|
25
|
+
loading: true,
|
|
26
|
+
data: null,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const rendered = render(<ImplementationsUploadJob />);
|
|
30
|
+
|
|
31
|
+
expect(rendered.container.querySelector(".ui.loader")).toBeInTheDocument();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("renders empty state when no events", async () => {
|
|
35
|
+
useImplementationsUploadJob.mockReturnValue({
|
|
36
|
+
loading: false,
|
|
37
|
+
data: {
|
|
38
|
+
data: {
|
|
39
|
+
filename: "test.xlsx",
|
|
40
|
+
hash: "abc123",
|
|
41
|
+
latest_status: "COMPLETED",
|
|
42
|
+
latest_event_at: "2023-01-01T00:00:00Z",
|
|
43
|
+
events: [],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const rendered = render(<ImplementationsUploadJob />);
|
|
49
|
+
await waitForLoad(rendered);
|
|
50
|
+
|
|
51
|
+
expect(rendered.getAllByText(/test.xlsx/i)).toHaveLength(2);
|
|
52
|
+
expect(rendered.getByText(/abc123/i)).toBeInTheDocument();
|
|
53
|
+
expect(rendered.getByText(/no events found/i)).toBeInTheDocument();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("renders events grouped by status", async () => {
|
|
57
|
+
useImplementationsUploadJob.mockReturnValue({
|
|
58
|
+
loading: false,
|
|
59
|
+
data: {
|
|
60
|
+
data: {
|
|
61
|
+
filename: "test.xlsx",
|
|
62
|
+
hash: "abc123",
|
|
63
|
+
latest_status: "COMPLETED",
|
|
64
|
+
latest_event_at: "2023-01-01T00:00:00Z",
|
|
65
|
+
events: [
|
|
66
|
+
{
|
|
67
|
+
status: "INFO",
|
|
68
|
+
inserted_at: "2023-01-01T00:00:00Z",
|
|
69
|
+
response: { type: "info_message" },
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
status: "ERROR",
|
|
73
|
+
inserted_at: "2023-01-01T00:00:00Z",
|
|
74
|
+
response: { type: "error_message" },
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
status: "COMPLETED",
|
|
78
|
+
inserted_at: "2023-01-01T00:00:00Z",
|
|
79
|
+
response: { type: "completed_message" },
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const rendered = render(<ImplementationsUploadJob />);
|
|
87
|
+
await waitForLoad(rendered);
|
|
88
|
+
|
|
89
|
+
// Check group headers exist
|
|
90
|
+
expect(rendered.getByText(/info \(1\)/i)).toBeInTheDocument();
|
|
91
|
+
expect(rendered.getByText(/error \(1\)/i)).toBeInTheDocument();
|
|
92
|
+
|
|
93
|
+
// Expand INFO group
|
|
94
|
+
await user.click(rendered.getByText(/info \(1\)/i));
|
|
95
|
+
await waitFor(() => {
|
|
96
|
+
expect(rendered.getByText(/info_message/i)).toBeInTheDocument();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Expand ERROR group
|
|
100
|
+
await user.click(rendered.getByText(/error \(1\)/i));
|
|
101
|
+
await waitFor(() => {
|
|
102
|
+
expect(rendered.getByText(/error_message/i)).toBeInTheDocument();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// COMPLETED events are always visible
|
|
106
|
+
expect(
|
|
107
|
+
rendered.getAllByText(
|
|
108
|
+
/implementations.bulkUpload.event.status.COMPLETED/i
|
|
109
|
+
)
|
|
110
|
+
).toHaveLength(2);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { render, waitForLoad } from "@truedat/test/render";
|
|
2
|
+
import { useImplementationsUploadJobs } from "../../hooks/useImplementations";
|
|
3
|
+
import ImplementationsUploadJobs from "../ImplementationsUploadJobs";
|
|
4
|
+
|
|
5
|
+
jest.mock("../../hooks/useImplementations", () => ({
|
|
6
|
+
useImplementationsUploadJobs: jest.fn(),
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
describe("<ImplementationsUploadJobs />", () => {
|
|
10
|
+
it("renders loading state", async () => {
|
|
11
|
+
useImplementationsUploadJobs.mockReturnValue({
|
|
12
|
+
loading: true,
|
|
13
|
+
data: null,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const rendered = render(<ImplementationsUploadJobs />);
|
|
17
|
+
|
|
18
|
+
expect(rendered.container.querySelector(".ui.loader")).toBeInTheDocument();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("renders empty state", async () => {
|
|
22
|
+
useImplementationsUploadJobs.mockReturnValue({
|
|
23
|
+
loading: false,
|
|
24
|
+
data: {
|
|
25
|
+
data: [],
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const rendered = render(<ImplementationsUploadJobs />);
|
|
30
|
+
await waitForLoad(rendered);
|
|
31
|
+
|
|
32
|
+
expect(rendered.getByText(/No jobs found./i)).toBeInTheDocument();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("renders jobs list", async () => {
|
|
36
|
+
const mockJobs = [
|
|
37
|
+
{
|
|
38
|
+
id: 1,
|
|
39
|
+
filename: "test.csv",
|
|
40
|
+
latest_status: "completed",
|
|
41
|
+
latest_event_response: "Success",
|
|
42
|
+
latest_event_at: "2023-01-01T00:00:00Z",
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
useImplementationsUploadJobs.mockReturnValue({
|
|
47
|
+
loading: false,
|
|
48
|
+
data: {
|
|
49
|
+
data: mockJobs,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const rendered = render(<ImplementationsUploadJobs />);
|
|
54
|
+
await waitForLoad(rendered);
|
|
55
|
+
|
|
56
|
+
expect(rendered.getByText(/test.csv/i)).toBeInTheDocument();
|
|
57
|
+
expect(rendered.getByText(/completed/i)).toBeInTheDocument();
|
|
58
|
+
expect(rendered.getByText(/success/i)).toBeInTheDocument();
|
|
59
|
+
});
|
|
60
|
+
});
|