@truedat/qx 8.4.9 → 8.5.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 (52) hide show
  1. package/package.json +3 -3
  2. package/src/components/common/expressions/Clauses.js +5 -9
  3. package/src/components/common/expressions/Condition.js +36 -37
  4. package/src/components/common/expressions/__tests__/Clauses.spec.js +87 -0
  5. package/src/components/common/expressions/__tests__/Condition.spec.js +220 -1
  6. package/src/components/common/expressions/__tests__/__snapshots__/Clauses.spec.js.snap +22 -21
  7. package/src/components/common/expressions/__tests__/__snapshots__/Condition.spec.js.snap +212 -214
  8. package/src/components/dataViews/queryableProperties/GroupBy.js +4 -2
  9. package/src/components/dataViews/queryableProperties/__tests__/GroupBy.spec.js +134 -28
  10. package/src/components/qualityControls/ControlProperties.js +32 -16
  11. package/src/components/qualityControls/ControlPropertiesForm.js +3 -3
  12. package/src/components/qualityControls/ControlPropertiesSummary.js +127 -104
  13. package/src/components/qualityControls/ControlPropertiesView.js +48 -74
  14. package/src/components/qualityControls/InformationForm.js +181 -180
  15. package/src/components/qualityControls/ScoreCriteria.js +0 -4
  16. package/src/components/qualityControls/ScoreCriteriaView.js +6 -9
  17. package/src/components/qualityControls/__tests__/ControlProperties.spec.js +47 -16
  18. package/src/components/qualityControls/__tests__/ControlPropertiesForm.spec.js +100 -0
  19. package/src/components/qualityControls/__tests__/ControlPropertiesSummary.spec.js +141 -0
  20. package/src/components/qualityControls/__tests__/ControlPropertiesView.spec.js +102 -11
  21. package/src/components/qualityControls/__tests__/EditQualityControl.spec.js +27 -3
  22. package/src/components/qualityControls/__tests__/InformationForm.spec.js +342 -0
  23. package/src/components/qualityControls/__tests__/NewDraftQualityControl.spec.js +26 -6
  24. package/src/components/qualityControls/__tests__/NewQualityControl.spec.js +66 -20
  25. package/src/components/qualityControls/__tests__/QualityBadge.spec.js +30 -3
  26. package/src/components/qualityControls/__tests__/QualityControlEditor.spec.js +282 -45
  27. package/src/components/qualityControls/__tests__/ScoreCriteria.spec.js +25 -3
  28. package/src/components/qualityControls/__tests__/ScoreCriteriaView.spec.js +19 -3
  29. package/src/components/qualityControls/__tests__/__fixtures__/qualityControlHelper.js +1 -1
  30. package/src/components/qualityControls/__tests__/__snapshots__/ControlProperties.spec.js.snap +13 -1
  31. package/src/components/qualityControls/__tests__/__snapshots__/ControlPropertiesView.spec.js.snap +70 -40
  32. package/src/components/qualityControls/__tests__/__snapshots__/EditQualityControl.spec.js.snap +118 -132
  33. package/src/components/qualityControls/__tests__/__snapshots__/NewDraftQualityControl.spec.js.snap +118 -132
  34. package/src/components/qualityControls/__tests__/__snapshots__/NewQualityControl.spec.js.snap +0 -13
  35. package/src/components/qualityControls/__tests__/__snapshots__/QualityBadge.spec.js.snap +15 -5
  36. package/src/components/qualityControls/__tests__/__snapshots__/QualityControlEditor.spec.js.snap +488 -125
  37. package/src/components/qualityControls/__tests__/__snapshots__/ScoreCriteria.spec.js.snap +13 -5
  38. package/src/components/qualityControls/__tests__/qualityByControlMode.spec.js +65 -14
  39. package/src/components/qualityControls/controlProperties/{Ratio.js → ResourceWithValidation.js} +19 -10
  40. package/src/components/qualityControls/controlProperties/__tests__/ResourceWithValidation.spec.js +192 -0
  41. package/src/components/qualityControls/qualityByControlMode.js +6 -30
  42. package/src/components/qualityControls/scoreCriterias/ErrorCount.js +0 -1
  43. package/src/components/qualityControls/scoreCriterias/__tests__/ErrorCount.spec.js +4 -4
  44. package/src/components/dataViews/queryableProperties/__tests__/__snapshots__/GroupBy.spec.js.snap +0 -604
  45. package/src/components/qualityControls/controlProperties/Count.js +0 -56
  46. package/src/components/qualityControls/controlProperties/__tests__/Count.spec.js +0 -66
  47. package/src/components/qualityControls/controlProperties/__tests__/Ratio.spec.js +0 -95
  48. package/src/components/qualityControls/controlProperties/__tests__/__snapshots__/Count.spec.js.snap +0 -67
  49. package/src/components/qualityControls/controlProperties/__tests__/__snapshots__/Ratio.spec.js.snap +0 -161
  50. package/src/components/qualityControls/scoreCriterias/Count.js +0 -88
  51. package/src/components/qualityControls/scoreCriterias/__tests__/Count.spec.js +0 -62
  52. package/src/components/qualityControls/scoreCriterias/__tests__/__snapshots__/Count.spec.js.snap +0 -58
