@truedat/dq 8.11.4 → 8.11.6

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.
@@ -0,0 +1,168 @@
1
+ import userEvent from "@testing-library/user-event";
2
+ import { render, waitForLoad } from "@truedat/test/render";
3
+ import { multipleTemplatesMock } from "@truedat/test/mocks";
4
+ import { ExecutionTemplateSelector } from "../ExecutionTemplateSelector";
5
+
6
+ const variables = { scope: "qe" };
7
+ const optionalTemplate = {
8
+ __typename: "Template",
9
+ id: "optional",
10
+ name: "optional",
11
+ scope: "qe",
12
+ label: "Optional template",
13
+ content: [
14
+ {
15
+ name: "additional_information",
16
+ fields: [{ name: "notes", label: "Notes" }],
17
+ },
18
+ ],
19
+ };
20
+ const requiredTemplate = {
21
+ ...optionalTemplate,
22
+ id: "required",
23
+ label: "Required template",
24
+ content: [
25
+ {
26
+ name: "additional_information",
27
+ fields: [
28
+ { name: "notes", label: "Notes", type: "string", cardinality: "1" },
29
+ ],
30
+ },
31
+ ],
32
+ };
33
+
34
+ const defaultProps = {
35
+ templates: [],
36
+ template: null,
37
+ content: {},
38
+ onTemplateSelected: jest.fn(),
39
+ onTemplatesLoaded: jest.fn(),
40
+ onContentChange: jest.fn(),
41
+ };
42
+
43
+ const renderSelector = (
44
+ props = {},
45
+ mocks = [multipleTemplatesMock(variables)],
46
+ ) =>
47
+ render(<ExecutionTemplateSelector {...defaultProps} {...props} />, { mocks });
48
+
49
+ describe("<ExecutionTemplateSelector />", () => {
50
+ describe("with multiple templates", () => {
51
+ it("shows the template selector label and combobox", async () => {
52
+ const rendered = renderSelector({
53
+ templates: [optionalTemplate, requiredTemplate],
54
+ });
55
+ await waitForLoad(rendered);
56
+
57
+ expect(rendered.getByText("Select template")).toBeInTheDocument();
58
+ expect(rendered.getByRole("combobox")).toBeInTheDocument();
59
+ });
60
+
61
+ it("shows optional badge when selected template has no mandatory fields", async () => {
62
+ const rendered = renderSelector({
63
+ templates: [optionalTemplate, requiredTemplate],
64
+ template: optionalTemplate,
65
+ });
66
+ await waitForLoad(rendered);
67
+
68
+ expect(rendered.getByText("optional")).toHaveClass("optional-badge");
69
+ });
70
+
71
+ it("shows mandatory badge with pending state when required fields are not filled", async () => {
72
+ const rendered = renderSelector({
73
+ templates: [optionalTemplate, requiredTemplate],
74
+ template: requiredTemplate,
75
+ content: {},
76
+ });
77
+ await waitForLoad(rendered);
78
+
79
+ expect(rendered.getByText("Mandatory fields")).toHaveClass(
80
+ "mandatory-badge",
81
+ "pending",
82
+ );
83
+ });
84
+ });
85
+
86
+ describe("with single template", () => {
87
+ it("hides the selector label", async () => {
88
+ const rendered = renderSelector({
89
+ templates: [optionalTemplate],
90
+ template: optionalTemplate,
91
+ });
92
+ await waitForLoad(rendered);
93
+
94
+ expect(rendered.queryByText("Select template")).not.toBeInTheDocument();
95
+ });
96
+
97
+ it("shows single template label", async () => {
98
+ const rendered = renderSelector({
99
+ templates: [optionalTemplate],
100
+ template: optionalTemplate,
101
+ });
102
+ await waitForLoad(rendered);
103
+
104
+ expect(
105
+ rendered.getByText(
106
+ "Complete the template for additional information (optional)",
107
+ ),
108
+ ).toBeInTheDocument();
109
+ });
110
+ });
111
+
112
+ describe("dynamic form", () => {
113
+ it("shows the dynamic form when a template is selected", async () => {
114
+ const rendered = renderSelector({
115
+ templates: [optionalTemplate],
116
+ template: optionalTemplate,
117
+ });
118
+ await waitForLoad(rendered);
119
+
120
+ expect(rendered.getByText("Template fields")).toBeInTheDocument();
121
+ });
122
+
123
+ it("hides the dynamic form when no template is selected", async () => {
124
+ const rendered = renderSelector({
125
+ templates: [optionalTemplate],
126
+ template: null,
127
+ });
128
+ await waitForLoad(rendered);
129
+
130
+ expect(rendered.queryByText("Template fields")).not.toBeInTheDocument();
131
+ });
132
+ });
133
+
134
+ describe("callbacks", () => {
135
+ it("calls onTemplateSelected when a template is selected", async () => {
136
+ const onTemplateSelected = jest.fn();
137
+ const rendered = renderSelector({
138
+ templates: [optionalTemplate, requiredTemplate],
139
+ onTemplateSelected,
140
+ });
141
+ await waitForLoad(rendered);
142
+ const user = userEvent.setup({ delay: null });
143
+
144
+ await user.click(rendered.getByRole("combobox"));
145
+ const options = rendered.getAllByRole("option");
146
+ await user.click(options[0]);
147
+
148
+ expect(onTemplateSelected).toHaveBeenCalled();
149
+ });
150
+
151
+ it("calls onContentChange when form content changes", async () => {
152
+ const onContentChange = jest.fn();
153
+ const rendered = renderSelector({
154
+ templates: [optionalTemplate],
155
+ template: optionalTemplate,
156
+ onContentChange,
157
+ });
158
+ await waitForLoad(rendered);
159
+ const user = userEvent.setup({ delay: null });
160
+
161
+ const input = rendered.container.querySelector('input[name="notes"]');
162
+ if (input) {
163
+ await user.type(input, "Test content");
164
+ expect(onContentChange).toHaveBeenCalled();
165
+ }
166
+ });
167
+ });
168
+ });
@@ -0,0 +1,40 @@
1
+ import { render } from "@truedat/test/render";
2
+ import { ExecutionWarning } from "../ExecutionWarning";
3
+
4
+ describe("<ExecutionWarning />", () => {
5
+ it("renders the warning message with the count", () => {
6
+ const rendered = render(<ExecutionWarning count={5} />);
7
+
8
+ expect(
9
+ rendered.getByText(/implementations will be executed/i),
10
+ ).toBeInTheDocument();
11
+ expect(rendered.getByText("5")).toHaveClass("count");
12
+ });
13
+
14
+ it("renders the warning icon", () => {
15
+ const rendered = render(<ExecutionWarning count={3} />);
16
+
17
+ expect(rendered.container.querySelector(".warning")).toBeInTheDocument();
18
+ });
19
+
20
+ it("renders the correct CSS class", () => {
21
+ const rendered = render(<ExecutionWarning count={2} />);
22
+
23
+ expect(rendered.container.firstChild).toHaveClass(
24
+ "execution-popup-warning",
25
+ );
26
+ });
27
+
28
+ it("formats the count with bold styling", () => {
29
+ const rendered = render(<ExecutionWarning count={10} />);
30
+
31
+ const countElement = rendered.getByText("10");
32
+ expect(countElement.tagName).toBe("STRONG");
33
+ expect(countElement).toHaveClass("count");
34
+ });
35
+
36
+ it("matches snapshot", () => {
37
+ const rendered = render(<ExecutionWarning count={2} />);
38
+ expect(rendered.container).toMatchSnapshot();
39
+ });
40
+ });
@@ -51,7 +51,7 @@ describe("<RuleImplementation />", () => {
51
51
  });
