@truedat/core 4.44.4 → 4.45.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.44.5] 2022-05-20
4
+
5
+ ### Changed
6
+
7
+ - [TD-4230] `TemplateSelector` GraphQL fetchPolicy changed to
8
+ `cache-and-network` and changed hidden logic
9
+
3
10
  ## [4.44.4] 2022-05-19
4
11
 
5
12
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/core",
3
- "version": "4.44.4",
3
+ "version": "4.45.1",
4
4
  "description": "Truedat Web Core",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -17,23 +17,26 @@
17
17
  "scripts": {
18
18
  "clean": "rimraf yarn-error.log",
19
19
  "debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
20
- "test": "jest --coverage",
21
- "test:watch": "jest --watch",
20
+ "test": "TZ=UTC jest --coverage",
21
+ "test:watch": "TZ=UTC jest --watch",
22
22
  "eslint": "eslint src/**",
23
23
  "eslint:fix": "eslint --fix src/**"
24
24
  },
25
25
  "devDependencies": {
26
- "@babel/cli": "^7.14.8",
27
- "@babel/core": "^7.15.0",
28
- "@babel/plugin-proposal-class-properties": "^7.14.5",
29
- "@babel/plugin-proposal-object-rest-spread": "^7.14.7",
30
- "@babel/plugin-proposal-optional-chaining": "^7.14.5",
26
+ "@babel/cli": "^7.17.10",
27
+ "@babel/core": "^7.18.0",
28
+ "@babel/plugin-proposal-class-properties": "^7.17.12",
29
+ "@babel/plugin-proposal-object-rest-spread": "^7.18.0",
30
+ "@babel/plugin-proposal-optional-chaining": "^7.17.12",
31
31
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
32
- "@babel/plugin-transform-modules-commonjs": "^7.15.0",
33
- "@babel/preset-env": "^7.15.0",
34
- "@babel/preset-react": "^7.14.5",
35
- "@truedat/test": "4.44.4",
36
- "babel-jest": "^27.0.6",
32
+ "@babel/plugin-transform-modules-commonjs": "^7.18.0",
33
+ "@babel/preset-env": "^7.18.0",
34
+ "@babel/preset-react": "^7.17.12",
35
+ "@testing-library/jest-dom": "^5.16.4",
36
+ "@testing-library/react": "^12.0.0",
37
+ "@testing-library/user-event": "^13.2.1",
38
+ "@truedat/test": "4.45.1",
39
+ "babel-jest": "^28.1.0",
37
40
  "babel-plugin-dynamic-import-node": "^2.3.3",
38
41
  "babel-plugin-lodash": "^3.3.4",
39
42
  "babel-plugin-react-intl": "^5.1.18",
@@ -41,7 +44,8 @@
41
44
  "enzyme": "^3.11.0",
42
45
  "enzyme-to-json": "^3.6.2",
43
46
  "identity-obj-proxy": "^3.0.0",
44
- "jest": "^27.0.6",
47
+ "jest": "^28.1.0",
48
+ "jest-environment-jsdom": "^28.1.0",
45
49
  "jest-localstorage-mock": "^2.4.14",
46
50
  "react": "^16.14.0",
47
51
  "react-dom": "^16.14.0",
@@ -50,6 +54,8 @@
50
54
  "semantic-ui-react": "^2.0.3"
51
55
  },
52
56
  "jest": {
57
+ "maxWorkers": "50%",
58
+ "testTimeout": 10000,
53
59
  "moduleDirectories": [
54
60
  "<rootDir>/src",
55
61
  "../../node_modules"
@@ -82,16 +88,16 @@
82
88
  }
83
89
  },
84
90
  "dependencies": {
85
- "@apollo/client": "^3.4.10",
91
+ "@apollo/client": "^3.6.4",
86
92
  "axios": "^0.19.2",
87
93
  "immutable": "^4.0.0-rc.12",
88
94
  "is-hotkey": "^0.1.6",
89
95
  "is-url": "^1.2.4",
90
- "prop-types": "^15.7.2",
96
+ "prop-types": "^15.8.1",
91
97
  "react-csv": "^2.2.2",
92
98
  "react-dropzone": "^4.2.13",
93
99
  "react-intl": "^5.20.10",
94
- "react-moment": "^0.9.7",
100
+ "react-moment": "^1.1.2",
95
101
  "react-redux": "^7.2.4",
96
102
  "react-router-dom": "^5.2.0",
97
103
  "redux": "^4.1.1",
@@ -106,5 +112,5 @@
106
112
  "react-dom": ">= 16.8.6 < 17",
107
113
  "semantic-ui-react": ">= 0.88.2 < 2.1"
108
114
  },