@@ -0,0 +1,342 @@
1
+ import { render, waitForLoad } from "@truedat/test/render";
2
+
3
+ const mockUseFormContext = jest.fn();
4
+ const mockController = jest.fn();
5
+ const mockUseIntl = jest.fn();
6
+ const mockDefaultScoreCriteriaForMode = jest.fn();
7
+ const mockDefaultControlPropertiesForMode = jest.fn();
8
+ const mockSelectableDynamicForm = jest.fn();
9
+
10
+ jest.mock("react-intl", () => ({
11
+ ...jest.requireActual("react-intl"),
12
+ useIntl: () => mockUseIntl(),
13
+ }));
14
+
15
+ jest.mock("react-hook-form", () => ({
16
+ useFormContext: () => mockUseFormContext(),
17
+ Controller: (props) => mockController(props),
18
+ }));
19
+
20
+ jest.mock("@truedat/core/components", () => ({
21
+ DomainSelector: ({ value, onChange }) => (
22
+ <div>
23
+ {`domain-selector-${value?.length || 0}`}
24
+ <button type="button" onClick={() => onChange?.(null, { value: [1, 2] })}>change-domain</button>
25
+ </div>
26
+ ),
27
+ FieldLabel: ({ children, label }) => (
28
+ <div>
29
+ <span>{label}</span>
30
+ {children}
31
+ </div>
32
+ ),
33
+ }));
34
+
35
+ jest.mock("semantic-ui-react", () => ({
36
+ Divider: () => <div>divider</div>,
37
+ Segment: ({ children }) => <div>{children}</div>,
38
+ Form: {
39
+ Radio: ({ label, disabled, checked, onChange }) => (
40
+ <div>
41
+ {`radio-${label}-${disabled}-${checked}`}
42
+ <button type="button" onClick={() => onChange?.(null, { checked: !checked })}>toggle-radio</button>
43
+ </div>
44
+ ),
45
+ Input: ({ value, onChange }) => (
46
+ <div>
47
+ {`input-${value}`}
48
+ <button type="button" onClick={() => onChange?.(null, { value: "new-value" })}>change-input</button>
49
+ </div>
50
+ ),
51
+ Field: ({ children }) => <div>{children}</div>,
52
+ Dropdown: ({ onChange, value }) => (
53
+ <button
54
+ type="button"
55
+ onClick={() => onChange(null, { value: "error_count" })}
56
+ >{`dropdown-${value}`}</button>
57
+ ),
58
+ },
59
+ }));
60
+
61
+ jest.mock("../ScoreCriteria", () => ({
62
+ __esModule: true,
63
+ default: () => <div>score-criteria</div>,
64
+ defaultForMode: (...args) => mockDefaultScoreCriteriaForMode(...args),
65
+ }));
66
+
67
+ jest.mock("../ControlProperties", () => ({
68
+ __esModule: true,
69
+ defaultForMode: (...args) => mockDefaultControlPropertiesForMode(...args),
70
+ }));
71
+
72
+ jest.mock("@truedat/df/components/SelectableDynamicForm", () => ({
73
+ __esModule: true,
74
+ default: (props) => mockSelectableDynamicForm(props),
75
+ }));
76
+
77
+ describe("<InformationForm />", () => {
78
+ const fieldNames = [
79
+ "active",
80
+ "domain_ids",
81
+ "name",
82
+ "df_type",
83
+ "control_mode",
84
+ "score_criteria",
85
+ ];
86
+
87
+ beforeEach(() => {
88
+ jest.clearAllMocks();
89
+
90
+ mockUseIntl.mockReturnValue({
91
+ formatMessage: ({ id }) => id,
92
+ });
93
+
94
+ mockDefaultControlPropertiesForMode.mockReturnValue({
95
+ from: "control-properties",
96
+ });
97
+ mockDefaultScoreCriteriaForMode.mockReturnValue({
98
+ from: "score-criteria",
99
+ });
100
+ });
101
+
102
+ const setupControllers = ({
103
+ values = {},
104
+ errors = {},
105
+ handlers = {},
106
+ } = {}) => {
107
+ mockController.mockImplementation(({ name, render }) =>
108
+ render({
109
+ field: {
110
+ onBlur: jest.fn(),
111
+ onChange: handlers[name] || jest.fn(),
112
+ value: values[name],
113
+ },
114
+ fieldState: {
115
+ error: errors[name],
116
+ },
117
+ })
118
+ );
119
+ };
120
+
121
+ const renderComponent = (props = {}) => {
122
+ const InformationForm = require("../InformationForm").default;
123
+ const setValue = jest.fn();
124
+ const setStepInformation = jest.fn();
125
+ const setValidDfContent = jest.fn();
126
+ const stepInformation = props.stepInformation || {};
127
+
128
+ mockUseFormContext.mockReturnValue({
129
+ control: {},
130
+ watch: () => ({
131
+ dynamic_content: { previous: true },
132
+ domain_ids: [2],
133
+ }),
134
+ setValue,
135
+ });
136
+
137
+ mockSelectableDynamicForm.mockImplementation(({ onChange, name }) => (
138
+ <button
139
+ type="button"
140
+ onClick={() =>
141
+ onChange({
142
+ content: { new: "content" },
143
+ valid: [],
144
+ })
145
+ }
146
+ >{`selectable-df-${name}`}</button>
147
+ ));
148
+
149
+ const rendered = render(
150
+ <InformationForm
151
+ isModification={false}
152
+ setStepInformation={setStepInformation}
153
+ stepInformation={stepInformation}
154
+ setValidDfContent={setValidDfContent}
155
+ {...props}
156
+ />
157
+ );
158
+
159
+ return {
160
+ rendered,
161
+ setValue,
162
+ setStepInformation,
163
+ setValidDfContent,
164
+ };
165
+ };
166
+
167
+ it("renders the main fields and score criteria", async () => {
168
+ setupControllers({
169
+ values: {
170
+ active: true,
171
+ domain_ids: [2],
172
+ name: "quality name",
173
+ df_type: "template_1",
174
+ control_mode: "percentage",
175
+ },
176
+ });
177
+
178
+ const { rendered } = renderComponent();
179
+ await waitForLoad(rendered);
180
+
181
+ expect(rendered.getByText(/radio-quality_control.form.active-false-true/i)).toBeInTheDocument();
182
+ expect(rendered.getByText(/domain-selector-1/i)).toBeInTheDocument();
183
+ expect(rendered.getByText(/input-quality name/i)).toBeInTheDocument();
184
+ expect(rendered.getByText(/selectable-df-template_1/i)).toBeInTheDocument();
185
+ expect(rendered.getByText(/score-criteria/i)).toBeInTheDocument();
186
+ });
187
+
188
+ it("updates step information when field names differ", () => {
189
+ setupControllers({
190
+ values: {
191
+ active: true,
192
+ domain_ids: [],
193
+ name: "",
194
+ df_type: "template_1",
195
+ control_mode: "percentage",
196
+ },
197
+ });
198
+
199
+ const stepInformation = { fieldNames: ["active"] };
200
+ const { setStepInformation } = renderComponent({ stepInformation });
201
+
202
+ expect(setStepInformation).toHaveBeenCalledWith(0, {
203
+ ...stepInformation,
204
+ fieldNames,
205
+ });
206
+ });
207
+
208
+ it("does not update step information when field names are equal", () => {
209
+ setupControllers({
210
+ values: {
211
+ active: true,
212
+ domain_ids: [],
213
+ name: "",
214
+ df_type: "template_1",
215
+ control_mode: "percentage",
216
+ },
217
+ });
218
+
219
+ const { setStepInformation } = renderComponent({
220
+ stepInformation: { fieldNames },
221
+ });
222
+
223
+ expect(setStepInformation).not.toHaveBeenCalled();
224
+ });
225
+
226
+ it("sets dynamic content and valid df flag when selectable form changes", async () => {
227
+ setupControllers({
228
+ values: {
229
+ active: false,
230
+ domain_ids: [],
231
+ name: "a",
232
+ df_type: "template_2",
233
+ control_mode: "deviation",
234
+ },
235
+ });
236
+
237
+ const { rendered, setValue, setValidDfContent } = renderComponent();
238
+
239
+ rendered.getByRole("button", { name: /selectable-df-template_2/i }).click();
240
+
241
+ expect(setValue).toHaveBeenCalledWith("dynamic_content", { new: "content" }, {
242
+ shouldValidate: true,
243
+ shouldDirty: true,
244
+ });
245
+ expect(setValidDfContent).toHaveBeenCalledWith(true);
246
+ });
247
+
248
+ it("updates dependent fields when control mode changes", () => {
249
+ const controlModeOnChange = jest.fn();
250
+ setupControllers({
251
+ values: {
252
+ active: false,
253
+ domain_ids: [],
254
+ name: "a",
255
+ df_type: "template_3",
256
+ control_mode: "percentage",
257
+ },
258
+ handlers: {
259
+ control_mode: controlModeOnChange,
260
+ },
261
+ });
262
+
263
+ const { rendered, setValue } = renderComponent();
264
+
265
+ rendered.getByRole("button", { name: /dropdown-percentage/i }).click();
266
+
267
+ expect(controlModeOnChange).toHaveBeenCalledWith("error_count");
268
+ expect(mockDefaultControlPropertiesForMode).toHaveBeenCalledWith(
269
+ "error_count"
270
+ );
271
+ expect(mockDefaultScoreCriteriaForMode).toHaveBeenCalledWith("error_count");
272
+ expect(setValue).toHaveBeenCalledWith("control_properties", {
273
+ from: "control-properties",
274
+ });
275
+ expect(setValue).toHaveBeenCalledWith("score_criteria", {
276
+ from: "score-criteria",
277
+ });
278
+ });
279
+
280
+ it("active radio onChange passes checked value to field onChange", async () => {
281
+ const activeOnChange = jest.fn();
282
+ setupControllers({
283
+ values: {
284
+ active: true,
285
+ domain_ids: [],
286
+ name: "",
287
+ df_type: "t",
288
+ control_mode: "percentage",
289
+ },
290
+ handlers: { active: activeOnChange },
291
+ });
292
+
293
+ const { rendered } = renderComponent();
294
+ await waitForLoad(rendered);
295
+
296
+ rendered.getByRole("button", { name: /toggle-radio/i }).click();
297
+
298
+ expect(activeOnChange).toHaveBeenCalledWith(false);
299
+ });
300
+
301
+ it("domain_ids onChange passes selected value to field onChange", async () => {
302
+ const domainOnChange = jest.fn();
303
+ setupControllers({
304
+ values: {
305
+ active: false,
306
+ domain_ids: [1],
307
+ name: "",
308
+ df_type: "t",
309
+ control_mode: "percentage",
310
+ },
311
+ handlers: { domain_ids: domainOnChange },
312
+ });
313
+
314
+ const { rendered } = renderComponent();
315
+ await waitForLoad(rendered);
316
+
317
+ rendered.getByRole("button", { name: /change-domain/i }).click();
318
+
319
+ expect(domainOnChange).toHaveBeenCalledWith([1, 2]);
320
+ });
321
+
322
+ it("name input onChange passes value to field onChange", async () => {
323
+ const nameOnChange = jest.fn();
324
+ setupControllers({
325
+ values: {
326
+ active: false,
327
+ domain_ids: [],
328
+ name: "old",
329
+ df_type: "t",
330
+ control_mode: "percentage",
331
+ },
332
+ handlers: { name: nameOnChange },
333
+ });
334
+
335
+ const { rendered } = renderComponent();
336
+ await waitForLoad(rendered);
337
+
338
+ rendered.getByRole("button", { name: /change-input/i }).click();
339
+
340
+ expect(nameOnChange).toHaveBeenCalledWith("new-value");
341
+ });
342
+ });
@@ -1,7 +1,7 @@
1
1
  import userEvent from "@testing-library/user-event";
