@truedat/dq 4.33.10 → 4.35.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 (96) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/package.json +5 -5
  3. package/src/api.js +7 -1
  4. package/src/components/ConditionSummary.js +23 -21
  5. package/src/components/ExecutionDetails.js +11 -14
  6. package/src/components/ExecutionGroup.js +24 -15
  7. package/src/components/ImplementationResultBar.js +80 -0
  8. package/src/components/ImplementationSummary.js +33 -72
  9. package/src/components/ImplementationsUploadButton.js +61 -0
  10. package/src/components/InformationSummary.js +68 -0
  11. package/src/components/NewRuleImplementation.js +12 -0
  12. package/src/components/RuleForm.js +0 -178
  13. package/src/components/RuleImplementation.js +10 -6
  14. package/src/components/RuleImplementationProperties.js +31 -64
  15. package/src/components/RuleImplementationResults.js +87 -53
  16. package/src/components/RuleImplementationsActions.js +3 -59
  17. package/src/components/RuleImplementationsDownload.js +86 -0
  18. package/src/components/RuleImplementationsOptions.js +28 -0
  19. package/src/components/RuleProperties.js +1 -10
  20. package/src/components/RuleResultDecorator.js +43 -26
  21. package/src/components/RuleResultRow.js +4 -1
  22. package/src/components/RuleResultsUpload.js +47 -0
  23. package/src/components/RuleRoutes.js +0 -13
  24. package/src/components/RuleSummary.js +15 -2
  25. package/src/components/RulesActions.js +17 -10
  26. package/src/components/RulesUploadButton.js +58 -0
  27. package/src/components/__tests__/ExecutionGroup.spec.js +11 -7
  28. package/src/components/__tests__/ImplementationResultBar.spec.js +98 -0
  29. package/src/components/__tests__/ImplementationSummary.spec.js +9 -26
  30. package/src/components/__tests__/InformationSummary.spec.js +35 -0
  31. package/src/components/__tests__/NewRuleImplementation.spec.js +1 -1
  32. package/src/components/__tests__/RuleForm.spec.js +0 -191
  33. package/src/components/__tests__/RuleImplementation.spec.js +1 -0
  34. package/src/components/__tests__/RuleImplementationProperties.spec.js +23 -33
  35. package/src/components/__tests__/RuleImplementationsActions.spec.js +0 -9
  36. package/src/components/__tests__/RuleImplementationsOptions.spec.js +18 -0
  37. package/src/components/__tests__/RuleProperties.spec.js +7 -9
  38. package/src/components/__tests__/RuleResultDecorator.spec.js +17 -11
  39. package/src/components/__tests__/RuleResultRow.spec.js +25 -46
  40. package/src/components/__tests__/RuleResultsUpload.spec.js +18 -0
  41. package/src/components/__tests__/RuleRow.spec.js +0 -4
  42. package/src/components/__tests__/RuleSummary.spec.js +6 -6
  43. package/src/components/__tests__/Rules.spec.js +15 -39
  44. package/src/components/__tests__/__snapshots__/ConditionSummary.spec.js.snap +55 -51
  45. package/src/components/__tests__/__snapshots__/ExecutionGroup.spec.js.snap +5 -4
  46. package/src/components/__tests__/__snapshots__/ImplementationResultBar.spec.js.snap +141 -0
  47. package/src/components/__tests__/__snapshots__/ImplementationSummary.spec.js.snap +194 -457
  48. package/src/components/__tests__/__snapshots__/InformationSummary.spec.js.snap +185 -0
  49. package/src/components/__tests__/__snapshots__/NewRuleImplementation.spec.js.snap +6 -0
  50. package/src/components/__tests__/__snapshots__/RuleForm.spec.js.snap +0 -148
  51. package/src/components/__tests__/__snapshots__/RuleImplementation.spec.js.snap +20 -0
  52. package/src/components/__tests__/__snapshots__/RuleImplementationProperties.spec.js.snap +43 -49
  53. package/src/components/__tests__/__snapshots__/RuleImplementationResults.spec.js.snap +63 -61
  54. package/src/components/__tests__/__snapshots__/RuleImplementationsActions.spec.js.snap +1 -7
  55. package/src/components/__tests__/__snapshots__/RuleImplementationsOptions.spec.js.snap +58 -0
  56. package/src/components/__tests__/__snapshots__/RuleProperties.spec.js.snap +0 -1
  57. package/src/components/__tests__/__snapshots__/RuleResultsUpload.spec.js.snap +18 -0
  58. package/src/components/__tests__/__snapshots__/RuleRow.spec.js.snap +0 -28
  59. package/src/components/__tests__/__snapshots__/Rules.spec.js.snap +0 -101
  60. package/src/components/ruleImplementationForm/FiltersGroup.js +1 -0
  61. package/src/components/ruleImplementationForm/InformationForm.js +5 -5
  62. package/src/components/ruleImplementationForm/LimitsForm.js +142 -0
  63. package/src/components/ruleImplementationForm/RuleImplementationForm.js +14 -4
  64. package/src/components/ruleImplementationForm/RuleImplementationRawForm.js +16 -6
  65. package/src/components/ruleImplementationForm/ValueConditions.js +11 -0
  66. package/src/components/ruleImplementationForm/__tests__/LimitsForm.spec.js +186 -0
  67. package/src/components/ruleImplementationForm/__tests__/RuleImplementationRawForm.spec.js +42 -35
  68. package/src/components/ruleImplementationForm/__tests__/__snapshots__/LimitsForm.spec.js.snap +1104 -0
  69. package/src/components/ruleImplementationForm/__tests__/__snapshots__/RuleImplementationForm.spec.js.snap +4 -1
  70. package/src/components/ruleImplementationForm/__tests__/__snapshots__/RuleImplementationRawForm.spec.js.snap +12 -1
  71. package/src/components/ruleImplementationForm/limitsValidation.js +72 -0
  72. package/src/messages/en.js +167 -76
  73. package/src/messages/es.js +292 -185
  74. package/src/reducers/__tests__/rule.spec.js +2 -4
  75. package/src/reducers/__tests__/ruleImplementation.spec.js +2 -0
  76. package/src/reducers/__tests__/ruleImplementations.spec.js +12 -8
  77. package/src/reducers/__tests__/uploadingResults.spec.js +28 -0
  78. package/src/reducers/dqMessage.js +121 -1
  79. package/src/reducers/index.js +6 -0
  80. package/src/reducers/rule.js +0 -3
  81. package/src/reducers/ruleImplementation.js +3 -0
  82. package/src/reducers/ruleImplementationRedirect.js +6 -1
  83. package/src/reducers/ruleImplementations.js +3 -0
  84. package/src/reducers/ruleRedirect.js +5 -0
  85. package/src/reducers/uploadImplementationsFile.js +28 -0
  86. package/src/reducers/uploadRulesFile.js +25 -0
  87. package/src/reducers/uploadingResults.js +16 -0
  88. package/src/routines.js +3 -0
  89. package/src/sagas/__tests__/uploadResults.spec.js +65 -0
  90. package/src/sagas/index.js +9 -0
  91. package/src/sagas/uploadImplementations.js +28 -0
  92. package/src/sagas/uploadResults.js +32 -0
  93. package/src/sagas/uploadRules.js +28 -0
  94. package/src/selectors/getRuleImplementationColumns.js +38 -3
  95. package/src/selectors/ruleColumnsSelector.js +0 -31
  96. package/src/styles/ruleSummary.less +17 -10
