@dynatrace/strato-components-testing 1.18.0 → 3.0.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.
Files changed (117) hide show
  1. package/esm/jest/index.js +102 -3
  2. package/esm/jest/index.js.map +2 -2
  3. package/esm/jest/mocks/create-mock-element.js +81 -0
  4. package/esm/jest/mocks/create-mock-element.js.map +7 -0
  5. package/esm/jest/mocks/create-range-mock.js +28 -0
  6. package/esm/jest/mocks/create-range-mock.js.map +7 -0
  7. package/esm/jest/mocks/crypto-mock.js +20 -0
  8. package/esm/jest/mocks/crypto-mock.js.map +7 -0
  9. package/esm/jest/mocks/dom-rect-mock.js.map +2 -2
  10. package/esm/jest/mocks/element-from-point-mock.js +12 -0
  11. package/esm/jest/mocks/element-from-point-mock.js.map +7 -0
  12. package/esm/jest/mocks/fetch-mock.js +20 -0
  13. package/esm/jest/mocks/fetch-mock.js.map +7 -0
  14. package/esm/jest/mocks/framer-motion-mock.js +59 -0
  15. package/esm/jest/mocks/framer-motion-mock.js.map +7 -0
  16. package/esm/jest/mocks/intersection-observer-mock.js +40 -0
  17. package/esm/jest/mocks/intersection-observer-mock.js.map +7 -0
  18. package/esm/jest/mocks/match-media-mock.js +27 -0
  19. package/esm/jest/mocks/match-media-mock.js.map +7 -0
  20. package/esm/jest/mocks/offset-height-mock.js +21 -0
  21. package/esm/jest/mocks/offset-height-mock.js.map +7 -0
  22. package/esm/jest/mocks/offset-width-mock.js +21 -0
  23. package/esm/jest/mocks/offset-width-mock.js.map +7 -0
  24. package/esm/jest/mocks/pointer-event-mock.js +24 -0
  25. package/esm/jest/mocks/pointer-event-mock.js.map +7 -0
  26. package/esm/jest/mocks/screen-size-mock.js +16 -0
  27. package/esm/jest/mocks/screen-size-mock.js.map +7 -0
  28. package/esm/jest/mocks/scroll-into-view-mock.js +16 -0
  29. package/esm/jest/mocks/scroll-into-view-mock.js.map +7 -0
  30. package/esm/jest/mocks/streamdown.mock.js +8 -0
  31. package/esm/jest/mocks/streamdown.mock.js.map +7 -0
  32. package/esm/jest/mocks/table-virtualization-mock.js +87 -0
  33. package/esm/jest/mocks/table-virtualization-mock.js.map +7 -0
  34. package/esm/jest/mocks/virtualization-mock.js +155 -0
  35. package/esm/jest/mocks/virtualization-mock.js.map +7 -0
  36. package/esm/jest/preset/jest-preset.js +2 -1
  37. package/esm/jest/preset/jest-preset.js.map +2 -2
  38. package/esm/jest/setup/index.js +51 -0
  39. package/esm/jest/setup/index.js.map +2 -2
  40. package/esm/jest/testing-helpers/filters/filter-field.js +424 -0
  41. package/esm/jest/testing-helpers/filters/filter-field.js.map +7 -0
  42. package/esm/jest/testing-helpers/forms/base-input.js +32 -0
  43. package/esm/jest/testing-helpers/forms/base-input.js.map +7 -0
  44. package/esm/jest/testing-helpers/forms/password-input.js +29 -0
  45. package/esm/jest/testing-helpers/forms/password-input.js.map +7 -0
  46. package/esm/jest/testing-helpers/forms/search-input.js +27 -0
  47. package/esm/jest/testing-helpers/forms/search-input.js.map +7 -0
  48. package/esm/jest/testing-helpers/forms/select.js +131 -0
  49. package/esm/jest/testing-helpers/forms/select.js.map +7 -0
  50. package/esm/jest/testing-helpers/forms/text-input.js +24 -0
  51. package/esm/jest/testing-helpers/forms/text-input.js.map +7 -0
  52. package/esm/jest/testing-helpers/tables/datatable.js +794 -0
  53. package/esm/jest/testing-helpers/tables/datatable.js.map +7 -0
  54. package/esm/jest/testing-helpers/utils/isFakeTimersEnabled.js +9 -0
  55. package/esm/jest/testing-helpers/utils/isFakeTimersEnabled.js.map +7 -0
  56. package/esm/jest/testing-helpers/utils/setup-user-event.js +15 -0
  57. package/esm/jest/testing-helpers/utils/setup-user-event.js.map +7 -0
  58. package/jest/index.d.ts +22 -1
  59. package/jest/index.js +54 -3
  60. package/jest/mocks/create-mock-element.d.ts +15 -0
  61. package/jest/mocks/create-mock-element.js +99 -0
  62. package/jest/mocks/create-range-mock.d.ts +11 -0
  63. package/jest/mocks/create-range-mock.js +46 -0
  64. package/jest/mocks/crypto-mock.d.ts +12 -0
  65. package/jest/mocks/crypto-mock.js +48 -0
  66. package/jest/mocks/dom-rect-mock.d.ts +1 -0
  67. package/jest/mocks/element-from-point-mock.d.ts +11 -0
  68. package/jest/{setup.js → mocks/element-from-point-mock.js} +10 -16
  69. package/jest/mocks/fetch-mock.d.ts +10 -0
  70. package/jest/mocks/fetch-mock.js +38 -0
  71. package/jest/mocks/framer-motion-mock.d.ts +18 -0
  72. package/jest/mocks/framer-motion-mock.js +75 -0
  73. package/jest/mocks/intersection-observer-mock.d.ts +11 -0
  74. package/jest/mocks/intersection-observer-mock.js +58 -0
  75. package/jest/mocks/match-media-mock.d.ts +11 -0
  76. package/jest/mocks/match-media-mock.js +45 -0
  77. package/jest/mocks/offset-height-mock.d.ts +10 -0
  78. package/jest/mocks/offset-height-mock.js +39 -0
  79. package/jest/mocks/offset-width-mock.d.ts +10 -0
  80. package/jest/mocks/offset-width-mock.js +39 -0
  81. package/jest/mocks/pointer-event-mock.d.ts +10 -0
  82. package/jest/mocks/pointer-event-mock.js +42 -0
  83. package/jest/mocks/screen-size-mock.d.ts +10 -0
  84. package/jest/mocks/screen-size-mock.js +34 -0
  85. package/jest/mocks/scroll-into-view-mock.d.ts +10 -0
  86. package/jest/mocks/scroll-into-view-mock.js +34 -0
  87. package/jest/mocks/streamdown.mock.d.ts +2 -0
  88. package/jest/mocks/streamdown.mock.js +26 -0
  89. package/jest/mocks/table-virtualization-mock.d.ts +15 -0
  90. package/jest/mocks/table-virtualization-mock.js +102 -0
  91. package/jest/mocks/virtualization-mock.d.ts +9 -0
  92. package/jest/mocks/virtualization-mock.js +170 -0
  93. package/jest/preset/jest-preset.d.ts +2 -3
  94. package/jest/preset/jest-preset.js +2 -1
  95. package/jest/setup/index.js +27 -0
  96. package/jest/testing-helpers/filters/filter-field.d.ts +109 -0
  97. package/jest/testing-helpers/filters/filter-field.js +436 -0
  98. package/jest/testing-helpers/forms/base-input.d.ts +17 -0
  99. package/jest/testing-helpers/forms/base-input.js +50 -0
  100. package/jest/testing-helpers/forms/password-input.d.ts +16 -0
  101. package/jest/testing-helpers/forms/password-input.js +47 -0
  102. package/jest/testing-helpers/forms/search-input.d.ts +20 -0
  103. package/jest/testing-helpers/forms/search-input.js +45 -0
  104. package/jest/testing-helpers/forms/select.d.ts +65 -0
  105. package/jest/testing-helpers/forms/select.js +159 -0
  106. package/jest/testing-helpers/forms/text-input.d.ts +19 -0
  107. package/jest/testing-helpers/forms/text-input.js +42 -0
  108. package/jest/testing-helpers/tables/datatable.d.ts +239 -0
  109. package/jest/testing-helpers/tables/datatable.js +812 -0
  110. package/jest/testing-helpers/utils/isFakeTimersEnabled.d.ts +5 -0
  111. package/jest/testing-helpers/utils/isFakeTimersEnabled.js +27 -0
  112. package/jest/testing-helpers/utils/setup-user-event.d.ts +6 -0
  113. package/jest/testing-helpers/utils/setup-user-event.js +43 -0
  114. package/package.json +11 -3
  115. package/esm/jest/setup.js +0 -24
  116. package/esm/jest/setup.js.map +0 -7
  117. package/jest/setup.d.ts +0 -14
