@truedat/bg 7.10.3 → 7.11.0

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 (33) hide show
  1. package/package.json +3 -3
  2. package/src/concepts/api.js +2 -0
  3. package/src/concepts/components/ConceptLinksUploadButton.js +0 -4
  4. package/src/concepts/components/ConceptRoutes.js +28 -46
  5. package/src/concepts/components/ConceptSuggestions.js +71 -0
  6. package/src/concepts/components/__tests__/ConceptRoutes.spec.js +201 -0
  7. package/src/concepts/components/__tests__/ConceptSuggestions.spec.js +74 -0
  8. package/src/concepts/components/__tests__/__snapshots__/ConceptRoutes.spec.js.snap +165 -0
  9. package/src/concepts/hooks/useConcepts.js +7 -0
  10. package/src/concepts/relations/api.js +9 -1
  11. package/src/concepts/relations/components/ConceptLinksApprovalResults.js +91 -0
  12. package/src/concepts/relations/components/ConceptLinksApprovals.js +225 -0
  13. package/src/concepts/relations/components/ConceptLinksApprovalsLabelResults.js +42 -0
  14. package/src/concepts/relations/components/ConceptLinksApprovalsRow.js +43 -0
  15. package/src/concepts/relations/components/ConceptLinksApprovalsTable.js +104 -0
  16. package/src/concepts/relations/components/ConceptSelector.js +117 -75
  17. package/src/concepts/relations/components/__tests__/ConceptLinksApprovalResults.spec.js +123 -0
  18. package/src/concepts/relations/components/__tests__/ConceptLinksApprovals.spec.js +77 -0
  19. package/src/concepts/relations/components/__tests__/ConceptLinksApprovalsLabelResults.spec.js +47 -0
  20. package/src/concepts/relations/components/__tests__/ConceptLinksApprovalsRow.spec.js +68 -0
  21. package/src/concepts/relations/components/__tests__/ConceptLinksApprovalsTable.spec.js +107 -0
  22. package/src/concepts/relations/components/__tests__/ConceptSelector.spec.js +90 -1
  23. package/src/concepts/relations/components/__tests__/__snapshots__/ConceptLinksApprovalResults.spec.js.snap +217 -0
  24. package/src/concepts/relations/components/__tests__/__snapshots__/ConceptLinksApprovals.spec.js.snap +559 -0
  25. package/src/concepts/relations/components/__tests__/__snapshots__/ConceptLinksApprovalsLabelResults.spec.js.snap +34 -0
  26. package/src/concepts/relations/components/__tests__/__snapshots__/ConceptLinksApprovalsRow.spec.js.snap +47 -0
  27. package/src/concepts/relations/components/__tests__/__snapshots__/ConceptLinksApprovalsTable.spec.js.snap +132 -0
  28. package/src/concepts/relations/components/__tests__/__snapshots__/ConceptSelector.spec.js.snap +99 -0
  29. package/src/concepts/relations/hooks/useLinks.js +25 -0
  30. package/src/concepts/relations/sagas/linkConcept.js +1 -0
  31. package/src/concepts/relations/selectors/getLinksSearchColumns.js +106 -0
  32. package/src/concepts/relations/selectors/index.js +2 -0
  33. package/src/concepts/relations/styles/ConceptLinksApprovals.less +15 -0
@@ -1,14 +1,7 @@
1
1
  import _ from "lodash/fp";
2
2
  import PropTypes from "prop-types";
3
3
  import { connect } from "react-redux";
4
- import {
5
- Button,
6
- Table,
7
- Message,
8
- Label,
9
- Icon,
10
- Segment,
11
- } from "semantic-ui-react";
4
+ import { Button, Table, Message, Label, Segment } from "semantic-ui-react";
12
5
  import { FormattedMessage, useIntl } from "react-intl";
13
6
  import SearchWidget from "@truedat/core/search/SearchWidget";