52
52
  await waitForLoad(rendered);
53
53
  expect(
54
- rendered.getByText(/implementations.actions.do_execution/i),
54
+ rendered.getByText(/implementation.actions.do_execution/i),
55
55
  ).toBeInTheDocument();
56
56
  });
57
57
 
@@ -61,7 +61,7 @@ describe("<RuleImplementation />", () => {
61
61
  });
62
62
  await waitForLoad(rendered);
63
63
  expect(
64
- rendered.queryByText(/implementations.actions.do_execution/i),
64
+ rendered.queryByText(/implementation.actions.do_execution/i),
65
65
  ).not.toBeInTheDocument();
66
66
  });
67
67
  });
@@ -1,102 +1,146 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`<ExecutionForm /> matches the latest snapshot 1`] = `
3
+ exports[`<ExecutionForm /> shows the template selector and the bulk execution warning 1`] = `
4
4
  <div>
5
- <h2
6
- class="ui header"
5
+ <div
6
+ class="header"
7
7
  >
8
- implementations.actions.execution.confirmation.header
9
- </h2>
10
- <form
11
- class="ui form"
8
+ <div
9
+ class="execution-popup-header"
10
+ >
11
+ <div>
12
+ Implementations execution
13
+ <p
14
+ class="subtitle"
15
+ >
16
+ Select template for additional information
17
+ </p>
18
+ </div>
19
+ <button
20
+ aria-label="Close"
21
+ class="close-button"
22
+ type="button"
23
+ >
24
+ ×
25
+ </button>
26
+ </div>
27
+ </div>
28
+ <div
29
+ class="content"
12
30
  >