@@ -0,0 +1,424 @@
1
+ import {
2
+ act,
3
+ screen,
4
+ waitFor,
5
+ waitForElementToBeRemoved,
6
+ within
7
+ } from "@testing-library/react";
8
+ import { PointerEventsCheckLevel } from "@testing-library/user-event";
9
+ import { isFakeTimersEnabled } from "../utils/isFakeTimersEnabled.js";
10
+ import { setupUserEvent } from "../utils/setup-user-event.js";
11
+ class FilterFieldPinnedAndRecentSuggestionBase {
12
+ constructor(suggestionRoot) {
13
+ this.suggestionRoot = suggestionRoot;
14
+ }
15
+ get pinButtonElement() {
16
+ return this.suggestionRoot.querySelector(
17
+ "button[aria-checked]"
18
+ );
19
+ }
20
+ /**
21
+ * Receives the value of the suggestion that would be applied.
22
+ */
23
+ get value() {
24
+ return this.suggestionRoot.childNodes.item(1).textContent;
25
+ }
26
+ /**
27
+ * Returns if the current suggestion is currently pinned or not.
28
+ */
29
+ get pinned() {
30
+ if (this.pinButtonElement) {
31
+ return this.pinButtonElement.getAttribute("aria-checked") === "true";
32
+ }
33
+ return false;
34
+ }
35
+ /**
36
+ * Applies the suggestion to the filter field.
37
+ */
38
+ async apply() {
39
+ await setupUserEvent({
40
+ pointerEventsCheck: PointerEventsCheckLevel.Never
41
+ }).click(this.suggestionRoot);
42
+ }
43
+ get pinEnabled() {
44
+ if (this.pinButtonElement) {
45
+ return this.pinButtonElement.getAttribute("aria-disabled") === "false";
46
+ }
47
+ return false;
48
+ }
49
+ /**
50
+ * Allows the suggestion to be pinned if not pinned already.
51
+ */
52
+ async pin() {
53
+ if (this.pinned === true) {
54
+ return;
55
+ }
56
+ if (this.pinButtonElement) {
57
+ await setupUserEvent({
58
+ pointerEventsCheck: PointerEventsCheckLevel.Never
59
+ }).click(this.pinButtonElement);
60
+ if (isFakeTimersEnabled()) {
61
+ await act(async () => {
62
+ jest.runOnlyPendingTimers();
63
+ });
64
+ }
65
+ }
66
+ }
67
+ /**
68
+ * Allows the suggestion to be unpinned if not unpinned already.
69
+ */
70
+ async unpin() {
71
+ if (this.pinned === false) {
72
+ return;
73
+ }
74
+ if (this.pinButtonElement) {
75
+ await setupUserEvent({
76
+ pointerEventsCheck: PointerEventsCheckLevel.Never
77
+ }).click(this.pinButtonElement);
78
+ if (isFakeTimersEnabled()) {
79
+ await act(async () => {
80
+ jest.runOnlyPendingTimers();
81
+ });
82
+ }
83
+ }
84
+ }
85
+ }
86
+ class FilterFieldPinnedSuggestion extends FilterFieldPinnedAndRecentSuggestionBase {
87
+ /**
88
+ * Receives the value of the suggestion that would be applied.
89
+ */
90
+ get value() {
91
+ return this.suggestionRoot.childNodes.item(0).textContent;
92
+ }
93
+ }
94
+ class FilterFieldRecentSuggestion extends FilterFieldPinnedAndRecentSuggestionBase {
95
+ /**
96
+ * Receives the value of the suggestion that would be applied.
97
+ */
98
+ get value() {
99
+ return this.suggestionRoot.querySelector('[role="option"]')?.childNodes.item(0).textContent ?? null;
100
+ }
101
+ /**
102
+ * Receives time offset indicating when the filter statement has last been used.
103
+ */
104
+ get lastUsed() {
105
+ return this.suggestionRoot.querySelector('[role="option"]')?.childNodes.item(1).textContent ?? null;
106
+ }
107
+ }
108
+ class FilterFieldHelper {
109
+ constructor(dataTestId) {
110
+ this.dataTestId = dataTestId;
111
+ }
112
+ get filterFieldWrapper() {
113
+ return screen.getByTestId(this.dataTestId);
114
+ }
115
+ get editorView() {
116
+ return this.filterFieldWrapper.querySelector(
117
+ ".cm-content"
118
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
119
+ )?.cmTile.view;
120
+ }
121
+ get inputElement() {
122
+ return within(this.filterFieldWrapper).getAllByRole(
123
+ "textbox",
124
+ { hidden: true }
125
+ )[1];
126
+ }
127
+ get filterFieldElement() {
128
+ return within(this.filterFieldWrapper).getByRole(
129
+ "textbox",
130
+ {
131
+ name: "Filter field",
132
+ hidden: true
133
+ }
134
+ );
135
+ }
136
+ get placeholderElement() {
137
+ return this.filterFieldWrapper.querySelector(".cm-placeholder");
138
+ }
139
+ get suggestionsContainer() {
140
+ return screen.queryByTestId(`filterfield-suggestions-${this.dataTestId}`);
141
+ }
142
+ /** Returns the value of the native text input. */
143
+ get value() {
144
+ return this.inputElement.value;
145
+ }
146
+ /** Returns the value of the filter field. */
147
+ get filterFieldValue() {
148
+ return this.filterFieldElement.textContent || "";
149
+ }
150
+ /**
151
+ * The placeholder text shown in the filter field.
152
+ * Undefined if the placeholder is currently not rendered.
153
+ */
154
+ get placeholder() {
155
+ return this.placeholderElement?.textContent || void 0;
156
+ }
157
+ /** Focus the filter field if not already focused. */
158
+ async focus() {
159
+ if (!this.filterFieldWrapper.contains(document.activeElement)) {
160
+ await act(async () => {
161
+ this.inputElement.focus();
162
+ });
163
+ expect(
164
+ this.filterFieldWrapper.contains(document.activeElement)
165
+ ).toBeTruthy();
166
+ if (isFakeTimersEnabled()) {
167
+ await act(async () => {
168
+ jest.runOnlyPendingTimers();
169
+ });
170
+ }
171
+ }
172
+ }
173
+ /** Blur the filter field by tabbing out of it. */
174
+ async blur() {
175
+ await act(async () => {
176
+ this.filterFieldElement.blur();
177
+ });
178
+ if (isFakeTimersEnabled()) {
179
+ await act(async () => {
180
+ jest.runOnlyPendingTimers();
181
+ });
182
+ }
183
+ }
184
+ /** Fill a provided value into the filter field. */
185
+ async type(text, cursorIndex) {
186
+ const regEx = new RegExp(text, "g");
187
+ const matches = this.value.match(regEx);
188
+ await this.moveCursorTo(cursorIndex ?? -1);
189
+ await setupUserEvent({
190
+ pointerEventsCheck: PointerEventsCheckLevel.Never
191
+ }).keyboard(text);
192
+ await waitFor(() => {
193
+ expect(this.value.match(regEx) ?? []).toHaveLength(
194
+ (matches?.length ?? 0) + 1
195
+ );
196
+ });
197
+ if (isFakeTimersEnabled()) {
198
+ await act(async () => {
199
+ jest.runOnlyPendingTimers();
200
+ });
201
+ }
202
+ }
203
+ /** Clears the filter field value. */
204
+ async clear() {
205
+ if (this.value !== "") {
206
+ await setupUserEvent({
207
+ pointerEventsCheck: PointerEventsCheckLevel.Never
208
+ }).click(
209
+ await within(this.filterFieldWrapper).findByRole("button", {
210
+ name: "Clear filter",
211
+ hidden: true
212
+ })
213
+ );
214
+ if (isFakeTimersEnabled()) {
215
+ await act(async () => {
216
+ jest.runOnlyPendingTimers();
217
+ });
218
+ }
219
+ }
220
+ }
221
+ /**
222
+ * Moves the cursor to the given index.
223
+ * -1 moves to the end of the input.
224
+ */
225
+ async moveCursorTo(index) {
226
+ const user = setupUserEvent({
227
+ pointerEventsCheck: PointerEventsCheckLevel.Never
228
+ });
229
+ if (index === -1) {
230
+ await act(async () => {
231
+ await this.focus();
232
+ });
233
+ await user.keyboard("{PageDown}");
234
+ return;
235
+ }
236
+ if (!this.editorView) {
237
+ console.warn("FilterField editor could not be found. Panic now.");
238
+ return;
239
+ }
240
+ await act(async () => {
241
+ await this.focus();
242
+ this.editorView.dispatch({
243
+ selection: {
244
+ anchor: Math.min(index, this.editorView.state.doc.length)
245
+ }
246
+ });
247
+ });
248
+ if (isFakeTimersEnabled()) {
249
+ await act(async () => {
250
+ jest.runOnlyPendingTimers();
251
+ });
252
+ }
253
+ }
254
+ /** Open the suggestions overlay with the keyboard shortcut. */
255
+ async openSuggestions() {
256
+ await act(async () => {
257
+ await this.focus();
258
+ });
259
+ await setupUserEvent({
260
+ pointerEventsCheck: PointerEventsCheckLevel.Never
261
+ }).keyboard("{Control>}{Space}{/Control}");
262
+ await waitFor(
263
+ async () => expect(this.suggestionsContainer).toBeInTheDocument()
264
+ );
265
+ if (isFakeTimersEnabled()) {
266
+ await act(async () => {
267
+ jest.runOnlyPendingTimers();
268
+ });
269
+ }
270
+ }
271
+ /**
272
+ * Close the suggestions overlay using the `Escape` key.
273
+ * If the filter field is focused, the focus will stay in the filter field.
274
+ */
275
+ async closeSuggestions() {
276
+ await act(async () => {
277
+ await this.focus();
278
+ });
279
+ await setupUserEvent({
280
+ pointerEventsCheck: PointerEventsCheckLevel.Never
281
+ }).keyboard("{Escape}");
282
+ if (this.suggestionsContainer !== null) {
283
+ await waitForElementToBeRemoved(() => this.suggestionsContainer);
284
+ }
285
+ }
286
+ /** Apply the suggestion with the given text. */
287
+ async applySuggestion(queryString) {
288
+ await act(async () => {
289
+ await this.focus();
290
+ });
291
+ await waitFor(() => {
292
+ expect(this.suggestionsContainer).toBeInTheDocument();
293
+ });
294
+ if (!this.suggestionsContainer) {
295
+ console.warn(
296
+ "The filter field suggestions overlay seems to be closed. Make sure to open it before applying a suggestion."
297
+ );
298
+ return;
299
+ }
300
+ const showMore = within(this.suggestionsContainer).queryByRole("option", {
301
+ name: "Show more"
302
+ });
303
+ if (showMore) {
304
+ await setupUserEvent({
305
+ pointerEventsCheck: PointerEventsCheckLevel.Never
306
+ }).click(showMore);
307
+ }
308
+ let suggestions = within(this.suggestionsContainer).queryAllByTestId(
309
+ queryString,
310
+ { exact: true }
311
+ );
312
+ if (suggestions.length > 0) {
313
+ suggestions = suggestions.reduce((acc, container) => {
314
+ const suggestion = within(container).queryByRole("option");
315
+ if (suggestion) {
316
+ acc.push(suggestion);
317
+ }
318
+ return acc;
319
+ }, []);
320
+ }
321
+ if (suggestions.length === 0) {
322
+ suggestions.push(
323
+ ...within(this.suggestionsContainer).queryAllByText(
324
+ (_, element) => element?.getAttribute("role") === "option" && // The replace is needed to ignore non-breaking spaces
325
+ element.firstElementChild?.textContent?.replace(/\s+/g, " ") === queryString.replace(/\s+/g, " ")
326
+ )
327
+ );
328
+ }
329
+ if (suggestions.length === 0) {
330
+ console.warn(
331
+ `Could not query a suggestion with the given queryString '${queryString}' (trying queryByTestId and queryByText).`
332
+ );
333
+ return;
334
+ }
335
+ if (suggestions.length > 1) {
336
+ console.warn(
337
+ "Found multiple suggestions with the given testId. Will apply the first one"
338
+ );
339
+ }
340
+ await setupUserEvent({
341
+ pointerEventsCheck: PointerEventsCheckLevel.Never
342
+ }).click(suggestions[0]);
343
+ }
344
+ /** Get recent suggestions */
345
+ async getRecentSuggestions() {
346
+ if (this.suggestionsContainer) {
347
+ const recentGroup = within(this.suggestionsContainer).getByRole("group", {
348
+ name: "Recently used filters"
349
+ });
350
+ const suggestions = within(recentGroup).getAllByRole(
351
+ "group",
352
+ {
353
+ hidden: true,
354
+ name(_accessibleName, element) {
355
+ return element.getAttribute(
356
+ "data-strato-filter-field-virtual-focus-type"
357
+ ) === "recent-suggestion";
358
+ }
359
+ }
360
+ );
361
+ return suggestions.map((el) => new FilterFieldRecentSuggestion(el));
362
+ }
363
+ return [];
364
+ }
365
+ /** Get pinned suggestions */
366
+ async getPinnedSuggestions() {
367
+ if (this.suggestionsContainer) {
368
+ try {
369
+ await waitFor(
370
+ () => screen.getByRole("group", {
371
+ name: "Pinned filters",
372
+ hidden: true,
373
+ suggest: false
374
+ })
375
+ );
376
+ const pinnedGroup = within(this.suggestionsContainer).getByRole(
377
+ "group",
378
+ {
379
+ name: "Pinned filters",
380
+ hidden: true
381
+ }
382
+ );
383
+ const suggestions = within(pinnedGroup).getAllByRole(
384
+ "group",
385
+ {
386
+ hidden: true,
387
+ name(_accessibleName, element) {
388
+ return element.getAttribute(
389
+ "data-strato-filter-field-virtual-focus-type"
390
+ ) === "pinned-suggestion";
391
+ }
392
+ }
393
+ );
394
+ return suggestions.map((el) => new FilterFieldPinnedSuggestion(el));
395
+ } catch {
396
+ return [];
397
+ }
398
+ }
399
+ return [];
400
+ }
401
+ /** Paste text at the current cursor position */
402
+ async paste(text, cursorIndex) {
403
+ await this.moveCursorTo(cursorIndex ?? -1);
404
+ await setupUserEvent({
405
+ pointerEventsCheck: PointerEventsCheckLevel.Never
406
+ }).paste(text);
407
+ if (isFakeTimersEnabled()) {
408
+ await act(async () => {
409
+ jest.runOnlyPendingTimers();
410
+ });
411
+ }
412
+ }
413
+ }
414
+ function getFilterFieldHelper(dataTestId) {
415
+ return new FilterFieldHelper(dataTestId);
416
+ }
417
+ export {
418
+ FilterFieldHelper,
419
+ FilterFieldPinnedAndRecentSuggestionBase,
420
+ FilterFieldPinnedSuggestion,
421
+ FilterFieldRecentSuggestion,
422
+ getFilterFieldHelper
423
+ };
424
+ //# sourceMappingURL=filter-field.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/jest/testing-helpers/filters/filter-field.ts"],
4
+ "sourcesContent": ["import {\n act,\n screen,\n waitFor,\n waitForElementToBeRemoved,\n within,\n} from '@testing-library/react';\nimport { PointerEventsCheckLevel } from '@testing-library/user-event';\n\nimport { isFakeTimersEnabled } from '../utils/isFakeTimersEnabled.js';\nimport { setupUserEvent } from '../utils/setup-user-event.js';\n\n/**\n * Base class for pinned or recent filter field suggestion.\n * @public */\nexport class FilterFieldPinnedAndRecentSuggestionBase {\n constructor(protected readonly suggestionRoot: HTMLDivElement) {}\n\n private get pinButtonElement(): HTMLButtonElement | null {\n return this.suggestionRoot.querySelector<HTMLButtonElement>(\n 'button[aria-checked]',\n );\n }\n\n /**\n * Receives the value of the suggestion that would be applied.\n */\n get value(): string | null {\n return this.suggestionRoot.childNodes.item(1).textContent;\n }\n\n /**\n * Returns if the current suggestion is currently pinned or not.\n */\n get pinned(): boolean {\n if (this.pinButtonElement) {\n return this.pinButtonElement.getAttribute('aria-checked') === 'true';\n }\n return false;\n }\n\n /**\n * Applies the suggestion to the filter field.\n */\n async apply() {\n await setupUserEvent({\n pointerEventsCheck: PointerEventsCheckLevel.Never,\n }).click(this.suggestionRoot);\n }\n\n get pinEnabled(): boolean {\n if (this.pinButtonElement) {\n return this.pinButtonElement.getAttribute('aria-disabled') === 'false';\n }\n return false;\n }\n\n /**\n * Allows the suggestion to be pinned if not pinned already.\n */\n async pin() {\n if (this.pinned === true) {\n return;\n }\n if (this.pinButtonElement) {\n await setupUserEvent({\n pointerEventsCheck: PointerEventsCheckLevel.Never,\n }).click(this.pinButtonElement);\n\n if (isFakeTimersEnabled()) {\n await act(async () => {\n jest.runOnlyPendingTimers();\n });\n }\n }\n }\n\n /**\n * Allows the suggestion to be unpinned if not unpinned already.\n */\n async unpin() {\n if (this.pinned === false) {\n return;\n }\n if (this.pinButtonElement) {\n await setupUserEvent({\n pointerEventsCheck: PointerEventsCheckLevel.Never,\n }).click(this.pinButtonElement);\n\n if (isFakeTimersEnabled()) {\n await act(async () => {\n jest.runOnlyPendingTimers();\n });\n }\n }\n }\n}\n\n/**\n * Testing helper class for pinned suggestions in the filter field\n * @public */\nexport class FilterFieldPinnedSuggestion extends FilterFieldPinnedAndRecentSuggestionBase {\n /**\n * Receives the value of the suggestion that would be applied.\n */\n get value(): string | null {\n return this.suggestionRoot.childNodes.item(0).textContent;\n }\n}\n\n/**\n * Testing helper class for recent suggestions in the filter field\n * @public */\nexport class FilterFieldRecentSuggestion extends FilterFieldPinnedAndRecentSuggestionBase {\n /**\n * Receives the value of the suggestion that would be applied.\n */\n get value(): string | null {\n return (\n this.suggestionRoot.querySelector('[role=\"option\"]')?.childNodes.item(0)\n .textContent ?? null\n );\n }\n /**\n * Receives time offset indicating when the filter statement has last been used.\n */\n get lastUsed(): string | null {\n return (\n this.suggestionRoot.querySelector('[role=\"option\"]')?.childNodes.item(1)\n .textContent ?? null\n );\n }\n}\n\n/**\n * Helper class for interacting with the filter field.\n * @public\n */\nexport class FilterFieldHelper {\n private get filterFieldWrapper(): HTMLElement {\n return screen.getByTestId(this.dataTestId);\n }\n\n private get editorView() {\n return (\n this.filterFieldWrapper.querySelector(\n '.cm-content',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ) as any\n )?.cmTile.view;\n }\n\n private get inputElement(): HTMLInputElement {\n return within(this.filterFieldWrapper).getAllByRole<HTMLInputElement>(\n 'textbox',\n { hidden: true },\n )[1];\n }\n\n private get filterFieldElement(): HTMLDivElement {\n return within(this.filterFieldWrapper).getByRole<HTMLDivElement>(\n 'textbox',\n {\n name: 'Filter field',\n hidden: true,\n },\n );\n }\n\n private get placeholderElement(): HTMLSpanElement | null {\n return this.filterFieldWrapper.querySelector('.cm-placeholder');\n }\n\n private get suggestionsContainer(): HTMLDivElement | null {\n return screen.queryByTestId(`filterfield-suggestions-${this.dataTestId}`);\n }\n\n constructor(private dataTestId: string) {}\n\n /** Returns the value of the native text input. */\n get value(): string {\n return this.inputElement.value;\n }\n\n /** Returns the value of the filter field. */\n get filterFieldValue(): string {\n return this.filterFieldElement.textContent || '';\n }\n\n /**\n * The placeholder text shown in the filter field.\n * Undefined if the placeholder is currently not rendered.\n */\n get placeholder(): string | undefined {\n return this.placeholderElement?.textContent || undefined;\n }\n\n /** Focus the filter field if not already focused. */\n async focus() {\n if (!this.filterFieldWrapper.contains(document.activeElement)) {\n await act(async () => {\n this.inputElement.focus();\n });\n\n expect(\n this.filterFieldWrapper.contains(document.activeElement),\n ).toBeTruthy();\n\n if (isFakeTimersEnabled()) {\n await act(async () => {\n jest.runOnlyPendingTimers();\n });\n }\n }\n }\n\n /** Blur the filter field by tabbing out of it. */\n async blur() {\n await act(async () => {\n this.filterFieldElement.blur();\n });\n\n if (isFakeTimersEnabled()) {\n await act(async () => {\n jest.runOnlyPendingTimers();\n });\n }\n }\n\n /** Fill a provided value into the filter field. */\n async type(text: string, cursorIndex?: number) {\n const regEx = new RegExp(text, 'g');\n const matches = this.value.match(regEx);\n\n await this.moveCursorTo(cursorIndex ?? -1);\n\n await setupUserEvent({\n pointerEventsCheck: PointerEventsCheckLevel.Never,\n }).keyboard(text);\n await waitFor(() => {\n expect(this.value.match(regEx) ?? []).toHaveLength(\n (matches?.length ?? 0) + 1,\n );\n });\n\n if (isFakeTimersEnabled()) {\n await act(async () => {\n jest.runOnlyPendingTimers();\n });\n }\n }\n\n /** Clears the filter field value. */\n async clear() {\n if (this.value !== '') {\n await setupUserEvent({\n pointerEventsCheck: PointerEventsCheckLevel.Never,\n }).click(\n await within(this.filterFieldWrapper).findByRole('button', {\n name: 'Clear filter',\n hidden: true,\n }),\n );\n\n if (isFakeTimersEnabled()) {\n await act(async () => {\n jest.runOnlyPendingTimers();\n });\n }\n }\n }\n\n /**\n * Moves the cursor to the given index.\n * -1 moves to the end of the input.\n */\n async moveCursorTo(index: number) {\n const user = setupUserEvent({\n pointerEventsCheck: PointerEventsCheckLevel.Never,\n });\n\n if (index === -1) {\n await act(async () => {\n await this.focus();\n });\n await user.keyboard('{PageDown}');\n\n return;\n }\n\n if (!this.editorView) {\n // eslint-disable-next-line no-console\n console.warn('FilterField editor could not be found. Panic now.');\n return;\n }\n\n await act(async () => {\n await this.focus();\n this.editorView.dispatch({\n selection: {\n anchor: Math.min(index, this.editorView.state.doc.length),\n },\n });\n });\n\n if (isFakeTimersEnabled()) {\n await act(async () => {\n jest.runOnlyPendingTimers();\n });\n }\n }\n\n /** Open the suggestions overlay with the keyboard shortcut. */\n async openSuggestions() {\n await act(async () => {\n await this.focus();\n });\n await setupUserEvent({\n pointerEventsCheck: PointerEventsCheckLevel.Never,\n }).keyboard('{Control>}{Space}{/Control}');\n\n await waitFor(async () =>\n expect(this.suggestionsContainer).toBeInTheDocument(),\n );\n if (isFakeTimersEnabled()) {\n await act(async () => {\n jest.runOnlyPendingTimers();\n });\n }\n }\n\n /**\n * Close the suggestions overlay using the `Escape` key.\n * If the filter field is focused, the focus will stay in the filter field.\n */\n async closeSuggestions() {\n await act(async () => {\n await this.focus();\n });\n await setupUserEvent({\n pointerEventsCheck: PointerEventsCheckLevel.Never,\n }).keyboard('{Escape}');\n\n if (this.suggestionsContainer !== null) {\n await waitForElementToBeRemoved(() => this.suggestionsContainer);\n }\n }\n\n /** Apply the suggestion with the given text. */\n async applySuggestion(queryString: string) {\n await act(async () => {\n await this.focus();\n });\n\n // Wait for the suggestions overlay to open.\n await waitFor(() => {\n expect(this.suggestionsContainer).toBeInTheDocument();\n });\n\n if (!this.suggestionsContainer) {\n // eslint-disable-next-line no-console\n console.warn(\n 'The filter field suggestions overlay seems to be closed. Make sure to open it before applying a suggestion.',\n );\n return;\n }\n\n const showMore = within(this.suggestionsContainer).queryByRole('option', {\n name: 'Show more',\n });\n\n if (showMore) {\n await setupUserEvent({\n pointerEventsCheck: PointerEventsCheckLevel.Never,\n }).click(showMore);\n }\n\n let suggestions = within(this.suggestionsContainer).queryAllByTestId(\n queryString,\n { exact: true },\n );\n\n if (suggestions.length > 0) {\n suggestions = suggestions.reduce<HTMLElement[]>((acc, container) => {\n const suggestion = within(container).queryByRole('option');\n if (suggestion) {\n acc.push(suggestion);\n }\n\n return acc;\n }, []);\n }\n\n if (suggestions.length === 0) {\n suggestions.push(\n ...within(this.suggestionsContainer).queryAllByText(\n (_, element) =>\n element?.getAttribute('role') === 'option' &&\n // The replace is needed to ignore non-breaking spaces\n element.firstElementChild?.textContent?.replace(/\\s+/g, ' ') ===\n queryString.replace(/\\s+/g, ' '),\n ),\n );\n }\n\n if (suggestions.length === 0) {\n // eslint-disable-next-line no-console\n console.warn(\n `Could not query a suggestion with the given queryString '${queryString}' (trying queryByTestId and queryByText).`,\n );\n return;\n }\n\n if (suggestions.length > 1) {\n // eslint-disable-next-line no-console\n console.warn(\n 'Found multiple suggestions with the given testId. Will apply the first one',\n );\n }\n\n await setupUserEvent({\n pointerEventsCheck: PointerEventsCheckLevel.Never,\n }).click(suggestions[0]);\n }\n\n /** Get recent suggestions */\n async getRecentSuggestions(): Promise<FilterFieldRecentSuggestion[]> {\n if (this.suggestionsContainer) {\n const recentGroup = within(this.suggestionsContainer).getByRole('group', {\n name: 'Recently used filters',\n });\n const suggestions = within(recentGroup).getAllByRole<HTMLDivElement>(\n 'group',\n {\n hidden: true,\n name(_accessibleName: string, element: Element) {\n return (\n element.getAttribute(\n 'data-strato-filter-field-virtual-focus-type',\n ) === 'recent-suggestion'\n );\n },\n },\n );\n return suggestions.map((el) => new FilterFieldRecentSuggestion(el));\n }\n return [];\n }\n\n /** Get pinned suggestions */\n async getPinnedSuggestions(): Promise<FilterFieldPinnedSuggestion[]> {\n if (this.suggestionsContainer) {\n try {\n await waitFor(() =>\n screen.getByRole('group', {\n name: 'Pinned filters',\n hidden: true,\n suggest: false,\n }),\n );\n const pinnedGroup = within(this.suggestionsContainer).getByRole(\n 'group',\n {\n name: 'Pinned filters',\n hidden: true,\n },\n );\n const suggestions = within(pinnedGroup).getAllByRole<HTMLDivElement>(\n 'group',\n {\n hidden: true,\n name(_accessibleName: string, element: Element) {\n return (\n element.getAttribute(\n 'data-strato-filter-field-virtual-focus-type',\n ) === 'pinned-suggestion'\n );\n },\n },\n );\n return suggestions.map((el) => new FilterFieldPinnedSuggestion(el));\n } catch {\n return [];\n }\n }\n return [];\n }\n\n /** Paste text at the current cursor position */\n async paste(text: string, cursorIndex?: number) {\n await this.moveCursorTo(cursorIndex ?? -1);\n\n await setupUserEvent({\n pointerEventsCheck: PointerEventsCheckLevel.Never,\n }).paste(text);\n\n if (isFakeTimersEnabled()) {\n await act(async () => {\n jest.runOnlyPendingTimers();\n });\n }\n }\n}\n\n/**\n * Helper function that returns the filter field with its testing utilities.\n * @public\n */\nexport function getFilterFieldHelper(\n /** The accessible test id used to locate the filter field wrapper. */\n dataTestId: string,\n): FilterFieldHelper {\n return new FilterFieldHelper(dataTestId);\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,32 @@
1
+ import { screen, within } from "@testing-library/react";
2
+ import { setupUserEvent } from "../utils/setup-user-event.js";
3
+ class BaseInputHelper {
4
+ constructor(dataTestId) {
5
+ this.dataTestId = dataTestId;
6
+ }
7
+ get inputWrapper() {
8
+ return screen.getByTestId(this.dataTestId);
9
+ }
10
+ get inputElement() {
11
+ return within(this.inputWrapper).getByRole("textbox", { hidden: true });
12
+ }
13
+ /** Returns the value of the native input element. */
14
+ get value() {
15
+ return this.inputElement.value;
16
+ }
17
+ focus() {
18
+ this.inputElement.focus();
19
+ }
20
+ /** Fill a provided value into the text input. */
21
+ async type(text) {
22
+ await setupUserEvent().type(this.inputElement, text);
23
+ }
24
+ /** Clears the text input value. */
25
+ async clear() {
26
+ await setupUserEvent().clear(this.inputElement);
27
+ }
28
+ }
29
+ export {
30
+ BaseInputHelper
31
+ };
32
+ //# sourceMappingURL=base-input.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/jest/testing-helpers/forms/base-input.ts"],
4
+ "sourcesContent": ["import { screen, within } from '@testing-library/react';\n\nimport { setupUserEvent } from '../utils/setup-user-event.js';\n\n/**\n * Helper class for interacting with the text input\n * @public\n */\nexport class BaseInputHelper {\n protected get inputWrapper(): HTMLElement {\n return screen.getByTestId(this.dataTestId);\n }\n\n protected get inputElement(): HTMLInputElement {\n return within(this.inputWrapper).getByRole('textbox', { hidden: true });\n }\n\n constructor(protected dataTestId: string) {}\n\n /** Returns the value of the native input element. */\n get value(): string {\n return this.inputElement.value;\n }\n\n focus() {\n this.inputElement.focus();\n }\n\n /** Fill a provided value into the text input. */\n async type(text: string) {\n await setupUserEvent().type(this.inputElement, text);\n }\n\n /** Clears the text input value. */\n async clear() {\n await setupUserEvent().clear(this.inputElement);\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,QAAQ,cAAc;AAE/B,SAAS,sBAAsB;AAMxB,MAAM,gBAAgB;AAAA,EAS3B,YAAsB,YAAoB;AAApB;AAAA,EAAqB;AAAA,EAR3C,IAAc,eAA4B;AACxC,WAAO,OAAO,YAAY,KAAK,UAAU;AAAA,EAC3C;AAAA,EAEA,IAAc,eAAiC;AAC7C,WAAO,OAAO,KAAK,YAAY,EAAE,UAAU,WAAW,EAAE,QAAQ,KAAK,CAAC;AAAA,EACxE;AAAA;AAAA,EAKA,IAAI,QAAgB;AAClB,WAAO,KAAK,aAAa;AAAA,EAC3B;AAAA,EAEA,QAAQ;AACN,SAAK,aAAa,MAAM;AAAA,EAC1B;AAAA;AAAA,EAGA,MAAM,KAAK,MAAc;AACvB,UAAM,eAAe,EAAE,KAAK,KAAK,cAAc,IAAI;AAAA,EACrD;AAAA;AAAA,EAGA,MAAM,QAAQ;AACZ,UAAM,eAAe,EAAE,MAAM,KAAK,YAAY;AAAA,EAChD;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,29 @@
1
+ import { within } from "@testing-library/react";
2
+ import { BaseInputHelper } from "./base-input.js";
3
+ import { setupUserEvent } from "../utils/setup-user-event.js";
4
+ class PasswordInputHelper extends BaseInputHelper {
5
+ async showPassword() {
6
+ if (this.inputElement.getAttribute("type") === "password") {
7
+ const passwordButton = within(this.inputWrapper).getByRole("button", {
8
+ hidden: true
9
+ });
10
+ await setupUserEvent().click(passwordButton);
11
+ }
12
+ }
13
+ async hidePassword() {
14
+ if (this.inputElement.getAttribute("type") === "text") {
15
+ const passwordButton = within(this.inputWrapper).getByRole("button", {
16
+ hidden: true
17
+ });
18
+ await setupUserEvent().click(passwordButton);
19
+ }
20
+ }
21
+ }
22
+ function getPasswordInputHelper(dataTestId) {
23
+ return new PasswordInputHelper(dataTestId);
24
+ }
25
+ export {
26
+ PasswordInputHelper,
27
+ getPasswordInputHelper
28
+ };
29
+ //# sourceMappingURL=password-input.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/jest/testing-helpers/forms/password-input.ts"],
4
+ "sourcesContent": ["import { within } from '@testing-library/react';\n\nimport { BaseInputHelper } from './base-input.js';\nimport { setupUserEvent } from '../utils/setup-user-event.js';\n\n/**\n * Helper class for interacting with the text input\n * @public\n */\nexport class PasswordInputHelper extends BaseInputHelper {\n async showPassword() {\n if (this.inputElement.getAttribute('type') === 'password') {\n const passwordButton = within(this.inputWrapper).getByRole('button', {\n hidden: true,\n });\n await setupUserEvent().click(passwordButton);\n }\n }\n async hidePassword() {\n if (this.inputElement.getAttribute('type') === 'text') {\n const passwordButton = within(this.inputWrapper).getByRole('button', {\n hidden: true,\n });\n await setupUserEvent().click(passwordButton);\n }\n }\n}\n\n/**\n * Helper function that returns the password input element with its testing utilities.\n * @public\n */\nexport function getPasswordInputHelper(\n /** The accessible test id used to locate the password input wrapper. */\n dataTestId: string,\n): PasswordInputHelper {\n return new PasswordInputHelper(dataTestId);\n}\n"],
5
+ "mappings": "AAAA,SAAS,cAAc;AAEvB,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAMxB,MAAM,4BAA4B,gBAAgB;AAAA,EACvD,MAAM,eAAe;AACnB,QAAI,KAAK,aAAa,aAAa,MAAM,MAAM,YAAY;AACzD,YAAM,iBAAiB,OAAO,KAAK,YAAY,EAAE,UAAU,UAAU;AAAA,QACnE,QAAQ;AAAA,MACV,CAAC;AACD,YAAM,eAAe,EAAE,MAAM,cAAc;AAAA,IAC7C;AAAA,EACF;AAAA,EACA,MAAM,eAAe;AACnB,QAAI,KAAK,aAAa,aAAa,MAAM,MAAM,QAAQ;AACrD,YAAM,iBAAiB,OAAO,KAAK,YAAY,EAAE,UAAU,UAAU;AAAA,QACnE,QAAQ;AAAA,MACV,CAAC;AACD,YAAM,eAAe,EAAE,MAAM,cAAc;AAAA,IAC7C;AAAA,EACF;AACF;AAMO,SAAS,uBAEd,YACqB;AACrB,SAAO,IAAI,oBAAoB,UAAU;AAC3C;",
6
+ "names": []
7
+ }
@@ -0,0 +1,27 @@
1
+ import { within } from "@testing-library/react";
2
+ import { BaseInputHelper } from "./base-input.js";
3
+ import { setupUserEvent } from "../utils/setup-user-event.js";
4
+ class SearchInputHelper extends BaseInputHelper {
5
+ get inputElement() {
6
+ return within(this.inputWrapper).getByRole("searchbox", { hidden: true });
7
+ }
8
+ /**
9
+ * Helper that will let you call a specific suffix button
10
+ * within the SearchInput component.
11
+ */
12
+ async clickButton(name) {
13
+ const button = within(this.inputWrapper).getByRole("button", {
14
+ hidden: true,
15
+ name
16
+ });
17
+ await setupUserEvent().click(button);
18
+ }
19
+ }
20
+ function getSearchInputHelper(dataTestId) {
21
+ return new SearchInputHelper(dataTestId);
22
+ }
23
+ export {
24
+ SearchInputHelper,
25
+ getSearchInputHelper
26
+ };
27
+ //# sourceMappingURL=search-input.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/jest/testing-helpers/forms/search-input.ts"],
4
+ "sourcesContent": ["import { within } from '@testing-library/react';\n\nimport { BaseInputHelper } from './base-input.js';\nimport { setupUserEvent } from '../utils/setup-user-event.js';\n\n/**\n * Helper class for interacting with the search input\n * @public\n */\nexport class SearchInputHelper extends BaseInputHelper {\n protected override get inputElement(): HTMLInputElement {\n return within(this.inputWrapper).getByRole('searchbox', { hidden: true });\n }\n /**\n * Helper that will let you call a specific suffix button\n * within the SearchInput component.\n */\n async clickButton(name: string) {\n const button = within(this.inputWrapper).getByRole('button', {\n hidden: true,\n name,\n });\n\n await setupUserEvent().click(button);\n }\n}\n\n/**\n * Helper function that returns the search input element with its testing utilities.\n * @public\n */\nexport function getSearchInputHelper(\n /** The accessible test id used to locate the input wrapper. */\n dataTestId: string,\n): SearchInputHelper {\n return new SearchInputHelper(dataTestId);\n}\n"],
5
+ "mappings": "AAAA,SAAS,cAAc;AAEvB,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAMxB,MAAM,0BAA0B,gBAAgB;AAAA,EACrD,IAAuB,eAAiC;AACtD,WAAO,OAAO,KAAK,YAAY,EAAE,UAAU,aAAa,EAAE,QAAQ,KAAK,CAAC;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,MAAc;AAC9B,UAAM,SAAS,OAAO,KAAK,YAAY,EAAE,UAAU,UAAU;AAAA,MAC3D,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AAED,UAAM,eAAe,EAAE,MAAM,MAAM;AAAA,EACrC;AACF;AAMO,SAAS,qBAEd,YACmB;AACnB,SAAO,IAAI,kBAAkB,UAAU;AACzC;",
6
+ "names": []
7
+ }