@truedat/dd 5.9.1 → 5.9.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 +6 -6
- package/src/api/mutations.js +28 -0
- package/src/api/queries.js +20 -0
- package/src/api.js +4 -0
- package/src/components/BucketView.js +92 -0
- package/src/components/CatalogCustomViewCards.js +89 -0
- package/src/components/CatalogViewConfigForm.js +130 -0
- package/src/components/CatalogViewConfigs.js +124 -0
- package/src/components/DictionaryRoutes.js +40 -9
- package/src/components/FilteredNav.js +47 -5
- package/src/components/StructureCrumbs.js +43 -15
- package/src/components/StructureItem.js +24 -2
- package/src/components/StructureItemRoot.js +34 -5
- package/src/components/StructureItems.js +3 -2
- package/src/components/StructureNav.js +1 -1
- package/src/components/StructureTabs.js +104 -102
- package/src/components/StructureTags.js +2 -2
- package/src/components/StructureView.js +56 -37
- package/src/components/StructuresRoutes.js +57 -49
- package/src/components/StructuresView.js +5 -0
- package/src/components/SystemCards.js +1 -0
- package/src/components/SystemFilteredNav.js +1 -1
- package/src/components/SystemStructures.js +40 -22
- package/src/components/SystemsRoutes.js +3 -3
- package/src/components/__tests__/BucketView.spec.js +49 -0
- package/src/components/__tests__/CatalogCustomViewCards.spec.js +56 -0
- package/src/components/__tests__/CatalogViewConfigForm.spec.js +75 -0
- package/src/components/__tests__/CatalogViewConfigs.spec.js +75 -0
- package/src/components/__tests__/FilteredNav.spec.js +73 -22
- package/src/components/__tests__/GrantApprovalRuleDeleteButton.spec.js +2 -2
- package/src/components/__tests__/StructureItemRoot.spec.js +5 -4
- package/src/components/__tests__/StructureNav.spec.js +3 -0
- package/src/components/__tests__/StructureStructureLinks.spec.js +1 -1
- package/src/components/__tests__/StructureView.spec.js +60 -12
- package/src/components/__tests__/StructuresView.spec.js +60 -15
- package/src/components/__tests__/SystemFilteredNav.spec.js +7 -1
- package/src/components/__tests__/SystemStructures.spec.js +5 -0
- package/src/components/__tests__/__snapshots__/DictionaryRoutes.spec.js.snap +21 -1
- package/src/components/__tests__/__snapshots__/StructureCrumbs.spec.js.snap +4 -4
- package/src/components/__tests__/__snapshots__/StructuresRoutes.spec.js.snap +7 -1
- package/src/components/__tests__/__snapshots__/SystemStructures.spec.js.snap +1 -3
- package/src/components/index.js +2 -0
- package/src/hooks/useBucketStructures.js +10 -0
- package/src/messages/en.js +3 -0
- package/src/messages/es.js +3 -0
- package/src/reducers/bucketFilter.js +15 -0
- package/src/reducers/index.js +4 -1
- package/src/reducers/navFilter.js +14 -0
- package/src/reducers/structure.js +24 -1
- package/src/reducers/structureRedirect.js +7 -0
- package/src/routines.js +4 -0
- package/src/sagas/deleteCatalogViewConfig.js +37 -0
- package/src/sagas/index.js +6 -0
- package/src/sagas/upsertCatalogViewConfig.js +45 -0
- package/src/selectors/getStructureParent.js +17 -5
- package/src/components/__tests__/__snapshots__/FilteredNav.spec.js.snap +0 -23
- package/src/components/__tests__/__snapshots__/StructureView.spec.js.snap +0 -37
- package/src/components/__tests__/__snapshots__/StructuresView.spec.js.snap +0 -70
|
@@ -5,6 +5,8 @@ import { Route, Switch, useRouteMatch } from "react-router-dom";
|
|
|
5
5
|
import { Unauthorized } from "@truedat/core/components";
|
|
6
6
|
import { useAuthorized } from "@truedat/core/hooks";
|
|
7
7
|
import {
|
|
8
|
+
BUCKETS_VIEW,
|
|
9
|
+
BUCKET_VIEW,
|
|
8
10
|
STRUCTURE,
|
|
9
11
|
STRUCTURES,
|
|
10
12
|
STRUCTURES_BULK_UPDATE,
|
|
@@ -15,6 +17,7 @@ import StructureCrumbs from "./StructureCrumbs";
|
|
|
15
17
|
import StructureLoader from "./StructureLoader";
|
|
16
18
|
import UserSearchFiltersLoader from "./UserSearchFiltersLoader";
|
|
17
19
|
import StructureView from "./StructureView";
|
|
20
|
+
import BucketView from "./BucketView";
|
|
18
21
|
import StructuresBulkUpdate from "./StructuresBulkUpdate";
|
|
19
22
|
import StructuresView from "./StructuresView";
|
|
20
23
|
|
|
@@ -58,60 +61,65 @@ const StructureEventsLoader = () => {
|
|
|
58
61
|
|
|
59
62
|
const AuthorizedRoutes = () => {
|
|
60
63
|
const { formatMessage } = useIntl();
|
|
64
|
+
|
|
61
65
|
return (
|
|
62
|
-
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
<>
|
|
67
|
+
<Switch>
|
|
68
|
+
<Route
|
|
69
|
+
exact
|
|
70
|
+
path={BUCKETS_VIEW}
|
|
71
|
+
render={() => (
|
|
72
|
+
<>
|
|
73
|
+
<UserSearchFiltersLoader scope="data_structure" />
|
|
74
|
+
<StructuresView customView />
|
|
75
|
+
</>
|
|
76
|
+
)}
|
|
77
|
+
/>
|
|
78
|
+
<Route exact path={[BUCKET_VIEW]} render={() => <BucketView />} />
|
|
79
|
+
|
|
80
|
+
<Route
|
|
81
|
+
exact
|
|
82
|
+
path={STRUCTURES}
|
|
83
|
+
render={() => (
|
|
84
|
+
<>
|
|
85
|
+
<UserSearchFiltersLoader scope="data_structure" />
|
|
86
|
+
<StructuresView />
|
|
87
|
+
</>
|
|
88
|
+
)}
|
|
89
|
+
/>
|
|
90
|
+
|
|
91
|
+
<Route
|
|
92
|
+
exact
|
|
93
|
+
path={STRUCTURES_BULK_UPDATE}
|
|
94
|
+
render={() => (
|
|
95
|
+
<>
|
|
96
|
+
<StructureCrumbs
|
|
97
|
+
name={formatMessage({ id: "structures.bulkUpdate.crumbs.top" })}
|
|
98
|
+
/>
|
|
99
|
+
<StructuresBulkUpdate />
|
|
100
|
+
</>
|
|
101
|
+
)}
|
|
102
|
+
/>
|
|
103
|
+
</Switch>
|
|
73
104
|
<Route
|
|
74
105
|
exact
|
|
75
|
-
path={
|
|
76
|
-
|
|
77
|
-
<>
|
|
78
|
-
<StructureCrumbs
|
|
79
|
-
name={formatMessage({ id: "structures.bulkUpdate.crumbs.top" })}
|
|
80
|
-
/>
|
|
81
|
-
<StructuresBulkUpdate />
|
|
82
|
-
</>
|
|
83
|
-
)}
|
|
106
|
+
path={[STRUCTURE_EVENTS, STRUCTURE_VERSION, STRUCTURE]}
|
|
107
|
+
component={ConceptSelectorConceptsLoader}
|
|
84
108
|
/>
|
|
109
|
+
<Route path={STRUCTURE_EVENTS} component={StructureEventsLoader} />
|
|
85
110
|
<Route
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
<StructureImplementationsLoader />
|
|
96
|
-
</>
|
|
97
|
-
)}
|
|
98
|
-
/>
|
|
99
|
-
<Route
|
|
100
|
-
path={STRUCTURE}
|
|
101
|
-
render={() => (
|
|
102
|
-
<>
|
|
103
|
-
<StructureLoader />
|
|
104
|
-
<StructureImplementationsLoader />
|
|
105
|
-
</>
|
|
106
|
-
)}
|
|
107
|
-
/>
|
|
108
|
-
</Switch>
|
|
109
|
-
<Route path={STRUCTURE_EVENTS} component={StructureEventsLoader} />
|
|
110
|
-
<Route path={STRUCTURE} component={StructureView} />
|
|
111
|
-
</>
|
|
112
|
-
)}
|
|
111
|
+
path={[STRUCTURE_VERSION, STRUCTURE]}
|
|
112
|
+
render={() => {
|
|
113
|
+
return (
|
|
114
|
+
<>
|
|
115
|
+
<StructureLoader />
|
|
116
|
+
<StructureImplementationsLoader />
|
|
117
|
+
</>
|
|
118
|
+
);
|
|
119
|
+
}}
|
|
113
120
|
/>
|
|
114
|
-
|
|
121
|
+
<Route path={[STRUCTURE]} component={StructureView} />
|
|
122
|
+
</>
|
|
115
123
|
);
|
|
116
124
|
};
|
|
117
125
|
|
|
@@ -120,7 +128,7 @@ export const StructuresRoutes = () => {
|
|
|
120
128
|
|
|
121
129
|
return (
|
|
122
130
|
<Route
|
|
123
|
-
path={STRUCTURES}
|
|
131
|
+
path={[STRUCTURES, BUCKET_VIEW, BUCKETS_VIEW]}
|
|
124
132
|
render={() => (authorized ? <AuthorizedRoutes /> : <Unauthorized />)}
|
|
125
133
|
/>
|
|
126
134
|
);
|
|
@@ -13,6 +13,7 @@ import StructureDateFilter from "./StructureDateFilter";
|
|
|
13
13
|
import StructuresSearch from "./StructuresSearch";
|
|
14
14
|
import StructuresSearchResults from "./StructuresSearchResults";
|
|
15
15
|
import SystemCards from "./SystemCards";
|
|
16
|
+
import CatalogCustomViewCards from "./CatalogCustomViewCards";
|
|
16
17
|
|
|
17
18
|
export const StructuresHeader = () => (
|
|
18
19
|
<Header as="h2">
|
|
@@ -32,6 +33,7 @@ const StructuresViewContent = ({
|
|
|
32
33
|
structures,
|
|
33
34
|
hasFilterApplied,
|
|
34
35
|
embedded,
|
|
36
|
+
customView,
|
|
35
37
|
}) => {
|
|
36
38
|
const history = useHistory();
|
|
37
39
|
return (
|
|
@@ -46,6 +48,8 @@ const StructuresViewContent = ({
|
|
|
46
48
|
loading={loading}
|
|
47
49
|
onSelect={({ id }) => history.push(linkTo.STRUCTURE({ id }))}
|
|
48
50
|
/>
|
|
51
|
+
) : customView ? (
|
|
52
|
+
<CatalogCustomViewCards />
|
|
49
53
|
) : (
|
|
50
54
|
<SystemCards />
|
|
51
55
|
)}
|
|
@@ -60,6 +64,7 @@ StructuresViewContent.propTypes = {
|
|
|
60
64
|
loading: PropTypes.bool,
|
|
61
65
|
hasFilterApplied: PropTypes.bool,
|
|
62
66
|
embedded: PropTypes.bool,
|
|
67
|
+
customView: PropTypes.bool,
|
|
63
68
|
};
|
|
64
69
|
|
|
65
70
|
export const StructuresView = (props) => {
|
|
@@ -1,48 +1,66 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
|
-
import React from "react";
|
|
2
|
+
import React, { useEffect } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import { connect } from "react-redux";
|
|
5
5
|
import { Grid, Segment } from "semantic-ui-react";
|
|
6
|
+
import { useParams } from "react-router-dom";
|
|
6
7
|
import { getSystem, getSystemTemplate } from "../selectors";
|
|
7
|
-
import
|
|
8
|
+
import { saveNavFilter as saveNavFilterRoutine } from "../routines";
|
|
9
|
+
import FilteredNav from "./FilteredNav";
|
|
8
10
|
import SystemCrumbs from "./SystemCrumbs";
|
|
9
11
|
import SystemView from "./SystemView";
|
|
10
12
|
|
|
11
13
|
export const SystemStructures = ({
|
|
14
|
+
navFilter,
|
|
15
|
+
saveNavFilter,
|
|
12
16
|
system,
|
|
13
17
|
systemStructuresLoading,
|
|
14
18
|
systemTemplate,
|
|
15
|
-
}) =>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
19
|
+
}) => {
|
|
20
|
+
const { id: systemId } = useParams();
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
saveNavFilter({ system_id: systemId });
|
|
24
|
+
}, [systemId, saveNavFilter]);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
!systemStructuresLoading && (
|
|
28
|
+
<Grid>
|
|
29
|
+
<Grid.Row>
|
|
30
|
+
<Grid.Column width={16}>
|
|
31
|
+
<SystemCrumbs system={system} />
|
|
32
|
+
</Grid.Column>
|
|
33
|
+
</Grid.Row>
|
|
34
|
+
<Grid.Row stretched>
|
|
35
|
+
<Grid.Column width={4}>
|
|
36
|
+
<Segment>
|
|
37
|
+
{navFilter?.system_id ? <FilteredNav filter={navFilter} /> : null}
|
|
38
|
+
</Segment>
|
|
39
|
+
</Grid.Column>
|
|
40
|
+
<Grid.Column width={12}>
|
|
41
|
+
<SystemView system={system} systemTemplate={systemTemplate} />
|
|
42
|
+
</Grid.Column>
|
|
43
|
+
</Grid.Row>
|
|
44
|
+
</Grid>
|
|
45
|
+
)
|
|
34
46
|
);
|
|
47
|
+
};
|
|
35
48
|
|
|
36
49
|
SystemStructures.propTypes = {
|
|
50
|
+
navFilter: PropTypes.object,
|
|
51
|
+
saveNavFilter: PropTypes.func,
|
|
37
52
|
system: PropTypes.object,
|
|
38
53
|
systemStructuresLoading: PropTypes.bool,
|
|
39
54
|
systemTemplate: PropTypes.object,
|
|
40
55
|
};
|
|
41
56
|
|
|
42
57
|
const mapStateToProps = (state) => ({
|
|
58
|
+
navFilter: state?.navFilter,
|
|
43
59
|
system: getSystem(state),
|
|
44
60
|
systemStructuresLoading: _.prop("systemStructuresLoading")(state),
|
|
45
61
|
systemTemplate: getSystemTemplate(state),
|
|
46
62
|
});
|
|
47
63
|
|
|
48
|
-
export default connect(mapStateToProps
|
|
64
|
+
export default connect(mapStateToProps, {
|
|
65
|
+
saveNavFilter: saveNavFilterRoutine,
|
|
66
|
+
})(SystemStructures);
|
|
@@ -7,7 +7,7 @@ import { Route, Switch } from "react-router-dom";
|
|
|
7
7
|
import {
|
|
8
8
|
SYSTEM_EDIT,
|
|
9
9
|
SYSTEM_NEW,
|
|
10
|
-
SYSTEM_STRUCTURES
|
|
10
|
+
SYSTEM_STRUCTURES,
|
|
11
11
|
} from "@truedat/core/routes";
|
|
12
12
|
import SystemCrumbs from "./SystemCrumbs";
|
|
13
13
|
import SystemForm from "./SystemForm";
|
|
@@ -24,7 +24,7 @@ export const SystemsRoutes = ({ system }) => {
|
|
|
24
24
|
exact
|
|
25
25
|
render={() => (
|
|
26
26
|
<>
|
|
27
|
-
<SystemStructuresLoader />
|
|
27
|
+
{/* <SystemStructuresLoader /> */}
|
|
28
28
|
<SystemStructures />
|
|
29
29
|
</>
|
|
30
30
|
)}
|
|
@@ -60,7 +60,7 @@ export const SystemsRoutes = ({ system }) => {
|
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
SystemsRoutes.propTypes = {
|
|
63
|
-
system: PropTypes.object
|
|
63
|
+
system: PropTypes.object,
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
const mapStateToProps = _.pick(["system"]);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@truedat/test/render";
|
|
3
|
+
import { waitFor } from "@testing-library/react";
|
|
4
|
+
import { MemoryRouter } from "react-router-dom";
|
|
5
|
+
import { BucketView } from "../BucketView";
|
|
6
|
+
|
|
7
|
+
const state = {
|
|
8
|
+
authentication: { role: "admin" },
|
|
9
|
+
userPermissions: {
|
|
10
|
+
confidential: true,
|
|
11
|
+
create_foreign_grant_request: true,
|
|
12
|
+
profile_permission: false,
|
|
13
|
+
request_grant: true,
|
|
14
|
+
update: true,
|
|
15
|
+
update_domain: true,
|
|
16
|
+
update_grant_removal: true,
|
|
17
|
+
view_profiling_permission: true,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
describe("<BucketView />", () => {
|
|
22
|
+
it("Applies navFilter", async () => {
|
|
23
|
+
const saveNavFilter = jest.fn();
|
|
24
|
+
const navFilter = {};
|
|
25
|
+
const renderOpts = {
|
|
26
|
+
state,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
render(
|
|
30
|
+
<MemoryRouter
|
|
31
|
+
initialEntries={[
|
|
32
|
+
"?propertyPath=metadata.region&propertyValue=eu-west-1",
|
|
33
|
+
]}
|
|
34
|
+
>
|
|
35
|
+
<BucketView {...{ navFilter, saveNavFilter }} />
|
|
36
|
+
</MemoryRouter>,
|
|
37
|
+
renderOpts
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
await waitFor(() =>
|
|
41
|
+
/* Maybe it would be better to test the real store instead of the
|
|
42
|
+
* mock store from "@truedat/test/render"
|
|
43
|
+
*/
|
|
44
|
+
expect(saveNavFilter).toHaveBeenCalledWith({
|
|
45
|
+
"metadata.region": "eu-west-1",
|
|
46
|
+
})
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@truedat/test/render";
|
|
3
|
+
import { within } from "@testing-library/react";
|
|
4
|
+
import { CatalogCustomViewCards } from "../CatalogCustomViewCards";
|
|
5
|
+
import es from "../../messages/en";
|
|
6
|
+
|
|
7
|
+
const structureFilters = {
|
|
8
|
+
"metadata.database": {
|
|
9
|
+
buckets: [
|
|
10
|
+
{
|
|
11
|
+
doc_count: 11234,
|
|
12
|
+
key: "_missing",
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
doc_count: 2345,
|
|
16
|
+
key: "database_1",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
doc_count: 3456,
|
|
20
|
+
key: "database_2",
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
values: ["_missing", "database_1", "database_2"],
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const messages = {
|
|
28
|
+
es: {
|
|
29
|
+
...es,
|
|
30
|
+
missingBucket: "_missing",
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
jest.mock("react-router-dom", () => ({
|
|
35
|
+
...jest.requireActual("react-router-dom"),
|
|
36
|
+
useParams: () => ({ propertyPath: "metadata.database" }),
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
describe("<CatalogCustomViewCard />", () => {
|
|
40
|
+
it("Shows a structure filter value and count inside each Card", () => {
|
|
41
|
+
const { getByRole } = render(
|
|
42
|
+
<CatalogCustomViewCards structureFilters={structureFilters} />,
|
|
43
|
+
{ locale: "es", messages }
|
|
44
|
+
);
|
|
45
|
+
const missingCard = getByRole("link", { name: /_missing/ });
|
|
46
|
+
expect(missingCard).toBeInTheDocument();
|
|
47
|
+
const databaseOneCard = getByRole("link", { name: /database_1/ });
|
|
48
|
+
expect(databaseOneCard).toBeInTheDocument();
|
|
49
|
+
const databaseTwoCard = getByRole("link", { name: /database_2/ });
|
|
50
|
+
expect(databaseTwoCard).toBeInTheDocument();
|
|
51
|
+
|
|
52
|
+
expect(within(missingCard).getByText(/^11.234$/)).toBeInTheDocument();
|
|
53
|
+
expect(within(databaseOneCard).getByText(/^2345$/)).toBeInTheDocument();
|
|
54
|
+
expect(within(databaseTwoCard).getByText(/^3456$/)).toBeInTheDocument();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@truedat/test/render";
|
|
3
|
+
import { waitFor, within } from "@testing-library/react";
|
|
4
|
+
import userEvent from "@testing-library/user-event";
|
|
5
|
+
import { CatalogViewConfigFormLoader } from "../CatalogViewConfigForm";
|
|
6
|
+
import { CATALOG_VIEW_CONFIG_QUERY } from "../../api/queries";
|
|
7
|
+
import { upsertCatalogViewConfig } from "../../routines";
|
|
8
|
+
|
|
9
|
+
const config = {
|
|
10
|
+
__typename: "CatalogViewConfig",
|
|
11
|
+
id: "123",
|
|
12
|
+
fieldType: "metadata",
|
|
13
|
+
fieldName: "someFieldName",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const configsMock = {
|
|
17
|
+
request: { query: CATALOG_VIEW_CONFIG_QUERY },
|
|
18
|
+
result: { data: { catalogViewConfig: config } },
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const renderOpts = { mocks: [configsMock] };
|
|
22
|
+
|
|
23
|
+
jest.mock("@truedat/core/hooks", () => ({
|
|
24
|
+
useAuthorized: jest.fn(() => true),
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
const mockHistoryPush = jest.fn();
|
|
28
|
+
|
|
29
|
+
jest.mock("react-router-dom", () => ({
|
|
30
|
+
...jest.requireActual("react-router-dom"),
|
|
31
|
+
useHistory: () => ({
|
|
32
|
+
push: mockHistoryPush,
|
|
33
|
+
}),
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
describe("<CatalogViewConfigFormLoader />", () => {
|
|
37
|
+
it("Saves the configuration", async () => {
|
|
38
|
+
const dispatch = jest.fn();
|
|
39
|
+
const { findByRole, getByRole } = render(<CatalogViewConfigFormLoader />, {
|
|
40
|
+
...renderOpts,
|
|
41
|
+
dispatch,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
/* https://github.com/testing-library/dom-testing-library/issues/474#issuecomment-597606894
|
|
45
|
+
* A <form> element needs an accessible name to have the form role. So you
|
|
46
|
+
* need <form aria-label="form" /> or
|
|
47
|
+
* <form aria-labelledby="form-label-element-id" />.
|
|
48
|
+
*/
|
|
49
|
+
await findByRole("form");
|
|
50
|
+
|
|
51
|
+
const fieldTypeDropdown = getByRole("listbox", { name: "fieldType" });
|
|
52
|
+
const selectedFieldType = within(fieldTypeDropdown).getByRole("option", {
|
|
53
|
+
selected: true,
|
|
54
|
+
});
|
|
55
|
+
expect(within(selectedFieldType).getByText(/Metadata/)).toBeInTheDocument();
|
|
56
|
+
|
|
57
|
+
const fieldName = getByRole("textbox", { name: "fieldName" });
|
|
58
|
+
expect(fieldName).toHaveValue("someFieldName");
|
|
59
|
+
|
|
60
|
+
userEvent.clear(fieldName);
|
|
61
|
+
userEvent.type(fieldName, "updatedFieldName");
|
|
62
|
+
const saveButton = getByRole("button", { name: "save" });
|
|
63
|
+
|
|
64
|
+
userEvent.click(saveButton);
|
|
65
|
+
await waitFor(() => {
|
|
66
|
+
expect(dispatch).toHaveBeenLastCalledWith(
|
|
67
|
+
upsertCatalogViewConfig({
|
|
68
|
+
id: "123",
|
|
69
|
+
fieldType: "metadata",
|
|
70
|
+
fieldName: "updatedFieldName",
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@truedat/test/render";
|
|
3
|
+
import { waitFor, within } from "@testing-library/react";
|
|
4
|
+
import userEvent from "@testing-library/user-event";
|
|
5
|
+
import { CatalogViewConfigsLoader } from "../CatalogViewConfigs";
|
|
6
|
+
import { CATALOG_VIEW_CONFIGS_QUERY } from "../../api/queries";
|
|
7
|
+
import { deleteCatalogViewConfig } from "../../routines";
|
|
8
|
+
|
|
9
|
+
const config = {
|
|
10
|
+
__typename: "CatalogViewConfig",
|
|
11
|
+
id: "123",
|
|
12
|
+
fieldType: "someFieldType",
|
|
13
|
+
fieldName: "someFieldName",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const configsMock = {
|
|
17
|
+
request: { query: CATALOG_VIEW_CONFIGS_QUERY },
|
|
18
|
+
result: { data: { catalogViewConfigs: [config] } },
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const renderOpts = { mocks: [configsMock] };
|
|
22
|
+
|
|
23
|
+
jest.mock("@truedat/core/hooks", () => ({
|
|
24
|
+
useAuthorized: jest.fn(() => true),
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
const mockHistoryPush = jest.fn();
|
|
28
|
+
|
|
29
|
+
jest.mock("react-router-dom", () => ({
|
|
30
|
+
...jest.requireActual("react-router-dom"),
|
|
31
|
+
useHistory: () => ({
|
|
32
|
+
push: mockHistoryPush,
|
|
33
|
+
}),
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
describe("<CatalogViewConfigsLoader />", () => {
|
|
37
|
+
it("loads all catalog view configs and shows them in a table", async () => {
|
|
38
|
+
const { findByRole } = render(<CatalogViewConfigsLoader />, renderOpts);
|
|
39
|
+
|
|
40
|
+
const table = await findByRole("table");
|
|
41
|
+
const row = within(table).getAllByRole("row")[1];
|
|
42
|
+
const fieldType = within(row).getByText(/someFieldType/);
|
|
43
|
+
const fieldName = within(row).getByText(/someFieldName/);
|
|
44
|
+
expect(fieldType).toBeInTheDocument();
|
|
45
|
+
expect(fieldName).toBeInTheDocument();
|
|
46
|
+
userEvent.click(fieldName);
|
|
47
|
+
expect(mockHistoryPush).toHaveBeenCalledWith("/bucketViewConfigs/123/edit");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("deletes a catalog view config", async () => {
|
|
51
|
+
const dispatch = jest.fn();
|
|
52
|
+
const { findByRole, getByRole } = render(<CatalogViewConfigsLoader />, {
|
|
53
|
+
...renderOpts,
|
|
54
|
+
dispatch,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const table = await findByRole("table");
|
|
58
|
+
const row = within(table).getAllByRole("row")[1];
|
|
59
|
+
const deleteButton = within(row).getByRole("button", { name: "delete" });
|
|
60
|
+
userEvent.click(deleteButton);
|
|
61
|
+
|
|
62
|
+
const modalConfirmDeleteButton = getByRole("button", {
|
|
63
|
+
name: "modal-affirmative-action",
|
|
64
|
+
});
|
|
65
|
+
userEvent.click(modalConfirmDeleteButton);
|
|
66
|
+
|
|
67
|
+
await waitFor(() => {
|
|
68
|
+
expect(dispatch).toHaveBeenLastCalledWith(
|
|
69
|
+
deleteCatalogViewConfig({
|
|
70
|
+
id: "123",
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
});
|