13
31
  <div
14
- class="field"
32
+ class="execution-popup-template-area"
15
33
  >
16
- <label>
17
- template.selector.label
18
- </label>
34
+ <div
35
+ class="execution-popup-selector-label"
36
+ >
37
+ <span>
38
+ Select template
39
+ </span>
40
+ <span
41
+ class="optional-badge"
42
+ >
43
+ optional
44
+ </span>
45
+ </div>
19
46
  <div
20
47
  class="field"
21
48
  >
22
49
  <div
23
- aria-busy="false"
24
- aria-expanded="false"
25
- class="ui search selection dropdown"
26
- name="template"
27
- role="combobox"
50
+ class="field"
28
51
  >
29
- <input
30
- aria-autocomplete="list"
31
- autocomplete="off"
32
- class="search"
33
- tabindex="0"
34
- type="text"
35
- value=""
36
- />
37
52
  <div
38
- aria-atomic="true"
39
- aria-live="polite"
40
- class="divider default text"
41
- role="alert"
42
- >
43
- template.selector.placeholder
44
- </div>
45
- <i
46
- aria-hidden="true"
47
- class="dropdown icon"
48
- />
49
- <div
50
- class="menu transition"
51
- role="listbox"
53
+ aria-busy="false"
54
+ aria-expanded="false"
55
+ class="ui search selection dropdown"
56
+ name="template"
57
+ role="combobox"
52
58
  >
59
+ <input
60
+ aria-autocomplete="list"
61
+ autocomplete="off"
62
+ class="search"
63
+ tabindex="0"
64
+ type="text"
65
+ value=""
66
+ />
53
67
  <div
54
- aria-checked="false"
55
- aria-selected="true"
56
- class="selected item"
57
- role="option"
58
- style="pointer-events: all;"
68
+ aria-atomic="true"
69
+ aria-live="polite"
70
+ class="divider default text"
71
+ role="alert"
59
72
  >
60
- <span
61
- class="text"
62
- >
63
- template1
64
- </span>
73
+ template.selector.placeholder
65
74
  </div>
75
+ <i
76
+ aria-hidden="true"
77
+ class="dropdown icon"
78
+ />
66
79
  <div
67
- aria-checked="false"
68
- aria-selected="false"
69
- class="item"
70
- role="option"
71
- style="pointer-events: all;"
80
+ class="menu transition"
81
+ role="listbox"
72
82
  >
73
- <span
74
- class="text"
83
+ <div
84
+ aria-checked="false"
85
+ aria-selected="true"
86
+ class="selected item"
87
+ role="option"
88
+ style="pointer-events: all;"
75
89
  >
76
- template2
77
- </span>
90
+ <span
91
+ class="text"
92
+ >
93
+ template1
94
+ </span>
95
+ </div>
96
+ <div
97
+ aria-checked="false"
98
+ aria-selected="false"
99
+ class="item"
100
+ role="option"
101
+ style="pointer-events: all;"
102
+ >
103
+ <span
104
+ class="text"
105
+ >
106
+ template2
107
+ </span>
108
+ </div>
78
109
  </div>
79
110
  </div>
80
111
  </div>