@@ -0,0 +1,186 @@
1
+ import React from "react";
2
+ import { render } from "@truedat/test/render";
3
+ import { fireEvent } from "@testing-library/react";
4
+ import LimitsForm from "../LimitsForm";
5
+ import messages from "../../../messages/en";
6
+
7
+ describe("<LimitsForm />", () => {
8
+ const renderOpts = {
9
+ messages: { en: messages },
10
+ };
11
+
12
+ it("input changes calls onChange prop", () => {
13
+ const onChange = jest.fn();
14
+ const props = {
15
+ ruleImplementation: {
16
+ goal: null,
17
+ minimum: null,
18
+ result_type: "percentage",
19
+ },
20
+ onChange,
21
+ };
22
+
23
+ const { container } = render(<LimitsForm {...props} />, renderOpts);
24
+
25
+ fireEvent.change(container.querySelector("input[name=goal]"), {
26
+ target: { name: "goal", value: "5" },
27
+ });
28
+
29
+ expect(onChange).toBeCalledWith("goal", "5");
30
+ });
31
+
32
+ it("shows required label", () => {
33
+ const props = {
34
+ ruleImplementation: {
35
+ goal: null,
36
+ minimum: null,
37
+ result_type: "percentage",
38
+ },
39
+ onChange: jest.fn(),
40
+ };
41
+
42
+ const { container, getByText } = render(
43
+ <LimitsForm {...props} />,
44
+ renderOpts
45
+ );
46
+ expect(container).toMatchSnapshot();
47
+
48
+ const errorText = "Required field is empty";
49
+ expect(getByText("Goal")).toHaveTextContent(errorText);
50
+ expect(getByText("Threshold")).toHaveTextContent(errorText);
51
+ });
52
+
53
+ it("shows invalid number label", () => {
54
+ const props = {
55
+ ruleImplementation: {
56
+ goal: "text",
57
+ minimum: "text",
58
+ result_type: "percentage",
59
+ },
60
+ onChange: jest.fn(),
61
+ };
62
+
63
+ const { container, getByText } = render(
64
+ <LimitsForm {...props} />,
65
+ renderOpts
66
+ );
67
+ expect(container).toMatchSnapshot();
68
+
69
+ const errorText = "Invalid number format";
70
+ expect(getByText("Goal")).toHaveTextContent(errorText);
71
+ expect(getByText("Threshold")).toHaveTextContent(errorText);
72
+ });
73
+
74
+ it("shows label for percentage goal over 100", () => {
75
+ const props = {
76
+ ruleImplementation: {
77
+ goal: "200",
78
+ minimum: "1",
79
+ result_type: "percentage",
80
+ },
81
+ onChange: jest.fn(),
82
+ };
83
+
84
+ const { container, getByText } = render(
85
+ <LimitsForm {...props} />,
86
+ renderOpts
87
+ );
88
+ expect(container).toMatchSnapshot();
89
+
90
+ const errorText = "Goal percentage cannot be greater than 100";
91
+ expect(getByText("Goal")).toHaveTextContent(errorText);
92
+ });
93
+
94
+ it("shows label for percentage goal greater than minimum", () => {
95
+ const props = {
96
+ ruleImplementation: {
97
+ goal: 20,
98
+ minimum: 30,
99
+ result_type: "percentage",
100
+ },
101
+ onChange: jest.fn(),
102
+ };
103
+
104
+ const { container, getByText } = render(
105
+ <LimitsForm {...props} />,
106
+ renderOpts
107
+ );
108
+ expect(container).toMatchSnapshot();
109
+
110
+ expect(getByText("Goal")).toHaveTextContent(
111
+ "Goal must be greater than (or equal to) the threshold (higher goal is better)."
112
+ );
113
+ expect(getByText("Threshold")).toHaveTextContent(
114
+ "Threshold must be lower than (or equal to) the goal"
115
+ );
116
+ });
117
+
118
+ it("shows label for deviation minimum greater than 100", () => {
119
+ const props = {
120
+ ruleImplementation: {
121
+ goal: "1",
122
+ minimum: "200",
123
+ result_type: "deviation",
124
+ },
125
+ onChange: jest.fn(),
126
+ };
127
+
128
+ const { container, getByText } = render(
129
+ <LimitsForm {...props} />,
130
+ renderOpts
131
+ );
132
+ expect(container).toMatchSnapshot();
133
+
134
+ expect(getByText("Threshold")).toHaveTextContent(
135
+ "Threshold percentage cannot be greater than 100"
136
+ );
137
+ });
138
+
139
+ it("shows label for deviation minimum greater than goal", () => {
140
+ const props = {
141
+ ruleImplementation: {
142
+ goal: "50",
143
+ minimum: "10",
144
+ result_type: "deviation",
145
+ },
146
+ onChange: jest.fn(),
147
+ };
148
+
149
+ const { container, getByText } = render(
150
+ <LimitsForm {...props} />,
151
+ renderOpts
152
+ );
153
+ expect(container).toMatchSnapshot();
154
+
155
+ expect(getByText("Goal")).toHaveTextContent(
156
+ "Goal must be less than (or equal to) the threshold (lower goal is better)"
157
+ );
158
+ expect(getByText("Threshold")).toHaveTextContent(
159
+ "Threshold must greater than (or equal to) the goal"
160
+ );
161
+ });
162
+
163
+ it("shows label for errors_number minimum greater than goal", () => {
164
+ const props = {
165
+ ruleImplementation: {
166
+ goal: "200",
167
+ minimum: "100",
168
+ result_type: "errors_number",
169
+ },
170
+ onChange: jest.fn(),
171
+ };
172
+
173
+ const { container, getByText } = render(
174
+ <LimitsForm {...props} />,
175
+ renderOpts
176
+ );
177
+ expect(container).toMatchSnapshot();
178
+
179
+ expect(getByText("Goal")).toHaveTextContent(
180
+ "Goal must be less than (or equal to) the threshold (lower goal is better)"
181
+ );
182
+ expect(getByText("Threshold")).toHaveTextContent(
183
+ "Threshold must greater than (or equal to) the goal"
184
+ );
185
+ });
186
+ });
@@ -9,7 +9,7 @@ import { RuleImplementationRawForm } from "../RuleImplementationRawForm";
9
9
  jest.spyOn(React, "useContext").mockImplementation(() => intl);