14
7
  import {
@@ -44,6 +37,7 @@ const ConceptSelectorRow = ({
44
37
  onClick,
45
38
  disabled,
46
39
  positive,
40
+ extraColumns = [],
47
41
  }) => {
48
42
  const { name, status, domain } = concept;
49
43
  return (
@@ -65,6 +59,12 @@ const ConceptSelectorRow = ({
65
59
  </Label>
66
60
  }
67
61
  />
62
+ {extraColumns.map((column, key) => (
63
+ <Table.Cell
64
+ key={key}
65
+ content={column.fieldDecorator(column.fieldSelector(concept))}
66
+ />
67
+ ))}
68
68
  </Table.Row>
69
69
  );
70
70
  };
@@ -77,20 +77,14 @@ ConceptSelectorRow.propTypes = {
77
77
  positive: PropTypes.bool,
78
78
  };
79
79
 
80
- export function ConceptSelectorContent({
80
+ export const ConceptSelectorTable = ({
81
81
  businessConceptId,
82
- handleConceptSelected,
82
+ concepts,
83
83
  selectedConcept,
84
- showTitle = true,
84
+ handleConceptSelected,
85
85
  links,
86
- }) {
87
- const { searchData, filterParams: searchParams } = useSearchContext();
88
- const { trigger: triggerDownload, isMutating: downloading } =
89
- useConceptLinksDownload();
90
- const { formatMessage } = useIntl();
91
- const concepts = searchData?.data;
92
- const conceptsActions = _.propOr({}, "_actions")(searchData);
93
-
86
+ extraColumns = [],
87
+ }) => {
94
88
  const selectedConceptIsFiltered = !_.reduce(
95
89
  (acc, c) => (selectedConcept && c.id == selectedConcept.id) || acc,
96
90
  false
@@ -104,7 +98,85 @@ export function ConceptSelectorContent({
104
98
  )(concept)
105
99
  : false;
106
100
  };
107
-
101
+
102
+ return !_.isEmpty(concepts) || selectedConcept ? (
103
+ <Table selectable size="small">
104
+ <Table.Header>
105
+ <Table.Row>
106
+ <Table.HeaderCell
107
+ content={<FormattedMessage id="concepts.props.name" />}
108
+ />
109
+ <Table.HeaderCell
110
+ content={<FormattedMessage id="concepts.props.domain" />}
111
+ />
112
+ <Table.HeaderCell
113
+ content={<FormattedMessage id="concepts.props.status" />}
114
+ />
115
+ {extraColumns.map((column, key) => (
116
+ <Table.HeaderCell
117
+ key={key}
118
+ content={
119
+ <FormattedMessage id={`concepts.props.${column.name}`} />
120
+ }
121
+ />
122
+ ))}
123
+ </Table.Row>
124
+ </Table.Header>
125
+ <Table.Body>
126
+ {concepts.map((s, i) => (
127
+ <ConceptSelectorRow
128
+ disabled={
129
+ businessConceptId == s.business_concept_id || isDisabled(s)
130
+ }
131
+ key={i}
132
+ concept={s}
133
+ active={selectedConcept && selectedConcept.id == s.id}
134
+ onClick={handleConceptSelected}
135
+ positive={isPositive(
136
+ links,
137
+ s.business_concept_id,
138
+ businessConceptId
139
+ )}
140
+ extraColumns={extraColumns}
141
+ />
142
+ ))}
143
+ {selectedConcept && selectedConceptIsFiltered && (
144
+ <ConceptSelectorRow
145
+ concept={selectedConcept}
146
+ extraColumns={extraColumns}
147
+ active
148
+ />
149
+ )}
150
+ </Table.Body>
151
+ </Table>
152
+ ) : (
153
+ <Message header={<FormattedMessage id="concepts.search.results.empty" />} />
154
+ );
155
+ };
156
+
157
+ ConceptSelectorTable.propTypes = {
158
+ businessConceptId: PropTypes.number,
159
+ concepts: PropTypes.array,
160
+ selectedConcept: PropTypes.object,
161
+ handleConceptSelected: PropTypes.func,
162
+ links: PropTypes.array,
163
+ extraColumns: PropTypes.array,
164
+ };
165
+
166
+ export function ConceptSelectorContent({
167
+ businessConceptId,
168
+ handleConceptSelected,
169
+ selectedConcept,
170
+ showTitle = true,
171
+ links,
172
+ }) {
173
+ const { formatMessage } = useIntl();
174
+ const { searchData, filterParams: searchParams } = useSearchContext();
175
+ const { trigger: triggerDownload, isMutating: downloading } =
176
+ useConceptLinksDownload();
177
+ const concepts = searchData?.data;
178
+ const conceptsActions = _.propOr({}, "_actions")(searchData);
179
+
108
180
  return (
109
181
  <>
110
182
  {showTitle && (
@@ -113,64 +185,34 @@ export function ConceptSelectorContent({
113
185
  </label>
114
186
  )}
115
187
  <Segment>
116
- {conceptsActions?.downloadLinks && (
117
- <>
118
- <Button
119
- icon="download"
120
- floated="right"
121
- secondary
122
- loading={downloading}
123
- onClick={() => triggerDownload(searchParams)}
124
- data-tooltip={formatMessage({
125
- id: "concepts.actions.downloadLinks.tooltip",
126
- })}
127
- />
188
+ {conceptsActions?.downloadLinks && (
189
+ <>
190
+ <Button
191
+ icon="download"
192
+ floated="right"
193
+ secondary
194
+ loading={downloading}
195
+ onClick={() => triggerDownload(searchParams)}
196
+ data-tooltip={formatMessage({
197
+ id: "concepts.actions.downloadLinks.tooltip",
198
+ })}
199
+ />
128
200
  <ConceptLinksUploadButton />
129
- </>
201
+ </>
130
202
  )}
131
203
  <SearchWidget />
132
- {!_.isEmpty(concepts) || selectedConcept ? (
133
- <Table selectable size="small">
134
- <Table.Header>
135
- <Table.Row>
136
- <Table.HeaderCell
137
- content={<FormattedMessage id="concepts.props.name" />}
138
- />
139
- <Table.HeaderCell
140
- content={<FormattedMessage id="concepts.props.domain" />}
141
- />
142
- <Table.HeaderCell
143
- content={<FormattedMessage id="concepts.props.status" />}
144
- />
145
- </Table.Row>
146
- </Table.Header>
147
- <Table.Body>
148
- {concepts.map((s, i) => (
149
- <ConceptSelectorRow
150
- disabled={
151
- businessConceptId == s.business_concept_id || isDisabled(s)
152
- }
153
- key={i}
154
- concept={s}
155
- active={selectedConcept && selectedConcept.id == s.id}
156
- onClick={handleConceptSelected}
157
- positive={isPositive(
158
- links,
159
- s.business_concept_id,
160
- businessConceptId
161
- )}
162
- />
163
- ))}
164
- {selectedConcept && selectedConceptIsFiltered && (
165
- <ConceptSelectorRow concept={selectedConcept} active />
166
- )}
167
- </Table.Body>
168
- </Table>
169
- ) : (
170
- <Message
171
- header={<FormattedMessage id="concepts.search.results.empty" />}
172
- />
173
- )}
204
+ <ConceptSelectorTable
205
+ concepts={concepts}
206
+ showTitle={showTitle}
207
+ downloading={downloading}
208
+ selectedConcept={selectedConcept}
209
+ handleConceptSelected={handleConceptSelected}
210
+ links={links}
211
+ businessConceptId={businessConceptId}
212
+ triggerDownload={triggerDownload}
213
+ downloadLinks={conceptsActions?.downloadLinks}
214
+ searchParams={searchParams}
215
+ />
174
216
  <ConceptsPagination size="small" />
175
217
  </Segment>
176
218
  </>
@@ -0,0 +1,123 @@
1
+ import { render, waitForLoad } from "@truedat/test/render";
2
+ import LinksApprovalResults from "../ConceptLinksApprovalResults";
3
+ import { useLocation } from "react-router";
4
+
5
+ jest.mock("react-router", () => {
6
+ const actual = jest.requireActual("react-router");
7
+ return {
8
+ ...actual,
9
+ useLocation: jest.fn(),
10
+ };
11
+ });
12
+
13
+ const mockFormatMessage = jest.fn(({ id }) => id);
14
+ jest.mock("react-intl", () => ({
15
+ ...jest.requireActual("react-intl"),
16
+ useIntl: () => ({
17
+ formatMessage: mockFormatMessage,
18
+ }),
19
+ }));
20
+
21
+ describe("<LinksApprovalResults />", () => {
22
+ beforeEach(() => {
23
+ jest.clearAllMocks();
24
+ });
25
+
26
+ it("renders approval results with relations and errors", async () => {
27
+ useLocation.mockReturnValue({
28
+ state: {
29
+ status: "approved",
30
+ relations: [
31
+ {
32
+ id: 1,
33
+ source_id: 10,
34
+ source_name: "Source 1",
35
+ target_id: 20,
36
+ target_name: "Target 1",
37
+ },
38
+ ],
39
+ errors: {
40
+ permissions: {
41
+ message: "forbidden",
42
+ reason: "permissions",
43
+ relations: [
44
+ {
45
+ id: 2,
46
+ source_id: 11,
47
+ source_name: "Source 2",
48
+ target_id: 21,
49
+ target_name: "Target 2",
50
+ },
51
+ ],
52
+ },
53
+ },
54
+ },
55
+ });
56
+
57
+ const rendered = render(<LinksApprovalResults />);
58
+ await waitForLoad(rendered);
59
+
60
+ expect(rendered.container).toMatchSnapshot();
61
+ });
62
+
63
+ it("renders rejection results", async () => {
64
+ useLocation.mockReturnValue({
65
+ state: {
66
+ status: "rejected",
67
+ relations: [
68
+ {
69
+ id: 3,
70
+ source_id: 12,
71
+ source_name: "Source 3",
72
+ target_id: 22,
73
+ target_name: "Target 3",
74
+ },
75
+ ],
76
+ errors: {},
77
+ },
78
+ });
79
+
80
+ const rendered = render(<LinksApprovalResults />);
81
+ await waitForLoad(rendered);
82
+
83
+ expect(rendered.container).toMatchSnapshot();
84
+ });
85
+
86
+ it("renders with no errors", async () => {
87
+ useLocation.mockReturnValue({
88
+ state: {
89
+ status: "approved",
90
+ relations: [
91
+ {
92
+ id: 4,
93
+ source_id: 13,
94
+ source_name: "Source 4",
95
+ target_id: 23,
96
+ target_name: "Target 4",
97
+ },
98
+ ],
99
+ errors: {},
100
+ },
101
+ });
102
+
103
+ const rendered = render(<LinksApprovalResults />);
104
+ await waitForLoad(rendered);
105
+
106
+ expect(rendered.container).toMatchSnapshot();
107
+ });
108
+
109
+ it("renders with empty relations and errors", async () => {
110
+ useLocation.mockReturnValue({
111
+ state: {
112
+ status: "approved",
113
+ relations: [],
114
+ errors: {},
115
+ },
116
+ });
117
+
118
+ const rendered = render(<LinksApprovalResults />);
119
+ await waitForLoad(rendered);
120
+
121
+ expect(rendered.container).toMatchSnapshot();
122
+ });
123
+ });
@@ -0,0 +1,77 @@
1
+ import { render, waitForLoad } from "@truedat/test/render";
2
+ import { useSearchContext } from "@truedat/core/search/SearchContext";
3
+ import { ConceptLinksApprovals } from "../ConceptLinksApprovals";
4
+
5
+ jest.mock("@truedat/core/search/SearchContext", () => {
6
+ const originalModule = jest.requireActual(
7
+ "@truedat/core/search/SearchContext"
8
+ );
9
+
10
+ return {
11
+ __esModule: true,
12
+ ...originalModule,
13
+ useSearchContext: jest.fn(),
14
+ };
15
+ });
16
+
17
+ describe("<ConceptLinksApprovals />", () => {
18
+ it("matches the latest snapshot", async () => {
19
+ useSearchContext.mockReturnValue({
20
+ searchData: {
21
+ data: [
22
+ {
23
+ domain_ids: [2],
24
+ id: 1,
25
+ origin: null,
26
+ source_domain_ids: [2],
27
+ source_id: 11,
28
+ source_name: "Busines 11",
29
+ source_type: "business_concept",
30
+ status: "pending",
31
+ target_domain_ids: [2],
32
+ target_id: 21,
33
+ target_name: "Structure 21",
34
+ target_type: "data_structure",
35
+ updated_at: "2025-08-11T07:07:13.336631Z",
36
+ },
37
+ {
38
+ domain_ids: [2, 1],
39
+ id: 2,
40
+ origin: null,
41
+ source_domain_ids: [2],
42
+ source_id: 21,
43
+ source_name: "Busines 21",
44
+ source_type: "business_concept",
45
+ status: "pending",
46
+ target_domain_ids: [1],
47
+ target_id: 22,
48
+ target_name: "Structure 22",
49
+ target_type: "data_structure",
50
+ updated_at: "2025-08-11T07:07:13.336631Z",
51
+ },
52
+ ],
53
+ scroll_id: null,
54
+ },
55
+ searchMust: { status: ["pending"] },
56
+ setOnSearchChange: jest.fn(),
57
+ });
58
+ const rendered = render(<ConceptLinksApprovals />);
59
+
60
+ await waitForLoad(rendered);
61
+
62
+ expect(rendered.container).toMatchSnapshot();
63
+ });
64
+
65
+ it("matches the latest snapshot for empty results", async () => {
66
+ useSearchContext.mockReturnValue({
67
+ searchData: [],
68
+ searchMust: { status: ["pending"] },
69
+ setOnSearchChange: jest.fn(),
70
+ });
71
+ const rendered = render(<ConceptLinksApprovals />);
72
+
73
+ await waitForLoad(rendered);
74
+
75
+ expect(rendered.container).toMatchSnapshot();
76
+ });
77
+ });
@@ -0,0 +1,47 @@
1
+ import { render, waitForLoad } from "@truedat/test/render";
2
+ import { useSearchContext } from "@truedat/core/search/SearchContext";
3
+ import { ConceptLinksApprovalsLabelResults } from "../ConceptLinksApprovalsLabelResults";
4
+
5
+ jest.mock("@truedat/core/search/SearchContext", () => {
6
+ const originalModule = jest.requireActual(
7
+ "@truedat/core/search/SearchContext"
8
+ );
9
+
10
+ return {
11
+ __esModule: true,
12
+ ...originalModule,
13
+ useSearchContext: jest.fn(),
14
+ };
15
+ });
16
+
17
+ describe("ConceptLinksApprovalsLabelResults", () => {
18
+ it("matches the latest snapshot", async () => {
19
+ useSearchContext.mockReturnValue({
20
+ count: 1,
21
+ loading: false,
22
+ });
23
+
24
+ const props = {
25
+ selectedCount: 1,
26
+ approveView: true,
27
+ };
28
+ const rendered = render(<ConceptLinksApprovalsLabelResults {...props} />);
29
+ await waitForLoad(rendered);
30
+ rendered.debug();
31
+ expect(rendered.container).toMatchSnapshot();
32
+ });
33
+
34
+ it("should not render results count when is loading", async () => {
35
+ useSearchContext.mockReturnValue({
36
+ count: 1,
37
+ loading: true,
38
+ });
39
+ const props = {
40
+ selectedCount: 1,
41
+ approveView: true,
42
+ };
43
+ const rendered = render(<ConceptLinksApprovalsLabelResults {...props} />);
44
+ await waitForLoad(rendered);
45
+ expect(rendered.container).toMatchSnapshot();
46
+ });
47
+ });
@@ -0,0 +1,68 @@
1
+ import { render, waitForLoad } from "@truedat/test/render";
2
+ import { ConceptLinksApprovalsRow } from "../ConceptLinksApprovalsRow";
3
+
4
+ describe("ConceptLinksApprovalsRow", () => {
5
+ const defaultProps = {
6
+ checked: false,
7
+ columns: [
8
+ {
9
+ key: "name",
10
+ textAlign: "left",
11
+ },
12
+ ],
13
+ onCheckboxChange: jest.fn(),
14
+ link: {
15
+ id: "123",
16
+ name: "Test Link",
17
+ },
18
+ approveView: false,
19
+ };
20
+
21
+ it("renders null when columns are empty", async () => {
22
+ const rendered = render(
23
+ <ConceptLinksApprovalsRow {...defaultProps} columns={[]} />
24
+ );
25
+ await waitForLoad(rendered);
26
+ expect(rendered.container).toMatchSnapshot();
27
+ });
28
+
29
+ it("renders null when link is empty", async () => {
30
+ const rendered = render(
31
+ <ConceptLinksApprovalsRow {...defaultProps} link={{}} />
32
+ );
33
+ await waitForLoad(rendered);
34
+ expect(rendered.container).toMatchSnapshot();
35
+ });
36
+
37
+ it("renders row with checkbox when approveView is true", async () => {
38
+ const rendered = render(
39
+ <ConceptLinksApprovalsRow {...defaultProps} approveView={true} />
40
+ );
41
+ await waitForLoad(rendered);
42
+ expect(rendered.container).toMatchSnapshot();
43
+ });
44
+
45
+ it("renders row without checkbox when approveView is false", async () => {
46
+ const rendered = render(
47
+ <ConceptLinksApprovalsRow {...defaultProps} approveView={false} />
48
+ );
49
+ await waitForLoad(rendered);
50
+ expect(rendered.container).toMatchSnapshot();
51
+ });
52
+
53
+ it("calls onCheckboxChange when checkbox is clicked", async () => {
54
+ const onCheckboxChange = jest.fn();
55
+ const rendered = render(
56
+ <ConceptLinksApprovalsRow
57
+ {...defaultProps}
58
+ approveView={true}
59
+ onCheckboxChange={onCheckboxChange}
60
+ />
61
+ );
62
+ await waitForLoad(rendered);
63
+
64
+ const checkbox = rendered.container.querySelector("input[type='checkbox']");
65
+ checkbox.click();
66
+ expect(onCheckboxChange).toHaveBeenCalled();
67
+ });
68
+ });
@@ -0,0 +1,107 @@
1
+ import { render, waitForLoad } from "@truedat/test/render";
2
+ import { useSearchContext } from "@truedat/core/search/SearchContext";
3
+ import { ConceptLinksApprovalsTable } from "../ConceptLinksApprovalsTable";
4
+
5
+ jest.mock("@truedat/core/search/SearchContext", () => {
6
+ const originalModule = jest.requireActual(
7
+ "@truedat/core/search/SearchContext"
8
+ );
9
+
10
+ return {
11
+ __esModule: true,
12
+ ...originalModule,
13
+ useSearchContext: jest.fn(),
14
+ };
15
+ });
16
+
17
+ describe("ConceptLinksApprovalsTable", () => {
18
+ const mockColumns = [
19
+ { name: "source_name", width: 4 },
20
+ { name: "target_name", width: 4 },
21
+ { name: "tag_type", width: 2 },
22
+ { name: "status", width: 2 },
23
+ { name: "updated_at", width: 2 },
24
+ ];
25
+
26
+ beforeEach(() => {
27
+ useSearchContext.mockReturnValue({
28
+ searchData: {
29
+ data: [
30
+ {
31
+ id: 1,
32
+ source_name: "Concept 1",
33
+ target_name: "Structure 1",
34
+ tag_type: "relates_to",
35
+ status: "pending",
36
+ updated_at: "2023-01-01",
37
+ },
38
+ ],
39
+ },
40
+ loading: false,
41
+ sortColumn: null,
42
+ sortDirection: null,
43
+ handleSortSelection: jest.fn(),
44
+ });
45
+ });
46
+
47
+ it("matches the latest snapshot with data", async () => {
48
+ const props = {
49
+ columns: mockColumns,
50
+ approveView: true,
51
+ checkedAll: false,
52
+ addAll: jest.fn(),
53
+ checkRow: jest.fn(),
54
+ isRowChecked: jest.fn(),
55
+ };
56
+
57
+ const rendered = render(<ConceptLinksApprovalsTable {...props} />);
58
+ await waitForLoad(rendered);
59
+ expect(rendered.container).toMatchSnapshot();
60
+ });
61
+
62
+ it("matches the latest snapshot with empty data", async () => {
63
+ useSearchContext.mockReturnValue({
64
+ searchData: { data: [] },
65
+ loading: false,
66
+ sortColumn: null,
67
+ sortDirection: null,
68
+ handleSortSelection: jest.fn(),
69
+ });
70
+
71
+ const props = {
72
+ columns: mockColumns,
73
+ approveView: true,
74
+ checkedAll: false,
75
+ addAll: jest.fn(),
76
+ checkRow: jest.fn(),
77
+ isRowChecked: jest.fn(),
78
+ };
79
+
80
+ const rendered = render(<ConceptLinksApprovalsTable {...props} />);
81
+ await waitForLoad(rendered);
82
+ expect(rendered.container).toMatchSnapshot();
83
+ });
84
+
85
+ it("matches the latest snapshot while loading", async () => {
86
+ useSearchContext.mockReturnValue({
87
+ searchData: { data: [] },
88
+ loading: true,
89
+ sortColumn: null,
90
+ sortDirection: null,
91
+ handleSortSelection: jest.fn(),
92
+ });
93
+
94
+ const props = {
95
+ columns: mockColumns,
96
+ approveView: true,
97
+ checkedAll: false,
98
+ addAll: jest.fn(),
99
+ checkRow: jest.fn(),
100
+ isRowChecked: jest.fn(),
101
+ };
102
+
103
+ const rendered = render(<ConceptLinksApprovalsTable {...props} />);
104
+ await waitForLoad(rendered);
105
+ expect(rendered.container).toMatchSnapshot();
106
+ });
107
+ });