81
112
  </div>
82
113
  </div>
83
- <p>
84
- implementation.actions.execution.confirmation.content
85
- </p>
86
114
  <div
87
- class="actions"
115
+ class="execution-popup-warning"
88
116
  >
89
- <button
90
- class="ui secondary button"
91
- >
92
- actions.cancel
93
- </button>
94
- <button
95
- class="ui primary button"
96
- >
97
- actions.create
98
- </button>
117
+ <i
118
+ aria-hidden="true"
119
+ class="yellow warning sign large icon"
120
+ />
121
+ <p>
122
+ <strong
123
+ class="count"
124
+ >
125
+ 2
126
+ </strong>
127
+ implementations will be executed. Is this correct?
128
+ </p>
99
129
  </div>
100
- </form>
130
+ </div>
131
+ <div
132
+ class="actions"
133
+ >
134
+ <button
135
+ class="ui secondary button"
136
+ >
137
+ Cancel
138
+ </button>
139
+ <button
140
+ class="ui primary button"
141
+ >
142
+ Execute
143
+ </button>
144
+ </div>
101
145
  </div>
102
146
  `;
@@ -2,10 +2,14 @@
2
2
 
3
3
  exports[`<ExecutionPopup /> matches the latest snapshot 1`] = `
4
4
  <div>
5
- <button
6
- class="ui secondary button"
5
+ <div
6
+ class="execution-popup-wrapper"
7
7
  >
8
- do_execution
9
- </button>
8
+ <button
9
+ class="ui primary button"
10
+ >
11
+ do_execution
12
+ </button>
13
+ </div>
10
14
  </div>
11
15
  `;
@@ -0,0 +1,22 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`<ExecutionWarning /> matches snapshot 1`] = `
4
+ <div>
5
+ <div
6
+ class="execution-popup-warning"
7
+ >
8
+ <i
9
+ aria-hidden="true"
10
+ class="yellow warning sign large icon"
11
+ />
12
+ <p>
13
+ <strong
14
+ class="count"
15
+ >
16
+ 2
17
+ </strong>
18
+ implementations will be executed. Is this correct?
19
+ </p>
20
+ </div>
21
+ </div>
22
+ `;
@@ -2,11 +2,15 @@
2
2
 
3
3
  exports[`<ImplementationActions /> matches the snapshot 1`] = `
4
4
  <div>
5
- <button
6
- class="ui secondary button"
5
+ <div
6
+ class="execution-popup-wrapper"
7
7
  >
8
- implementations.actions.do_execution
9
- </button>
8
+ <button
9
+ class="ui primary button"
10
+ >
11
+ implementation.actions.do_execution
12
+ </button>
13
+ </div>
10
14
  <div
11
15
  aria-expanded="false"
12
16
  class="ui floating dropdown button icon group-actions"
@@ -24,13 +24,17 @@ exports[`<ImplementationSearchResults /> matches the latest snapshot 1`] = `
24
24
  for="execute_checkbox"
25
25
  />
26
26
  </div>
27
- <button
28
- class="ui secondary disabled button"
29
- disabled=""
30
- tabindex="-1"
27
+ <div
28
+ class="execution-popup-wrapper"
31
29
  >
32
- implementation.actions.do_execution
33
- </button>
30
+ <button
31
+ class="ui primary disabled button"
32
+ disabled=""
33
+ tabindex="-1"
34
+ >
35
+ implementation.actions.do_execution
36
+ </button>
37
+ </div>
34
38
  <div
35
39
  aria-disabled="false"
36
40
  aria-expanded="false"
@@ -179,11 +183,15 @@ exports[`<ImplementationSearchResults /> renders executions on when executionEna
179
183
  for="execute_checkbox"
180
184
  />
181
185
  </div>
182
- <button
183
- class="ui secondary button"
186
+ <div
187
+ class="execution-popup-wrapper"
184
188
  >
185
- implementation.actions.do_execution
186
- </button>
189
+ <button
190
+ class="ui primary button"
191
+ >
192
+ implementation.actions.do_execution
193
+ </button>
194
+ </div>
187
195
  <div
188
196
  aria-disabled="false"
189
197
  aria-expanded="false"