10
10
  jest.mock("react-router-dom", () => ({
11
11
  ...jest.requireActual("react-router-dom"),
12
- useHistory: () => ({ push: jest.fn() })
12
+ useHistory: () => ({ push: jest.fn() }),
13
13
  }));
14
14
 
15
15
  describe("<RuleImplementationRawForm />", () => {
@@ -20,36 +20,42 @@ describe("<RuleImplementationRawForm />", () => {
20
20
  {
21
21
  id: 1,
22
22
  config: { alias: "source1", job_types: ["quality"] },
23
- external_id: "ext_id_1"
23
+ external_id: "ext_id_1",
24
24
  },
25
25
  {
26
26
  id: 2,
27
27
  config: {
28
28
  alias: "source2",
29
29
  job_types: ["quality"],
30
- databases: ["db1", "db2"]
30
+ databases: ["db1", "db2"],
31
31
  },
32
- external_id: "ext_id_2"
32
+ external_id: "ext_id_2",
33
33
  },
34
- { id: 3, config: {}, external_id: "ext_id_3" }
34
+ { id: 3, config: {}, external_id: "ext_id_3" },
35
35
  ];
36
36
  const setImplementationRawContent = jest.fn();
37
37
 
38
38
  const props = {
39
39
  implementationKey: "",
40
40
  setImplementationKey: jest.fn(),
41
- ruleImplementation: { id: 1, executable: true },
41
+ ruleImplementation: {
42
+ id: 1,
43
+ executable: true,
44
+ goal: "10",
45
+ minimum: "1",
46
+ result_type: "percentage",
47
+ },
42
48
  rawContent: {
43
49
  dataset: "",
44
50
  source_id: 1,
45
51
  population: "",
46
- validations: ""
52
+ validations: "",
47
53
  },
48
54
  setImplementationRawContent: setImplementationRawContent,
49
55
  handleSubmit,
50
56
  isSubmitting,
51
57
  sources,
52
- onChange
58
+ onChange,
53
59
  };
54
60
 
55
61
  it("matches the latest snapshot", () => {
@@ -63,8 +69,8 @@ describe("<RuleImplementationRawForm />", () => {
63
69
  rawContent: {
64
70
  dataset: "cliente c join address a on c.address_id=a.id",
65
71
  population: "",
66
- validations: "a.city='MADRID'"
67
- }
72
+ validations: "a.city='MADRID'",
73
+ },
68
74
  };
69
75
 
70
76
  const wrapper = shallow(<RuleImplementationRawForm {...customProps} />);
@@ -79,8 +85,8 @@ describe("<RuleImplementationRawForm />", () => {
79
85
  dataset: "cliente c join address a on c.address_id=a.id",
80
86
  source_id: 2,
81
87
  population: "",
82
- validations: "a.city='MADRID'"
83
- }
88
+ validations: "a.city='MADRID'",
89
+ },
84
90
  };
85
91
 
86
92
  const wrapper = shallow(<RuleImplementationRawForm {...customProps} />);
@@ -95,8 +101,8 @@ describe("<RuleImplementationRawForm />", () => {
95
101
  dataset: "cliente c join address a on c.address_id=a.id",
96
102
  source_id: 1,
97
103
  population: "",
98
- validations: "a.city='MADRID'"
99
- }
104
+ validations: "a.city='MADRID'",
105
+ },
100
106
  };
101
107
 
102
108
  const wrapper = shallow(<RuleImplementationRawForm {...customProps} />);
@@ -112,8 +118,10 @@ describe("<RuleImplementationRawForm />", () => {
112
118
  source_id: 2,
113
119
  database: "db2",
114
120
  population: "",
115
- validations: "a.city='MADRID'"
116
- }
121
+ validations: "a.city='MADRID'",
122
+ },
123
+ template: { id: 1 },
124
+ dfContent: {},
117
125
  };
118
126
  const wrapper = shallow(<RuleImplementationRawForm {...customProps} />);
119
127
  const submitButton = wrapper.find("FormButton[type='submit']");
@@ -127,8 +135,8 @@ describe("<RuleImplementationRawForm />", () => {
127
135
  dataset: "address a on c.address_id=a.id",
128
136
  source_id: 2,
129
137
  population: "",
130
- validations: "a.city='MADRID'"
131
- }
138
+ validations: "a.city='MADRID'",
139
+ },
132
140
  };
133
141
  const wrapper = shallow(<RuleImplementationRawForm {...customProps} />);
134
142
  const submitButton = wrapper.find("FormButton[type='submit']");
@@ -138,12 +146,9 @@ describe("<RuleImplementationRawForm />", () => {
138
146
  it("calls setImplementationRawContent when filling raw content input fields", () => {
139
147
  const wrapper = shallow(<RuleImplementationRawForm {...props} />);
140
148
  expect(setImplementationRawContent.mock.calls).toHaveLength(0);
141
- wrapper
142
- .find("FormTextArea")
143
- .at(0)
144
- .simulate("change", null, {
145
- value: "cliente c join address a on c.address_id=a.id"
146
- });
149
+ wrapper.find("FormTextArea").at(0).simulate("change", null, {
150
+ value: "cliente c join address a on c.address_id=a.id",
151
+ });
147
152
  expect(setImplementationRawContent.mock.calls).toHaveLength(1);
148
153
  });
149
154
 
@@ -151,7 +156,7 @@ describe("<RuleImplementationRawForm />", () => {
151
156
  const setImplementationRawContent = jest.fn();
152
157
  const customProps = {
153
158
  ...props,
154
- setImplementationRawContent
159
+ setImplementationRawContent,
155
160
  };
156
161
  const wrapper = shallow(<RuleImplementationRawForm {...customProps} />);
157
162
 
@@ -160,7 +165,7 @@ describe("<RuleImplementationRawForm />", () => {
160
165
  .find("FormDropdown[name='source_id']")
161
166
  .at(0)
162
167
  .simulate("change", null, {
163
- value: 2
168
+ value: 2,
164
169
  });
165
170
  expect(setImplementationRawContent.mock.calls).toHaveLength(1);
166
171
  expect(setImplementationRawContent).toHaveBeenCalledWith({
@@ -168,7 +173,7 @@ describe("<RuleImplementationRawForm />", () => {
168
173
  dataset: "",
169
174
  population: "",
170
175
  source_id: 2,
171
- validations: ""
176
+ validations: "",
172
177
  });
173
178
  });
174
179
 
@@ -179,8 +184,10 @@ describe("<RuleImplementationRawForm />", () => {
179
184
  dataset: "cliente c join address a on c.address_id=a.id",
180
185
  source_id: 1,
181
186
  population: "",
182
- validations: "a.city='MADRID'"
183
- }
187
+ validations: "a.city='MADRID'",
188
+ },
189
+ template: { id: 1 },
190
+ dfContent: {},
184
191
  };
185
192
  const wrapper = shallow(<RuleImplementationRawForm {...customProps} />);
186
193
  const submitButton = wrapper.find("FormButton[type='submit']");
@@ -193,8 +200,8 @@ describe("<RuleImplementationRawForm />", () => {
193
200
  rawContent: {
194
201
  dataset: "insert into cliente c join address a on c.address_id=a.id",
195
202
  population: "",
196
- validations: "a.city='MADRID'"
197
- }
203
+ validations: "a.city='MADRID'",
204
+ },
198
205
  };
199
206
  const wrapper = shallow(<RuleImplementationRawForm {...customProps} />);
200
207
  const submitButton = wrapper.find("FormButton[type='submit']");
@@ -208,8 +215,8 @@ describe("<RuleImplementationRawForm />", () => {
208
215
  dataset: "insert into cliente c join address a on c.address_id=a.id",
209
216
  source_id: 1,
210
217
  population: "",
211
- validations: "a.city='MADRID'"
212
- }
218
+ validations: "a.city='MADRID'",
219
+ },
213
220
  };
214
221
  const wrapper = shallow(<RuleImplementationRawForm {...customProps} />);
215
222
  const datasetTextArea = wrapper.find("FormTextArea").at(0);
@@ -219,7 +226,7 @@ describe("<RuleImplementationRawForm />", () => {
219
226
  id="ruleImplementationRawForm.rawText.error"
220
227
  values={{ invalid_content: <i>insert</i> }}
221
228
  />
222
- )
229
+ ),
223
230
  });
224
231
  });
225
232
 
@@ -228,7 +235,7 @@ describe("<RuleImplementationRawForm />", () => {
228
235
  const radio = wrapper.find({ name: "executable" }).at(0);
229
236
 
230
237
  radio.simulate("change", null, {
231
- checked: false
238
+ checked: false,
232
239
  });
233
240
 
234
241
  expect(onChange).toHaveBeenCalledWith("executable", false);