@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.
Files changed (52) hide show
  1. package/package.json +3 -3
  2. package/src/api.js +12 -0
  3. package/src/components/ImplementationSearchResults.js +24 -42
  4. package/src/components/ImplementationUploadJobBreadcrumbs.js +25 -0
  5. package/src/components/Implementations.js +31 -17
  6. package/src/components/ImplementationsRoutes.js +9 -0
  7. package/src/components/ImplementationsUploadButton.js +38 -50
  8. package/src/components/ImplementationsUploadJob.js +217 -0
  9. package/src/components/ImplementationsUploadJobs.js +128 -0
  10. package/src/components/RuleFormImplementations.js +29 -10
  11. package/src/components/RuleImplementationActions.js +10 -20
  12. package/src/components/RuleImplementationsActions.js +15 -37
  13. package/src/components/RuleImplementationsDownload.js +26 -31
  14. package/src/components/RuleImplementationsDownloadXlsx.js +47 -0
  15. package/src/components/RuleImplementationsLabelResults.js +30 -39
  16. package/src/components/RuleImplementationsOptions.js +5 -3
  17. package/src/components/RuleImplementationsTable.js +7 -3
  18. package/src/components/RuleRoutes.js +1 -4
  19. package/src/components/SimpleRuleImplementationsTable.js +68 -0
  20. package/src/components/__tests__/ImplementationSearchResults.spec.js +32 -4
  21. package/src/components/__tests__/ImplementationUploadJobBreadcrumbs.spec.js +28 -0
  22. package/src/components/__tests__/Implementations.spec.js +43 -0
  23. package/src/components/__tests__/ImplementationsUploadButton.spec.js +67 -40
  24. package/src/components/__tests__/ImplementationsUploadJob.spec.js +112 -0
  25. package/src/components/__tests__/ImplementationsUploadJobs.spec.js +60 -0
  26. package/src/components/__tests__/RuleImplementationsActions.spec.js +71 -56
  27. package/src/components/__tests__/RuleImplementationsOptions.spec.js +28 -3
  28. package/src/components/__tests__/RuleImplementationsTable.spec.js +24 -0
  29. package/src/components/__tests__/__snapshots__/ImplementationSearchResults.spec.js.snap +113 -46
  30. package/src/components/__tests__/__snapshots__/ImplementationUploadJobBreadcrumbs.spec.js.snap +42 -0
  31. package/src/components/__tests__/__snapshots__/Implementations.spec.js.snap +125 -24
  32. package/src/components/__tests__/__snapshots__/RuleImplementationsActions.spec.js.snap +4 -8
  33. package/src/components/__tests__/__snapshots__/RuleImplementationsOptions.spec.js.snap +5 -8
  34. package/src/components/__tests__/implementationsUploadJobParser.spec.js +105 -0
  35. package/src/components/implementationsUploadJobParser.js +276 -0
  36. package/src/components/index.js +0 -2
  37. package/src/hooks/useImplementations.js +80 -0
  38. package/src/reducers/index.js +2 -0
  39. package/src/reducers/ruleImplementationSelectedFilter.js +1 -1
  40. package/src/reducers/ruleImplementationsDownloadingXlsx.js +14 -0
  41. package/src/routines.js +3 -0
  42. package/src/sagas/downloadRuleImplementationsXlsx.js +52 -0
  43. package/src/sagas/index.js +3 -0
  44. package/src/components/RuleImplementationFilters.js +0 -25
  45. package/src/components/RuleImplementationSelectedFilters.js +0 -99
  46. package/src/components/RuleImplementationsFromRuleLoader.js +0 -60
  47. package/src/components/RuleImplementationsPagination.js +0 -18
  48. package/src/components/RuleImplementationsSearch.js +0 -39
  49. package/src/components/__tests__/RuleImplementationsFromRuleLoader.spec.js +0 -63
  50. package/src/components/__tests__/RuleImplementationsSearch.spec.js +0 -29
  51. package/src/components/__tests__/__snapshots__/RuleImplementationsFromRuleLoader.spec.js.snap +0 -3
  52. 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 props = {
23
- loading: false,
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
- describe.skip("<ImplementationsUploadButton />", () => {
7
- const uploadImplementationsMock = jest.fn();
8
- const props = {
9
- uploadImplementations: uploadImplementationsMock,
10
- loading: false,
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
- const user = userEvent.setup({ delay: null });
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", { name: /actions.upload.tooltip/i })
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: /uploadModal.accept.update/i,
69
+ name: /uploadmodal.accept.update/i,
41
70
  });
42
71
  expect(uploadButton).toBeDisabled();
43
72
  const publishButton = rendered.getByRole("button", {
44
- name: /uploadModal.accept.publish/i,
73
+ name: /uploadmodal.accept.publish/i,
45
74
  });
46
75
  expect(publishButton).toBeDisabled();
47
76
 
48
- expect(rendered.getByText(/actions.upload.tooltip/i)).toBeInTheDocument();
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
- const rendered = render(
56
- <ImplementationsUploadButton {...{ ...props, canAutoPublish: false }} />
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", { name: /actions.upload.tooltip/i })
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: /uploadModal.accept.update/i,
104
+ name: /uploadmodal.accept.update/i,
66
105
  });
67
106
  expect(updateButton).toBeDisabled();
68
107
 
69
108
  const publishButton = rendered.queryByRole("button", {
70
- name: /uploadModal.accept.publish/i,
109
+ name: /uploadmodal.accept.publish/i,
71
110
  });
72
111
  expect(publishButton).not.toBeInTheDocument();
73
112
 
74
- const fakeFile = new File(["implementations"], "implementations.csv", {
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).toHaveBeenCalledWith({
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", { name: /actions.upload.tooltip/i })
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: /uploadModal.accept.update/i,
147
+ name: /uploadmodal.accept.update/i,
115
148
  });
116
149
  expect(updateButton).toBeDisabled();
117
150
 
118
151
  const publishButton = rendered.getByRole("button", {
119
- name: /uploadModal.accept.publish/i,
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).toHaveBeenCalledWith({
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
+ });