@truedat/bg 7.2.5 → 7.2.7

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/bg",
3
- "version": "7.2.5",
3
+ "version": "7.2.7",
4
4
  "description": "Truedat Web Business Glossary",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -34,7 +34,7 @@
34
34
  "@testing-library/jest-dom": "^5.16.5",
35
35
  "@testing-library/react": "^12.0.0",
36
36
  "@testing-library/user-event": "^13.2.1",
37
- "@truedat/test": "7.2.5",
37
+ "@truedat/test": "7.2.7",
38
38
  "babel-jest": "^28.1.0",
39
39
  "babel-plugin-dynamic-import-node": "^2.3.3",
40
40
  "babel-plugin-lodash": "^3.3.4",
@@ -86,9 +86,9 @@
86
86
  ]
87
87
  },
88
88
  "dependencies": {
89
- "@truedat/core": "7.2.5",
90
- "@truedat/df": "7.2.5",
91
- "@truedat/lm": "7.2.5",
89
+ "@truedat/core": "7.2.7",
90
+ "@truedat/df": "7.2.7",
91
+ "@truedat/lm": "7.2.7",
92
92
  "decode-uri-component": "^0.2.2",
93
93
  "file-saver": "^2.0.5",
94
94
  "moment": "^2.29.4",
@@ -111,5 +111,5 @@
111
111
  "react-dom": ">= 16.8.6 < 17",
112
112
  "semantic-ui-react": ">= 2.0.3 < 2.2"
113
113
  },
114
- "gitHead": "1f3cfdc8ebc43228b46b00bf690c2bf963d368d5"
114
+ "gitHead": "8bafa5d50e387f169d87b9a1d3b373d35114288e"
115
115
  }
@@ -1,11 +1,14 @@
1
1
  import _ from "lodash/fp";
2
- import React from "react";
2
+ import React, { useEffect, useState } from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { connect } from "react-redux";
5
5
  import { Route } from "react-router-dom";
6
6
  import { Grid, Segment } from "semantic-ui-react";
7
7
  import { Comments, CommentsLoader } from "@truedat/core/components";
8
8
  import { CONCEPT_VERSION } from "@truedat/core/routes";
9
+ import { useIntl } from "react-intl";
10
+ import { useLanguage } from "@truedat/core/i18n";
11
+ import { splitTranslatableFields } from "@truedat/core/services/i18nContent";
9
12
  import ConceptRelationsSummary from "../relations/components/ConceptRelationsSummary";
10
13
  import ConceptArchiveLoader from "./ConceptArchiveLoader";
11
14
  import ConceptCompleteness from "./ConceptCompleteness";
@@ -29,52 +32,121 @@ const ConceptRulesLoader = React.lazy(() =>
29
32
  import("@truedat/dq/components/ConceptRulesLoader")
30
33
  );
31
34
 