2
2
  import { waitFor } from "@testing-library/react";
3
3
  import { render, waitForLoad } from "@truedat/test/render";
4
- import { QUALITY_CONTROLS } from "@truedat/core/routes";
4
+ import { QUALITY_CONTROLS, linkTo } from "@truedat/core/routes";
5
5
  import { SOURCE_OPTIONS_QUERY } from "@truedat/cx/sources/api/queries";
6
6
  import { REFERENCE_DATASETS_HEADERS_QUERY } from "@truedat/dd/api/queries";
7
7
  import { DOMAINS_QUERY } from "@truedat/core/api/queries";
@@ -164,7 +164,9 @@ describe("<NewDraftQualityControl />", () => {
164
164
  });
165
165
 
166
166
  // Save button only appears on step 2 (last step)
167
- expect(rendered.queryByRole("button", { name: /save/ })).not.toBeInTheDocument();
167
+ expect(
168
+ rendered.queryByRole("button", { name: /save/ })
169
+ ).not.toBeInTheDocument();
168
170
 
169
171
  const user = userEvent.setup({ delay: null });
170
172
  // Fill step 0 (Information) - make a change to enable save later
@@ -173,7 +175,9 @@ describe("<NewDraftQualityControl />", () => {
173
175
  // Navigate to step 1
174
176
  await user.click(rendered.getByRole("button", { name: /forward/i }));
175
177
  await waitFor(() =>
176
- expect(rendered.getByRole("button", { name: /back/i })).toBeInTheDocument()
178
+ expect(
179
+ rendered.getByRole("button", { name: /back/i })
180
+ ).toBeInTheDocument()
177
181
  );
178
182
 
179
183
  // Navigate to step 2
@@ -195,6 +199,11 @@ describe("<NewDraftQualityControl />", () => {
195
199
  await waitFor(() =>
196
200
  expect(trigger).toHaveBeenCalledWith({ quality_control: qualityControl })
197
201
  );
202
+ await waitFor(() =>
203
+ expect(mockNavigate).toHaveBeenCalledWith(
204
+ linkTo.QUALITY_CONTROL({ id: "9", version: "1" })
205
+ )
206
+ );
198
207
  });
199
208
 
200
209
  it("test publish submit ", async () => {
@@ -214,7 +223,9 @@ describe("<NewDraftQualityControl />", () => {
214
223
  });
215
224
 
216
225
  // Publish button only appears on step 2 (last step)
217
- expect(rendered.queryByRole("button", { name: /publish/ })).not.toBeInTheDocument();
226
+ expect(
227
+ rendered.queryByRole("button", { name: /publish/ })
228
+ ).not.toBeInTheDocument();
218
229
 
219
230
  const user = userEvent.setup({ delay: null });
220
231
  // Fill step 0 (Information) - make a change to enable publish later
@@ -223,13 +234,17 @@ describe("<NewDraftQualityControl />", () => {
223
234
  // Navigate to step 1
224
235
  await user.click(rendered.getByRole("button", { name: /forward/i }));
225
236
  await waitFor(() =>
226
- expect(rendered.getByRole("button", { name: /back/i })).toBeInTheDocument()
237
+ expect(
238
+ rendered.getByRole("button", { name: /back/i })
239
+ ).toBeInTheDocument()
227
240
  );
228
241
 
229
242
  // Navigate to step 2
230
243
  await user.click(rendered.getByRole("button", { name: /forward/i }));
231
244
  await waitFor(() =>
232
- expect(rendered.getByRole("button", { name: /publish/ })).toBeInTheDocument()
245
+ expect(
246
+ rendered.getByRole("button", { name: /publish/ })
247
+ ).toBeInTheDocument()
233
248
  );
234
249
 
235
250
  await waitFor(() =>
@@ -245,6 +260,11 @@ describe("<NewDraftQualityControl />", () => {
245
260
  await waitFor(() =>
246
261
  expect(trigger).toHaveBeenCalledWith({ quality_control: qualityControl })
247
262
  );
263
+ await waitFor(() =>
264
+ expect(mockNavigate).toHaveBeenCalledWith(
265
+ linkTo.QUALITY_CONTROL({ id: "9", version: "1" })
266
+ )
267
+ );
248
268
  });
249
269
 
250
270
  it("when no quality control is fetched, do not render editor", async () => {
@@ -3,6 +3,7 @@ import { act, waitFor } from "@testing-library/react";
3
3
  import { render, waitForLoad } from "@truedat/test/render";
4
4
  import { singleTemplateMock, templateByNameMock } from "@truedat/test/mocks";
5
5
  import { DOMAINS_QUERY } from "@truedat/core/api/queries";
6
+ import { QUALITY_CONTROLS, linkTo } from "@truedat/core/routes";
6
7
  import { SOURCE_OPTIONS_QUERY } from "@truedat/cx/sources/api/queries";
7
8
  import { REFERENCE_DATASETS_HEADERS_QUERY } from "@truedat/dd/api/queries";
8
9
  import { useQualityControlCreate } from "@truedat/qx/hooks/useQualityControls";
@@ -18,7 +19,7 @@ jest.mock("react-router", () => ({
18
19
 
19
20
  jest.mock("@truedat/qx/hooks/useQualityControls", () => ({
20
21
  useQualityControlCreate: jest.fn(() => ({
21
- trigger: jest.fn(() => new Promise(() => { })),
22
+ trigger: jest.fn(() => new Promise(() => {})),
22
23
  isMutating: false,
23
24
  })),
24
25
  }));
@@ -128,7 +129,7 @@ describe("<NewQualityControl />", () => {
128
129
  await user.click(rendered.getByText(/confirmation.yes/i));
129
130
 
130
131
  await waitFor(() => expect(mockNavigate.mock.calls.length).toBe(1));
131
- expect(mockNavigate.mock.calls[0][0]).toBe("/qualityControls");
132
+ expect(mockNavigate.mock.calls[0][0]).toBe(QUALITY_CONTROLS);
132
133
  });
133
134
 
134
135
  it("test save submit ", async () => {
@@ -149,7 +150,9 @@ describe("<NewQualityControl />", () => {
149
150
  });
150
151
 
151
152
  // Save button only appears on step 2 (last step)
152
- expect(rendered.queryByRole("button", { name: /save/i })).not.toBeInTheDocument();
153
+ expect(
154
+ rendered.queryByRole("button", { name: /save/i })
155
+ ).not.toBeInTheDocument();
153
156
 
154
157
  // Fill step 0 (Information)
155
158
  // Select a domain
@@ -186,7 +189,9 @@ describe("<NewQualityControl />", () => {
186
189
  // Navigate to step 1 (Control Properties)
187
190
  await user.click(rendered.getByRole("button", { name: /forward/i }));
188
191
  await waitFor(() =>
189
- expect(rendered.getByRole("button", { name: /back/i })).toBeInTheDocument()
192
+ expect(
193
+ rendered.getByRole("button", { name: /back/i })
194
+ ).toBeInTheDocument()
190
195
  );
191
196
 
192
197
  // Fill step 1 - Source selector is now in step 1
@@ -209,7 +214,9 @@ describe("<NewQualityControl />", () => {
209
214
  // Navigate to step 2 (Segmentation)
210
215
  await user.click(rendered.getByRole("button", { name: /forward/i }));
211
216
  await waitFor(() =>
212
- expect(rendered.getByRole("button", { name: /save/i })).toBeInTheDocument()
217
+ expect(
218
+ rendered.getByRole("button", { name: /save/i })
219
+ ).toBeInTheDocument()
213
220
  );
214
221
 
215
222
  await waitFor(() =>
@@ -297,6 +304,11 @@ describe("<NewQualityControl />", () => {
297
304
  },
298
305
  })
299
306
  );
307
+ await waitFor(() =>
308
+ expect(mockNavigate).toHaveBeenCalledWith(
309
+ linkTo.QUALITY_CONTROL({ id: "9", version: "1" })
310
+ )
311
+ );
300
312
  });
301
313
 
302
314
  it("test publish submit ", async () => {
@@ -317,19 +329,34 @@ describe("<NewQualityControl />", () => {
317
329
  });
318
330
 
319
331
  // Publish button only appears on step 2 (last step)
320
- expect(rendered.queryByRole("button", { name: /publish/i })).not.toBeInTheDocument();
332
+ expect(
333
+ rendered.queryByRole("button", { name: /publish/i })
334
+ ).not.toBeInTheDocument();
321
335
 
322
336
  // Fill step 0 (Information)
323
337
  // Fill in the 'Name' field
324
338
  await user.type(rendered.getByPlaceholderText(/name/i), "test_modified");
325
339
 
326
- // Select a domain
340
+ // Select a domain (template loads and auto-selects when single; dynamic form appears)
327
341
  await user.click(rendered.getByText(/domain.multiple.placeholder/i));
328
342
  await user.click(rendered.getByText(/bardomain/i));
329
343
 
344
+ // Interact with dynamic form so setDfContent runs and validDfContent becomes true (required for Publish)
345
+ await waitFor(() =>
346
+ expect(rendered.getByPlaceholderText(/field1/i)).toBeInTheDocument()
347
+ );
348
+ await user.type(
349
+ rendered.getByPlaceholderText(/field1/i),
350
+ "field_template_modified"
351
+ );
352
+ await waitFor(() => {
353
+ const input = rendered.getByPlaceholderText(/field1/i);
354
+ expect(input).toHaveValue("field_template_modified");
355
+ });
356
+
330
357
  await user.click(
331
358
  rendered.getByRole("option", {
332
- name: /quality_control.control_mode.count/i,
359
+ name: /quality_control.control_mode.error_count/i,
333
360
  })
334
361
  );
335
362
 
@@ -337,7 +364,7 @@ describe("<NewQualityControl />", () => {
337
364
  await waitFor(() => {
338
365
  expect(
339
366
  rendered.getByPlaceholderText(
340
- /quality_control.score_criteria.count.goal/i
367
+ /quality_control.score_criteria.error_count.goal/i
341
368
  )
342
369
  ).toBeInTheDocument();
343
370
  });
@@ -345,14 +372,14 @@ describe("<NewQualityControl />", () => {
345
372
  // Fill in the 'Goal' field
346
373
  await user.type(
347
374
  rendered.getByPlaceholderText(
348
- /quality_control.score_criteria.count.goal/i
375
+ /quality_control.score_criteria.error_count.goal/i
349
376
  ),
350
377
  "25"
351
378
  );
352
379
  // Fill in the 'Threshold' field
353
380
  await user.type(
354
381
  rendered.getByPlaceholderText(
355
- /quality_control.score_criteria.count.maximum/i
382
+ /quality_control.score_criteria.error_count.maximum/i
356
383
  ),
357
384
  "50"
358
385
  );
@@ -360,7 +387,9 @@ describe("<NewQualityControl />", () => {
360
387
  // Navigate to step 1 (Control Properties)
361
388
  await user.click(rendered.getByRole("button", { name: /forward/i }));
362
389
  await waitFor(() =>
363
- expect(rendered.getByRole("button", { name: /back/i })).toBeInTheDocument()
390
+ expect(
391
+ rendered.getByRole("button", { name: /back/i })
392
+ ).toBeInTheDocument()
364
393
  );
365
394
 
366
395
  // Fill step 1 - Source selector is now in step 1
@@ -377,28 +406,40 @@ describe("<NewQualityControl />", () => {
377
406
  );
378
407
  await user.click(rendered.getByRole("option", { name: /dataset1/i }));
379
408
 
409
+ await waitFor(() =>
410
+ expect(
411
+ rendered.getAllByRole("option", { name: /campo1/ }).length
412
+ ).toBeGreaterThan(0)
413
+ );
414
+ await act(async () => {
415
+ await user.click(rendered.getAllByRole("option", { name: /campo1/ })[0]);
416
+ await user.click(rendered.getByRole("option", { name: "eq" }));
417
+ await user.click(rendered.getAllByRole("option", { name: /campo2/ })[1]);
418
+ });
419
+
380
420
  // Navigate to step 2 (Segmentation)
381
421
  await user.click(rendered.getByRole("button", { name: /forward/i }));
382
422
  await waitFor(() =>
383
- expect(rendered.getByRole("button", { name: /publish/i })).toBeInTheDocument()
423
+ expect(
424
+ rendered.getByRole("button", { name: /publish/i })
425
+ ).toBeInTheDocument()
384
426
  );
385
427
 
386
428
  await waitFor(() =>
387
429
  expect(rendered.getByRole("button", { name: /publish/i })).toBeEnabled()
388
430
  );
389
- await user.click(rendered.getByText(/publish/i));
431
+ await user.click(rendered.getByRole("button", { name: /publish/i }));
390
432
 
391
433
  await waitFor(() =>
392
434
  expect(trigger).toHaveBeenCalledWith({
393
- quality_control: {
435
+ quality_control: expect.objectContaining({
394
436
  name: "test_modified",
395
437
  active: true,
396
438
  domain_ids: ["2"],
397
439
  df_type: "template1",
398
440
  source_id: 181,
399
- control_mode: "count",
400
- dynamic_content: {},
401
- control_properties: {
441
+ control_mode: "error_count",
442
+ control_properties: expect.objectContaining({
402
443
  errors_resource: {
403
444
  type: "reference_dataset",
404
445
  id: 7,
@@ -422,11 +463,16 @@ describe("<NewQualityControl />", () => {
422
463
  ],
423
464
  },
424
465
  },
425
- },
466
+ }),
426
467
  score_criteria: { goal: "25", maximum: "50" },
427
468
  status: "published",
428
- },
469
+ }),
429
470
  })
430
471
  );
472
+ await waitFor(() =>
473
+ expect(mockNavigate).toHaveBeenCalledWith(
474
+ linkTo.QUALITY_CONTROL({ id: "9", version: "1" })
475
+ )
476
+ );
431
477
  });
432
478
  });
@@ -109,12 +109,12 @@ describe("<QualityBadgeForSearch />", () => {
109
109
  result: 200,
110
110
  result_message: "under_threshold",
111
111
  status: "succeeded",
112
- type: "count",
112
+ type: "error_count",
113
113
  };
114
114
 
115
115
  const rendered = render(
116
116
  <QualityBadgeForSearch
117
- controlMode={"count"}
117
+ controlMode={"error_count"}
118
118
  criteria={scoreCriteria}
119
119
  latestScore={latestScore}
120
120
  />
@@ -154,7 +154,7 @@ describe("<QualityBadgeForSearch />", () => {
154
154
  };
155
155
  const rendered = render(
156
156
  <QualityBadgeForSearch
157
- controlMode={"count"}
157
+ controlMode={"error_count"}
158
158
  criteria={scoreCriteria}
159
159
  latestScore={latestScore}
160
160
  />
@@ -190,4 +190,31 @@ describe("<QualityBadgeForSearch />", () => {
190
190
 
191
191
  expect(rendered.queryByText(/score.no_results/i)).toBeInTheDocument();
192
192
  });
193
+
194
+ it("matches the latest snapshot for default count mode", async () => {
195
+ const scoreCriteria = {
196
+ goal: 30,
197
+ maximum: 40,
198
+ };
199
+ const latestScore = {
200
+ executed_at: "2025-03-25T05:34:21.438113Z",
201
+ count_content: {
202
+ count: 20,
203
+ },
204
+ result: 20,
205
+ result_message: "under_goal",
206
+ status: "succeeded",
207
+ type: "count",
208
+ };
209
+
210
+ const rendered = render(
211
+ <QualityBadgeForSearch
212
+ controlMode={"count"}
213
+ criteria={scoreCriteria}
214
+ latestScore={latestScore}
215
+ />
216
+ );
217
+ await waitForLoad(rendered);
218
+ expect(rendered.container).toMatchSnapshot();
219
+ });
193
220
  });