109
- "gitHead": "36fb183e1d22181e6a15b3bac2c01b39214eacdb"
115
+ "gitHead": "c13f37ee357bf4a5e8c8c99eb6bd0c798f468c49"
110
116
  }
@@ -11,8 +11,8 @@ export const DOMAINS_QUERY = gql`
11
11
  `;
12
12
 
13
13
  export const TEMPLATES_QUERY = gql`
14
- query Templates($scope: String!) {
15
- templates(scope: $scope) {
14
+ query Templates($scope: String, $domainIds: [ID]) {
15
+ templates(scope: $scope, domainIds: $domainIds) {
16
16
  id
17
17
  name
18
18
  label
@@ -27,7 +27,7 @@ export const TemplateSelector = ({
27
27
  }) => {
28
28
  const { formatMessage } = useIntl();
29
29
  const options = makeOptions(templates);
30
- const hidden = _.size(templates) <= 1;
30
+ const hidden = loading ? false : _.size(templates) <= 1;
31
31
 
32
32
  const handleChange = (e, { value, ...data }) => {
33
33
  const template = _.find({ id: value })(templates);
@@ -50,7 +50,9 @@ export const TemplateSelector = ({
50
50
  name={name}
51
51
  onChange={handleChange}
52
52
  options={options}
53
- placeholder={formatMessage({ id: "template.selector.placeholder" })}
53
+ placeholder={formatMessage({
54
+ id: loading ? "loading" : "template.selector.placeholder",
55
+ })}
54
56
  search
55
57
  selection
56
58
  value={_.toString(selectedValue)}
@@ -69,19 +71,27 @@ TemplateSelector.propTypes = {
69
71
  templates: PropTypes.array,
70
72
  };
71
73
 
72
- export const TemplateSelectorLoader = ({ scope, onLoad, ...props }) => {
74
+ const emptyTemplates = [];
75
+ export const TemplateSelectorLoader = ({
76
+ scope,
77
+ onLoad,
78
+ domainIds,
79
+ ...props
80
+ }) => {
73
81
  const { loading, error, data } = useQuery(TEMPLATES_QUERY, {
74
- variables: { scope },
82
+ fetchPolicy: "cache-and-network",
83
+ variables: { scope, domainIds },
75
84
  onCompleted: onLoad,
76
85
  });
77
86
  if (error) return null;
78
- const templates = data?.templates || [];
87
+ const templates = data?.templates || emptyTemplates;
79
88
  return (
80
89
  <TemplateSelector loading={loading} templates={templates} {...props} />
81
90
  );
82
91
  };
83
92
 
84
93
  TemplateSelectorLoader.propTypes = {
94
+ domainIds: PropTypes.array,
85
95
  scope: PropTypes.string.isRequired,
86
96
  onLoad: PropTypes.func,
87
97
  };
@@ -1,10 +1,12 @@
1
1
  import React from "react";
2
- import { shallow } from "enzyme";
2
+ import { render } from "@truedat/test/render";
3
3
  import { DateTime } from "..";
4
4
 
5
5
  describe("<DateTime />", () => {
6
6
  it("matches the latest snapshot", () => {
7
- const wrapper = shallow(<DateTime value="2018-06-27T07:32:53.154377Z" />);
8
- expect(wrapper).toMatchSnapshot();
7
+ const { container } = render(
8
+ <DateTime value="2018-06-27T07:32:53.154377Z" />
9
+ );
10
+ expect(container).toMatchSnapshot();
9
11
  });
10
12
  });
@@ -1,51 +1,80 @@
1
- import React, { Suspense } from "react";
2
- import { waitFor } from "@testing-library/react";
1
+ import React from "react";
2
+ import { waitForElementToBeRemoved } from "@testing-library/react";
3
+ import userEvent from "@testing-library/user-event";
3
4
  import { render } from "@truedat/test/render";
4
- import { TEMPLATES_QUERY } from "@truedat/core/api/queries";
5
+ import {
6
+ errorTemplateMock,
7
+ multipleTemplatesMock,
8
+ singleTemplateMock,
9
+ } from "@truedat/test/mocks";
5
10
  import TemplateSelector from "../TemplateSelector";
6
11
 
7
12
  const scope = "foo";
8
- const templates = [
9
- {
10
- id: "1",
11
- name: "template1",
12
- label: "template1",
13
- content: [{ name: "g1", fields: [{ name: "field1", label: "field1" }] }],
14
- scope,
15
- },
16
- {
17
- id: "2",
18
- name: "template2",
19
- label: "template2",
20
- content: {},
21
- scope,
22
- },
23
- ];
24
- const templatesMock = {
25
- request: { query: TEMPLATES_QUERY, variables: { scope } },
26
- result: { data: { templates } },
27
- };
28
-
29
- const renderOpts = {
30
- mocks: [templatesMock],
31
- };
13
+ const domainIds = [1];
14
+ const variables = { scope, domainIds };
32
15
 
33
16
  describe("<TemplateSelector />", () => {
34
17
  const onChange = jest.fn();
35
- const onLoad = jest.fn();
36
- const props = { onChange, onLoad, scope: "foo" };
18
+ const props = { onChange, domainIds, scope };
19
+
20
+ it("matches the latest snapshot (loading)", () => {
21
+ const renderOpts = { mocks: [multipleTemplatesMock(variables)] };
22
+ const { container, queryByText } = render(
23
+ <TemplateSelector {...props} />,
24
+ renderOpts
25
+ );
26
+ expect(queryByText(/loading/i)).toBeInTheDocument();
27
+ expect(container).toMatchSnapshot();
28
+ });
37
29
 
38
30
  it("matches the latest snapshot", async () => {
31
+ const renderOpts = { mocks: [multipleTemplatesMock(variables)] };
32
+ const onLoad = jest.fn();
39
33
  const { container, queryByText } = render(
40
- <Suspense fallback="loading...">
41
- <TemplateSelector {...props} />
42
- </Suspense>,
34
+ <TemplateSelector {...props} onLoad={onLoad} />,
43
35
  renderOpts
44
36
  );
45
- await waitFor(() => {
46
- expect(queryByText(/template1/i)).toBeInTheDocument();
47
- });
37
+ await waitForElementToBeRemoved(() => queryByText(/loading/i));
38
+ expect(queryByText("template1")).toBeInTheDocument();
48
39
  expect(container).toMatchSnapshot();
49
40
  expect(onLoad.mock.calls.length).toBe(1);
50
41
  });
42
+
43
+ it("matches the latest snapshot when required", async () => {
44
+ const renderOpts = { mocks: [multipleTemplatesMock(variables)] };
45
+ const { container, queryByText } = render(
46
+ <TemplateSelector {...props} required />,
47
+ renderOpts
48
+ );
49
+ await waitForElementToBeRemoved(() => queryByText(/loading/i));
50
+ expect(queryByText("template1")).toBeInTheDocument();
51
+ expect(container).toMatchSnapshot();
52
+ });
53
+
54
+ it("is empty if templates query returns an error", async () => {
55
+ const renderOpts = { mocks: [errorTemplateMock(variables)] };
56
+ const { queryByText } = render(
57
+ <TemplateSelector {...props} required />,
58
+ renderOpts
59
+ );
60
+ await waitForElementToBeRemoved(() => queryByText(/loading/i));
61
+ expect(queryByText("template1")).not.toBeInTheDocument();
62
+ });
63
+
64
+ it("calls onChange when template is selected", async () => {
65
+ const renderOpts = { mocks: [multipleTemplatesMock(variables)] };
66
+ const { findByRole } = render(<TemplateSelector {...props} />, renderOpts);
67
+
68
+ userEvent.click(await findByRole("option", { name: "template1" }));
69
+ expect(onChange.mock.calls[0][1]).toMatchObject({
70
+ template: { id: "1", label: "template1" },
71
+ });
72
+ });
73
+
74
+ it("is empty when query returns a single template", async () => {
75
+ const renderOpts = { mocks: [singleTemplateMock(variables)] };
76
+ const { queryByText } = render(<TemplateSelector {...props} />, renderOpts);
77
+ await waitForElementToBeRemoved(() => queryByText(/loading/i));
78
+ expect(queryByText("template1")).not.toBeInTheDocument();
79
+ });
51
80
  });
@@ -1,23 +1,11 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`<DateTime /> matches the latest snapshot 1`] = `
4
- <t
5
- ago={false}
6
- calendar={false}
7
- date="2018-06-27T07:32:53.154377Z"
8
- decimal={false}
9
- element={null}
10
- filter={[Function]}
11
- format="YYYY-MM-DD HH:mm"
12
- fromNow={false}
13
- interval={60000}
14
- local={false}
15
- onChange={[Function]}
16
- titleFormat=""
17
- toNow={false}
18
- unit={null}
19
- unix={false}
20
- utc={false}
21
- withTitle={false}
22
- />
4
+ <div>
5
+ <time
6
+ datetime="1530084773154"
7
+ >
8
+ 2018-06-27 07:32
9
+ </time>
10
+ </div>
23
11
  `;
@@ -1,5 +1,59 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
+ exports[`<TemplateSelector /> matches the latest snapshot (loading) 1`] = `
4
+ <div>
5
+ <div
6
+ class="field"
7
+ >
8
+ <label>
9
+ Template
10
+ </label>
11
+ <div
12
+ class="field"
13
+ >
14
+ <div
15
+ aria-busy="true"
16
+ aria-expanded="false"
17
+ class="ui loading search selection dropdown"
18
+ name="template"
19
+ role="combobox"
20
+ >
21
+ <input
22
+ aria-autocomplete="list"
23
+ autocomplete="off"
24
+ class="search"
25
+ tabindex="0"
26
+ type="text"
27
+ value=""
28
+ />
29
+ <div
30
+ aria-atomic="true"
31
+ aria-live="polite"
32
+ class="divider default text"
33
+ role="alert"
34
+ >
35
+ loading...
36
+ </div>
37
+ <i
38
+ aria-hidden="true"
39
+ class="dropdown icon"
40
+ />
41
+ <div
42
+ class="menu transition"
43
+ role="listbox"
44
+ >
45
+ <div
46
+ class="message"
47
+ >
48
+ No results found.
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ `;
56
+
3
57
  exports[`<TemplateSelector /> matches the latest snapshot 1`] = `