32
- export const Concept = ({ id }) => (
33
- <>
34
- <ConceptCrumbs />
35
- <ConceptArchiveLoader />
36
- <CommentsLoader resource_id={id} resource_type="business_concept" />
37
- <EventsLoader resource_id={id} resource_type="concept" />
38
- <ConceptRulesLoader />
39
- <RelationsLoader
40
- resource_id={id}
41
- resource_type="business_concept"
42
- target_type="business_concept"
43
- />
44
- <Grid columns="equal" style={{ marginTop: 0 }}>
45
- <Grid.Column width={12}>
46
- <Segment>
47
- <ConceptHeader />
48
- <ConceptTabs />
49
- <ConceptTabPane />
50
- </Segment>
51
- <Route
52
- path={CONCEPT_VERSION}
53
- exact
54
- render={() => (
55
- <Segment>
56
- <Comments />
57
- </Segment>
58
- )}
59
- />
60
- </Grid.Column>
61
- <Grid.Column width={4}>
62
- <ConceptSummary />
63
- <ConceptRelationsSummary />
64
- <ConceptTaxonomy />
65
- <SharedToDomains />
66
- <ConceptCompleteness />
67
- </Grid.Column>
68
- </Grid>
69
- </>
70
- );
35
+ export const Concept = ({ id, concept }) => {
36
+ const { locales } = useLanguage();
37
+ const { locale } = useIntl();
38
+
39
+ const defaultLang = _.flow(
40
+ _.find({ is_default: true }),
41
+ _.prop("lang")
42
+ )(locales);
43
+
44
+ const initialLang = concept.status == "published" ? locale : defaultLang;
45
+
46
+ const [selectedLang, setSelectedLang] = useState(initialLang);
47
+ useEffect(() => {
48
+ setSelectedLang(initialLang);
49
+ }, [initialLang]);
50
+
51
+ const content = _.getOr({}, "dynamic_content")(concept);
52
+
53
+ const { noTranslatable: noTranslatableFields } = splitTranslatableFields(
54
+ concept.template
55
+ );
56
+ const noTranslatableContent = _.pick(_.keys(noTranslatableFields))(
57
+ concept.dynamic_content
58
+ );
59
+
60
+ const i18nContent = concept.i18n_content || {};
61
+
62
+ const i18nConcept = _.flow(
63
+ _.filter(({ is_enabled }) => is_enabled),
64
+ _.map((locale) => {
65
+ const { id, lang, is_default, is_required, local_name } = locale;
66
+ const contentLang = _.get(lang)(i18nContent);
67
+ const publishedWithoutLang =
68
+ _.isNil(contentLang) && concept.status == "published";
69
+ const langContent =
70
+ is_default || publishedWithoutLang
71
+ ? content
72
+ : _.isEmpty(contentLang?.content)
73
+ ? { ...noTranslatableContent }
74
+ : { ...noTranslatableContent, ...contentLang?.content };
75
+
76
+ const langName = is_default ? concept.name : contentLang?.name || "";
77
+
78
+ return {
79
+ id,
80
+ lang,
81
+ isDefault: is_default,
82
+ isRequired: is_required,
83
+ name: langName,
84
+ langLocalName: local_name,
85
+ content: langContent,
86
+ };
87
+ }),
88
+ _.orderBy(["isDefault", "isRequired", "lang"], ["desc", "desc", "asc"]),
89
+ _.keyBy("lang")
90
+ )(locales);
91
+
92
+ const selectedContent = i18nConcept[selectedLang]?.content || concept.content;
93
+
94
+ return (
95
+ <>
96
+ <ConceptCrumbs />
97
+ <ConceptArchiveLoader />
98
+ <CommentsLoader resource_id={id} resource_type="business_concept" />
99
+ <EventsLoader resource_id={id} resource_type="concept" />
100
+ <ConceptRulesLoader />
101
+ <RelationsLoader
102
+ resource_id={id}
103
+ resource_type="business_concept"
104
+ target_type="business_concept"
105
+ />
106
+ <Grid columns="equal" style={{ marginTop: 0 }}>
107
+ <Grid.Column width={12}>
108
+ <Segment>
109
+ <ConceptHeader
110
+ selectedLang={selectedLang}
111
+ setSelectedLang={setSelectedLang}
112
+ i18nConcept={i18nConcept}
113
+ />
114
+ <ConceptTabs />
115
+ <ConceptTabPane
116
+ lang={selectedLang}
117
+ selectedContent={selectedContent}
118
+ />
119
+ </Segment>
120
+ <Route
121
+ path={CONCEPT_VERSION}
122
+ exact
123
+ render={() => (
124
+ <Segment>
125
+ <Comments />
126
+ </Segment>
127
+ )}
128
+ />
129
+ </Grid.Column>
130
+ <Grid.Column width={4}>
131
+ <ConceptSummary />
132
+ <ConceptRelationsSummary />
133
+ <ConceptTaxonomy />
134
+ <SharedToDomains />
135
+ <ConceptCompleteness />
136
+ </Grid.Column>
137
+ </Grid>
138
+ </>
139
+ );
140
+ };
71
141
 
72
142
  Concept.propTypes = {
73
143
  id: PropTypes.number.isRequired,
144
+ concept: PropTypes.object,
74
145
  };
75
146
 
76
147
  const mapStateToProps = ({ concept }) => ({
77
148
  id: _.prop("business_concept_id")(concept),
149
+ concept: concept,
78
150
  });
79
151
 
80
152
  export default connect(mapStateToProps)(Concept);
@@ -1,105 +1,34 @@
1
- import _ from "lodash/fp";
2
- import React, { useEffect, useState } from "react";
1
+ import React from "react";
3
2
  import PropTypes from "prop-types";