4
58
  <div>
5
59
  <div
@@ -74,3 +128,83 @@ exports[`<TemplateSelector /> matches the latest snapshot 1`] = `
74
128
  </div>
75
129
  </div>
76
130
  `;
131
+
132
+ exports[`<TemplateSelector /> matches the latest snapshot when required 1`] = `
133
+ <div>
134
+ <div
135
+ class="required field"
136
+ >
137
+ <label>
138
+ Template
139
+ <div
140
+ class="ui left pointing label"
141
+ >
142
+ Empty required field
143
+ </div>
144
+ </label>
145
+ <div
146
+ class="field"
147
+ >
148
+ <div
149
+ aria-busy="false"
150
+ aria-expanded="false"
151
+ class="ui search selection dropdown"
152
+ name="template"
153
+ role="combobox"
154
+ >
155
+ <input
156
+ aria-autocomplete="list"
157
+ autocomplete="off"
158
+ class="search"
159
+ tabindex="0"
160
+ type="text"
161
+ value=""
162
+ />
163
+ <div
164
+ aria-atomic="true"
165
+ aria-live="polite"
166
+ class="divider default text"
167
+ role="alert"
168
+ >
169
+ Select a template...
170
+ </div>
171
+ <i
172
+ aria-hidden="true"
173
+ class="dropdown icon"
174
+ />
175
+ <div
176
+ class="menu transition"
177
+ role="listbox"
178
+ >
179
+ <div
180
+ aria-checked="false"
181
+ aria-selected="true"
182
+ class="selected item"
183
+ role="option"
184
+ style="pointer-events: all;"
185
+ >
186
+ <span
187
+ class="text"
188
+ >
189
+ template1
190
+ </span>
191
+ </div>
192
+ <div
193
+ aria-checked="false"
194
+ aria-selected="false"
195
+ class="item"
196
+ role="option"
197
+ style="pointer-events: all;"
198
+ >
199
+ <span
200
+ class="text"
201
+ >
202
+ template2
203
+ </span>
204
+ </div>
205
+ </div>
206
+ </div>
207
+ </div>
208
+ </div>
209
+ </div>
210
+ `;
@@ -45,6 +45,7 @@ export default {
45
45
  filters: "Filters",
46
46
  "filters.class.raw.field": "Field",
47
47
  "filters.reset": "(reset all filters)",
48
+ loading: "loading...",
48
49
  "form.validation.required": "{prop} is required",
49
50
  "form.validation.minLength": "{prop} must have at least {value} characters",
50
51
  "form.validation.email.invalid": "Invalid email address",
@@ -49,6 +49,7 @@ export default {
49
49
  "form.validation.required": "{prop} es un campo requerido",
50
50
  "form.validation.minLength": "{prop} debe tener al menos {value} elementos",
51
51
  "form.validation.email.invalid": "Dirección de email inválida",
52
+ loading: "cargando...",
52
53
  "navigation.dashboard": "Dashboard",
53
54
  "navigation.menu": "Menú",
54
55
  "search.applied_filters": "Filtros aplicados:",