4
3
  import { connect } from "react-redux";
5
- import { Button, ButtonGroup, Segment } from "semantic-ui-react";
6
- import { useIntl } from "react-intl";
7
- import { useLanguage } from "@truedat/core/i18n";
8
- import { splitTranslatableFields } from "@truedat/core/services/i18nContent";
4
+ import { Segment } from "semantic-ui-react";
5
+ import { I18nProvider } from "@truedat/core/i18n";
9
6
 
10
7
  const DynamicFormViewer = React.lazy(() =>
11
8
  import("@truedat/df/components/DynamicFormViewer")
12
9
  );
13
10
 
14
- export const ConceptDetails = ({ concept }) => {
15
- const { locale } = useIntl();
16
- const { locales } = useLanguage();
17
-
18
- const defaultLang = _.flow(
19
- _.find({ is_default: true }),
20
- _.prop("lang")
21
- )(locales);
22
-
23
- const initialLang = concept.status == "published" ? locale : defaultLang;
24
-
25
- const [selectedLang, setSelectedLang] = useState(initialLang);
26
- useEffect(() => {
27
- setSelectedLang(initialLang);
28
- }, [initialLang]);
29
-
30
- const content = _.getOr({}, "dynamic_content")(concept);
31
-
32
- const { noTranslatable: noTranslatableFields } = splitTranslatableFields(
33
- concept.template
34
- );
35
- const noTranslatableContent = _.pick(_.keys(noTranslatableFields))(
36
- concept.dynamic_content
37
- );
38
-
39
- const i18nContent = concept.i18n_content || {};
40
-
41
- const i18nConcept = _.flow(
42
- _.filter(({ is_enabled }) => is_enabled),
43
- _.map((locale) => {
44
- const { id, lang, is_default, is_required, local_name } = locale;
45
- const contentLang = _.get(lang)(i18nContent);
46
- const publishedWithoutLang =
47
- _.isNil(contentLang) && concept.status == "published";
48
- const langContent =
49
- is_default || publishedWithoutLang
50
- ? content
51
- : _.isEmpty(contentLang?.content)
52
- ? { ...noTranslatableContent }
53
- : { ...noTranslatableContent, ...contentLang?.content };
54
-
55
- const langName = is_default ? concept.name : contentLang?.name || "";
56
-
57
- return {
58
- id,
59
- lang,
60
- isDefault: is_default,
61
- isRequired: is_required,
62
- name: langName,
63
- langLocalName: local_name,
64
- content: langContent,
65
- };
66
- }),
67
- _.orderBy(["isDefault", "isRequired", "lang"], ["desc", "desc", "asc"]),
68
- _.keyBy("lang")
69
- )(locales);
70
-
11
+ export const ConceptDetails = ({ concept, selectedContent, lang }) => {
71
12
  return (
72
13
  <Segment attached="bottom">
73
- {!_.includes(concept.status)(["published", "versioned"]) &&
74
- _.size(i18nConcept) > 1 ? (
75
- <ButtonGroup floated="right">
76
- {_.flow(
77
- _.map(({ lang, content }) => {
78
- return !_.isEmpty(content) ? (
79
- <Button
80
- key={lang}
81
- content={lang}
82
- size="mini"
83
- onClick={() => setSelectedLang(lang)}
84
- active={selectedLang == lang}
85
- />
86
- ) : null;
87
- })
88
- )(i18nConcept)}
89
- </ButtonGroup>
90
- ) : null}
91
- <DynamicFormViewer
92
- template={concept.template}
93
- content={i18nConcept[selectedLang]?.content || concept.content}
94
- />
14
+ <I18nProvider lang={lang}>
15
+ <DynamicFormViewer
16
+ template={concept.template}
17
+ content={selectedContent}
18
+ />
19
+ </I18nProvider>
95
20
  </Segment>
96
21
  );
97
22
  };
98
23
 
99
24
  ConceptDetails.propTypes = {
100
25
  concept: PropTypes.object,
26
+ selectedContent: PropTypes.object,
27
+ lang: PropTypes.string,
101
28
  };
102
29
 
103
- const mapStateToProps = ({ concept }) => ({ concept });
30
+ const mapStateToProps = ({ concept }) => ({
31
+ concept,
32
+ });
104
33
 
105
34
  export default connect(mapStateToProps)(ConceptDetails);
@@ -3,7 +3,14 @@ import React from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { connect } from "react-redux";
5
5
  import { FormattedMessage, useIntl } from "react-intl";
6
- import { Grid, Header, Icon } from "semantic-ui-react";
6
+ import {
7
+ Grid,
8
+ Header,
9
+ Icon,
10
+ Button,
11
+ ButtonGroup,
12
+ GridRow,
13
+ } from "semantic-ui-react";
7
14
  import { linkTo } from "@truedat/core/routes";
8
15
  import ShareLinkPopup from "@truedat/audit/components/ShareLinkPopup";
9
16
  import ConceptConfidentialButton from "./ConceptConfidentialButton";
@@ -15,16 +22,22 @@ export const ConceptHeader = ({
15
22
  concept,
16
23
  setConfidentialConcept,
17
24
  share,
18
- template,
25
+ selectedLang,
26
+ setSelectedLang,
27
+ i18nConcept,
19
28
  }) => {
20
- const { locale, formatMessage } = useIntl();
29
+ const { formatMessage } = useIntl();
30
+ const template = concept.template;
21
31
 
22
32
  const path = linkTo.CONCEPT_VERSION({
23
33
  business_concept_id: _.prop("business_concept_id")(concept),
24
34
  id: "current",
25
35
  });
26
36
 
27
- const i18nContent = _.flow(_.get("i18n_content"), _.get(locale))(concept);
37
+ const i18nContent = _.flow(
38
+ _.get("i18n_content"),
39
+ _.get(selectedLang)
40
+ )(concept);
28
41
 
29
42
  const name = _.isUndefined(i18nContent) ? concept?.name : i18nContent?.name;
30
43
  const shareUrl = `${location.protocol}//${location.host}${path}`;
@@ -33,63 +46,80 @@ export const ConceptHeader = ({
33
46
 
34
47
  return (
35
48
  <Grid>
36
- <Grid.Column width={8}>
37
- <Header as="h2">
38
- <Icon circular name="book" />
39
- <Header.Content>
40
- {name}
41
- <Header.Subheader>
42
- <FormattedMessage
43
- id={`templates.${templateLabel}`}
44
- defaultMessage={templateLabel}
45
- />
46
- </Header.Subheader>
47
- </Header.Content>
48
- </Header>
49
- </Grid.Column>
50
- <Grid.Column width={8} textAlign="right">
51
- <Grid>
52
- <Grid.Row>
53
- <Grid.Column textAlign="right">
54
- <ShareLinkPopup
55
- url={shareUrl}
56
- title={shareTitle}
57
- name={name}
58
- icon="concepts"
59
- popupType="concepts"
60
- />
61
- {share && <SharedToDomainsPopup />}
62
- <ConceptSubscription />
63
- {!_.isEmpty(setConfidentialConcept) && (
64
- <ConceptConfidentialButton concept={concept} />
65
- )}
66
- </Grid.Column>
67
- </Grid.Row>
68
- <Grid.Row textAlign="right">
69
- <Grid.Column textAlign="right">
70
- <ConceptActions />
71
- </Grid.Column>
72
- </Grid.Row>
73
- </Grid>
74
- </Grid.Column>
49
+ <GridRow>
50
+ <Grid.Column width={8}>
51
+ <Header as="h2">
52
+ <Icon circular name="book" />
53
+ <Header.Content>
54
+ {name}
55
+ <Header.Subheader>
56
+ <FormattedMessage
57
+ id={`templates.${templateLabel}`}
58
+ defaultMessage={templateLabel}
59
+ />
60
+ </Header.Subheader>
61
+ </Header.Content>
62
+ </Header>
63
+ </Grid.Column>
64
+ <Grid.Column width={8} textAlign="right">
65
+ <ShareLinkPopup
66
+ url={shareUrl}
67
+ title={shareTitle}
68
+ name={name}
69
+ icon="concepts"
70
+ popupType="concepts"
71
+ />
72
+ {share && <SharedToDomainsPopup />}
73
+ <ConceptSubscription />
74
+ {!_.isEmpty(setConfidentialConcept) ? (
75
+ <ConceptConfidentialButton concept={concept} />
76
+ ) : null}
77
+ </Grid.Column>
78
+ </GridRow>
79
+ <GridRow>
80
+ <Grid.Column width={8}>
81
+ {!_.includes(concept.status)(["published", "versioned"]) &&
82
+ _.size(i18nConcept) > 1 ? (
83
+ <ButtonGroup floated="left">
84
+ {_.flow(
85
+ _.map(({ lang, content }) => {
86
+ return !_.isEmpty(content) ? (
87
+ <Button
88
+ key={lang}
89
+ content={
90
+ <FormattedMessage id={"i18n.messages.lang." + lang} />
91
+ }
92
+ size="mini"
93
+ onClick={() => setSelectedLang(lang)}
94
+ active={selectedLang == lang}
95
+ />
96
+ ) : null;
97
+ })
98
+ )(i18nConcept)}
99
+ </ButtonGroup>
100
+ ) : null}
101
+ </Grid.Column>
102
+ <Grid.Column width={8} textAlign="right">
103
+ <ConceptActions />
104
+ </Grid.Column>
105
+ </GridRow>
75
106
  </Grid>
76
107
  );
77
108
  };
78
109
 
79
110
  ConceptHeader.propTypes = {
80
111
  setConfidentialConcept: PropTypes.object,
81
- share: PropTypes.bool,
112
+ share: PropTypes.object,
82
113
  concept: PropTypes.object,
83
- template: PropTypes.object,
114
+ selectedLang: PropTypes.string,
115
+ setSelectedLang: PropTypes.func,
116
+ i18nConcept: PropTypes.object,
84
117
  };
85
118
 
86
- const EMPTY = {};
87
-
88
119
  const mapStateToProps = ({ concept, conceptActions, conceptPermissions }) => ({
89
120
  share: _.prop("share")(conceptPermissions),
90
121
  concept,
91
122
  setConfidentialConcept: _.prop("set_confidential")(conceptActions),
92
- template: concept.template || EMPTY,
93
123
  });
94
124
 
95
125
  export default connect(mapStateToProps)(ConceptHeader);
@@ -11,6 +11,7 @@ import {
11
11
  CONCEPT_RULES_NEW,
12
12
  CONCEPT_VERSION,
13
13
  } from "@truedat/core/routes";
14
+ import PropTypes from "prop-types";
14
15
  import ConceptRelationsRoutes from "../relations/components/ConceptRelationsRoutes";
15
16
  import ConceptArchive from "./ConceptArchive";
16
17
  import ConceptDetails from "./ConceptDetails";
@@ -22,10 +23,16 @@ const ConceptRules = React.lazy(() =>
22
23
 
23
24
  const NewRule = React.lazy(() => import("@truedat/dq/components/NewRule"));
24
25
 
25
- export const ConceptTabPane = () => (
26
+ export const ConceptTabPane = ({ selectedContent, lang }) => (
26
27
  <ErrorBoundary>
27
28
  <Switch>
28
- <Route path={CONCEPT_VERSION} exact render={() => <ConceptDetails />} />
29
+ <Route
30
+ path={CONCEPT_VERSION}
31
+ exact
32
+ render={() => (
33
+ <ConceptDetails selectedContent={selectedContent} lang={lang} />
34
+ )}
35
+ />
29
36
  <Route
30
37
  path={CONCEPT_LINKS_STRUCTURES}
31
38
  render={() => <ConceptRelationsRoutes />}
@@ -53,4 +60,9 @@ export const ConceptTabPane = () => (
53
60
  </ErrorBoundary>
54
61
  );
55
62
 
63
+ ConceptTabPane.propTypes = {
64
+ lang: PropTypes.string,
65
+ selectedContent: PropTypes.object,
66
+ };
67
+
56
68
  export default ConceptTabPane;
@@ -1,12 +1,131 @@
1
1
  import React from "react";
2
- import { shallow } from "enzyme";
2
+ import { render } from "@truedat/test/render";
3
+ import { waitFor } from "@testing-library/react";
4
+ import { LangProviderWrapper } from "@truedat/core/i18n";
3
5
  import { Concept } from "../Concept";
4
6
 
7
+ beforeAll(() => {
8
+ jest.useFakeTimers();
9
+ jest.setSystemTime(new Date("2025-01-01T10:00:00Z"));
10
+ });
11
+
12
+ afterAll(() => {
13
+ jest.useRealTimers();
14
+ });
15
+
16
+ const renderOpts = {
17
+ messages: {
18
+ en: {
19
+ "concepts.crumbs.top": "Business Glossary",
20
+ "concepts.crumbs.pending": "Draft",
21
+ "i18n.messages.lang.es": "Spanish",
22
+ "i18n.messages.lang.en": "English",
23
+ "tabs.bg.concept": "Concept",
24
+ "tabs.bg.relations_data_field": "Linkage",
25
+ "tabs.bg.qualityRules": "Quality Rules",
26
+ "tabs.bg.history": "History",
27
+ "tabs.bg.audit": "Audit",
28
+ "concept.props.status": "Status",
29
+ "concept.props.version": "Version",
30
+ "concept.props.last_update_at": "Update",
31
+ "concept.props.last_update_by": "User",
32
+ },
33
+ },
34
+ state: {
35
+ concept: {
36
+ id: 1,
37
+ business_concept_id: 1,
38
+ name: "Concept_en",
39
+ type: "type",
40
+ status: "draft",
41
+ last_change_at: "2025-01-01T10:00:00Z",
42
+ template: {
43
+ content: [
44
+ {
45
+ name: "foo_group",
46
+ fields: [
47
+ { name: "field", label: "field_label", values: ["value1"] },
48
+ ],
49
+ },
50
+ ],
51
+ },
52
+ i18n_content: {
53
+ es: {
54
+ field: "field_label",
55
+ content: { values: ["value"] },
56
+ completeness: 1.0,
57
+ name: "Concept_es",
58
+ },
59
+ en: {
60
+ field: "field_label",
61
+ content: { values: ["value1"] },
62
+ completeness: 1.0,
63
+ name: "Concept_en",
64
+ },
65
+ },
66
+ dynamic_content: {
67
+ field: { value: "value1", origin: "user" },
68
+ },
69
+ },
70
+ locales: [
71
+ { id: 1, lang: "en", is_default: true, is_required: true },
72
+ { id: 2, lang: "es", is_default: false, is_required: false },
73
+ ],
74
+ },
75
+ fallback: "lazy",
76
+ };
77
+
5
78
  describe("<Concept />", () => {
6
- const props = { id: 1 };
79
+ const props = {
80
+ id: 1,
81
+ concept: {
82
+ id: 1,
83
+ business_concept_id: 1,
84
+ name: "Concept1",
85
+ type: "type",
86
+ status: "draft",
87
+ last_change_at: "2024-01-01T10:00:00Z",
88
+ template: {
89
+ content: [
90
+ {
91
+ name: "foo_group",
92
+ fields: [
93
+ { name: "field", label: "field_label", values: ["value1"] },
94
+ ],
95
+ },
96
+ ],
97
+ },
98
+ i18n_content: {
99
+ es: {
100
+ field: "field_label",
101
+ content: { values: ["value1"] },
102
+ completeness: 1.0,
103
+ name: "Concepto1",
104
+ },
105
+ en: {
106
+ field: "field_label",
107
+ content: { values: ["value1"] },
108
+ completeness: 1.0,
109
+ name: "Concept1",
110
+ },
111
+ },
112
+ dynamic_content: {
113
+ field: { value: "value1", origin: "user" },
114
+ },
115
+ },
116
+ };
7
117
 
8
- it("matches the latest snapshot", () => {
9
- const wrapper = shallow(<Concept {...props} />);
10
- expect(wrapper).toMatchSnapshot();
118
+ it("matches the latest snapshot", async () => {
119
+ const { container, queryByText } = render(
120
+ <LangProviderWrapper langs={["es", "en"]}>
121
+ <Concept {...props} />
122
+ </LangProviderWrapper>,
123
+ renderOpts
124
+ );
125
+ await waitFor(() => {
126
+ expect(queryByText(/lazy/i)).not.toBeInTheDocument();
127
+ expect(container.querySelector(".loading")).not.toBeInTheDocument();
128
+ });
129
+ expect(container).toMatchSnapshot();
11
130
  });
12
131
  });