@ghentcdh/ui 1.0.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/testing.mjs ADDED
@@ -0,0 +1,420 @@
1
+ class r {
2
+ constructor(t) {
3
+ this.locator = t;
4
+ }
5
+ /** Access the Page this harness was scoped against. */
6
+ page() {
7
+ return this.locator.page();
8
+ }
9
+ /** Get the underlying Locator — useful for assertions or further scoping. */
10
+ asLocator() {
11
+ return this.locator;
12
+ }
13
+ }
14
+ const e = (x, t, a) => x.getByRole(t, { name: a });
15
+ class i extends r {
16
+ static byId(t, a) {
17
+ return new i(e(t, "textbox", a));
18
+ }
19
+ /** Resolve by visible label (the `<legend>` text). */
20
+ static byLabel(t, a) {
21
+ return new i(e(t, "textbox", a));
22
+ }
23
+ static for(t) {
24
+ return new i(t);
25
+ }
26
+ async fill(t) {
27
+ return await this.locator.click(), await this.locator.fill(t), this;
28
+ }
29
+ /** Type character-by-character — useful when the control reacts to each keystroke. */
30
+ async type(t) {
31
+ return await this.locator.click(), await this.locator.pressSequentially(t), this;
32
+ }
33
+ async clear() {
34
+ return await this.locator.fill(""), this;
35
+ }
36
+ async value() {
37
+ return this.locator.inputValue();
38
+ }
39
+ async blur() {
40
+ return await this.locator.press("Tab"), this;
41
+ }
42
+ }
43
+ class o extends r {
44
+ static byId(t, a) {
45
+ return new o(e(t, "spinbutton", a));
46
+ }
47
+ static byLabel(t, a) {
48
+ return new o(e(t, "spinbutton", a));
49
+ }
50
+ static for(t) {
51
+ return new o(t);
52
+ }
53
+ async fill(t) {
54
+ return await this.locator.click(), await this.locator.fill(String(t)), await this.locator.press("Tab"), this;
55
+ }
56
+ async clear() {
57
+ return await this.locator.fill(""), this;
58
+ }
59
+ async value() {
60
+ const t = await this.locator.inputValue();
61
+ return t === "" ? null : Number(t);
62
+ }
63
+ }
64
+ class c extends r {
65
+ static byId(t, a) {
66
+ return new c(e(t, "textbox", a));
67
+ }
68
+ static byLabel(t, a) {
69
+ return new c(e(t, "textbox", a));
70
+ }
71
+ static for(t) {
72
+ return new c(t);
73
+ }
74
+ async fill(t) {
75
+ return await this.locator.click(), await this.locator.fill(t), this;
76
+ }
77
+ async clear() {
78
+ return await this.locator.fill(""), this;
79
+ }
80
+ async value() {
81
+ return this.locator.inputValue();
82
+ }
83
+ }
84
+ class s extends r {
85
+ static byId(t, a) {
86
+ return new s(e(t, "checkbox", a));
87
+ }
88
+ static byLabel(t, a) {
89
+ return new s(e(t, "checkbox", a));
90
+ }
91
+ static for(t) {
92
+ return new s(t);
93
+ }
94
+ async fill(t) {
95
+ return t ? await this.locator.check() : await this.locator.uncheck(), this;
96
+ }
97
+ async toggle() {
98
+ return await this.locator.click(), this;
99
+ }
100
+ async value() {
101
+ return this.locator.isChecked();
102
+ }
103
+ }
104
+ class l extends r {
105
+ static byId(t, a) {
106
+ return new l(e(t, "combobox", a));
107
+ }
108
+ static byLabel(t, a) {
109
+ return new l(e(t, "combobox", a));
110
+ }
111
+ static for(t) {
112
+ return new l(t);
113
+ }
114
+ async open() {
115
+ return await this.locator.click(), this;
116
+ }
117
+ async fill(t) {
118
+ return this.select(t);
119
+ }
120
+ async select(t) {
121
+ return await this.open(), await this.page().getByRole("option", { name: t }).locator("a").click(), this;
122
+ }
123
+ async value() {
124
+ return (await this.locator.textContent())?.trim() ?? "";
125
+ }
126
+ /** Click the "Clear" button rendered next to the select. */
127
+ async clear() {
128
+ return await this.locator.locator(
129
+ 'xpath=ancestor::*[@role="select"][1]'
130
+ ).getByRole("button", { name: "Clear" }).click(), this;
131
+ }
132
+ /**
133
+ * Click the "Create new" button. Requires `enableCreate` to be set on
134
+ * the component (SelectWrapper conditionally renders the button).
135
+ */
136
+ async clickCreateNew() {
137
+ await this.locator.locator(
138
+ 'xpath=ancestor::*[@role="select"][1]'
139
+ ).getByRole("button", { name: "create" }).click();
140
+ }
141
+ }
142
+ class n extends r {
143
+ static byId(t, a) {
144
+ return new n(e(t, "combobox", a));
145
+ }
146
+ static byLabel(t, a) {
147
+ return new n(e(t, "combobox", a));
148
+ }
149
+ static for(t) {
150
+ return new n(t);
151
+ }
152
+ /** Type a query, wait for the matching option, click it. */
153
+ async fill(t) {
154
+ return await this.locator.click(), await this.locator.fill(t), await this.page().getByRole("option", { name: t }).locator("a").click(), this;
155
+ }
156
+ /** Just type a query without selecting — useful for asserting dropdown state. */
157
+ async query(t) {
158
+ return await this.locator.click(), await this.locator.fill(t), this;
159
+ }
160
+ /** Pick a specific option by visible label, after `query()` has filtered. */
161
+ async pickOption(t) {
162
+ return await this.page().getByRole("option", { name: t }).locator("a").click(), this;
163
+ }
164
+ /** Press a key — useful for arrow-down / Enter / Esc keyboard nav tests. */
165
+ async press(t) {
166
+ return await this.locator.press(t), this;
167
+ }
168
+ /** Click the "Create new" button (requires `enableCreate`). */
169
+ async clickCreateNew() {
170
+ await this.locator.locator(
171
+ 'xpath=ancestor::*[@role="select"][1]'
172
+ ).getByRole("button", { name: "create" }).click();
173
+ }
174
+ async clear() {
175
+ return await this.locator.locator(
176
+ 'xpath=ancestor::*[@role="select"][1]'
177
+ ).getByRole("button", { name: "Clear" }).click(), this;
178
+ }
179
+ async value() {
180
+ return this.locator.inputValue();
181
+ }
182
+ /** The listbox is portaled — locate it relative to the Page. */
183
+ listbox() {
184
+ return this.page().getByRole("listbox");
185
+ }
186
+ options() {
187
+ return this.page().getByRole("option");
188
+ }
189
+ }
190
+ class u extends r {
191
+ static byId(t, a) {
192
+ return new u(e(t, "combobox", a));
193
+ }
194
+ static byLabel(t, a) {
195
+ return new u(e(t, "combobox", a));
196
+ }
197
+ static for(t) {
198
+ return new u(t);
199
+ }
200
+ async open() {
201
+ return await this.locator.click(), this;
202
+ }
203
+ async fill(t) {
204
+ await this.open();
205
+ for (const a of t)
206
+ await this.page().getByRole("option", { name: a }).locator("a").click();
207
+ return await this.locator.click(), this;
208
+ }
209
+ async select(t) {
210
+ return await this.open(), await this.page().getByRole("option", { name: t }).locator("a").click(), this;
211
+ }
212
+ /** Remove a selected chip by its label. */
213
+ async removeChip(t) {
214
+ return await this.locator.locator(
215
+ 'xpath=ancestor::*[@role="select"][1]'
216
+ ).getByText(t, { exact: !0 }).getByRole("button").click(), this;
217
+ }
218
+ }
219
+ class h extends r {
220
+ static byId(t, a) {
221
+ return new h(e(t, "textbox", a));
222
+ }
223
+ static byLabel(t, a) {
224
+ return new h(e(t, "textbox", a));
225
+ }
226
+ static for(t) {
227
+ return new h(t);
228
+ }
229
+ /** The editable inner surface — TipTap renders a nested `role="textbox"`. */
230
+ get editor() {
231
+ return this.locator.getByRole("textbox");
232
+ }
233
+ async fill(t) {
234
+ return await this.editor.fill(t), this;
235
+ }
236
+ async clear() {
237
+ return await this.editor.fill(""), this;
238
+ }
239
+ async typeBold(t) {
240
+ return await this.toolbar("B").click(), await this.editor.pressSequentially(t), await this.toolbar("B").click(), this;
241
+ }
242
+ async typeItalic(t) {
243
+ return await this.toolbar("I").click(), await this.editor.pressSequentially(t), await this.toolbar("I").click(), this;
244
+ }
245
+ async type(t) {
246
+ return await this.editor.pressSequentially(t), this;
247
+ }
248
+ toolbar(t) {
249
+ return this.locator.getByRole("button", { name: t });
250
+ }
251
+ /** Is a toolbar mark currently active (the lib adds `btn-active`)? */
252
+ async isMarkActive(t) {
253
+ return (await this.toolbar(t).getAttribute("class") ?? "").includes("btn-active");
254
+ }
255
+ }
256
+ class y extends r {
257
+ /**
258
+ * Resolve by the dialog's accessible name (the `modalTitle` shown in the
259
+ * `<h3>`). Note: matches are case-insensitive substring.
260
+ */
261
+ static byTitle(t, a) {
262
+ return new y(
263
+ t.getByRole("dialog", { name: a })
264
+ );
265
+ }
266
+ /** Resolve the only-open dialog. Useful when there's just one at a time. */
267
+ static current(t) {
268
+ return new y(t.getByRole("dialog"));
269
+ }
270
+ static for(t) {
271
+ return new y(t);
272
+ }
273
+ // ── interactions ──────────────────────────────────────────────────────
274
+ async clickClose() {
275
+ return await this.locator.getByRole("button", { name: "Close" }).click(), this;
276
+ }
277
+ /** Press Esc on the dialog (handled by the native `<dialog>` element). */
278
+ async pressEscape() {
279
+ return await this.locator.press("Escape"), this;
280
+ }
281
+ /** Click outside the modal box to attempt a backdrop close. */
282
+ async clickBackdrop() {
283
+ return await this.locator.click({ position: { x: 5, y: 5 } }), this;
284
+ }
285
+ /** Click an action button in the modal's `#actions` slot by accessible name. */
286
+ async clickAction(t) {
287
+ return await this.locator.getByRole("button", { name: t }).click(), this;
288
+ }
289
+ // ── inspection ────────────────────────────────────────────────────────
290
+ /** The `<h3>` title element. */
291
+ title() {
292
+ return this.locator.locator("h3").first();
293
+ }
294
+ /** The content slot wrapper. */
295
+ content() {
296
+ return this.locator.locator('[id$="_content"]').first();
297
+ }
298
+ /** Whether the dialog is currently visible (for `expect().toBeVisible()`). */
299
+ asLocator() {
300
+ return this.locator;
301
+ }
302
+ }
303
+ class b extends r {
304
+ /** Resolve by accessible name (button text / aria-label). */
305
+ static byName(t, a) {
306
+ return new b(e(t, "button", a));
307
+ }
308
+ static for(t) {
309
+ return new b(t);
310
+ }
311
+ async click() {
312
+ return await this.locator.click(), this;
313
+ }
314
+ async isDisabled() {
315
+ return this.locator.isDisabled();
316
+ }
317
+ async text() {
318
+ return await this.locator.textContent() ?? "";
319
+ }
320
+ }
321
+ class p extends r {
322
+ /** Resolve by the collapse title text. */
323
+ static byTitle(t, a) {
324
+ const f = t.getByLabel(`Toggle ${a}`);
325
+ return new p(f.locator(".."));
326
+ }
327
+ static for(t) {
328
+ return new p(t);
329
+ }
330
+ /** Toggle open/close by clicking the hidden checkbox. */
331
+ async toggle() {
332
+ return await this.checkbox().click(), this;
333
+ }
334
+ /** Whether the collapse is currently open (checkbox checked). */
335
+ async isOpen() {
336
+ return this.checkbox().isChecked();
337
+ }
338
+ /** The title text element. */
339
+ title() {
340
+ return this.locator.locator(".collapse-title span").first();
341
+ }
342
+ /** The content wrapper. */
343
+ content() {
344
+ return this.locator.locator(".collapse-content");
345
+ }
346
+ checkbox() {
347
+ return this.locator.locator('input[type="checkbox"]');
348
+ }
349
+ }
350
+ class w extends r {
351
+ /** Resolve the alert by its message text. */
352
+ static byMessage(t, a) {
353
+ return new w(
354
+ t.getByRole("alert").filter({ hasText: a })
355
+ );
356
+ }
357
+ /** Resolve the first (or only) alert on the page. */
358
+ static first(t) {
359
+ return new w(t.getByRole("alert").first());
360
+ }
361
+ static for(t) {
362
+ return new w(t);
363
+ }
364
+ async message() {
365
+ return await this.locator.locator("span").textContent() ?? "";
366
+ }
367
+ async hasClass(t) {
368
+ return (await this.locator.getAttribute("class") ?? "").includes(t);
369
+ }
370
+ }
371
+ class g extends r {
372
+ /** Resolve the drawer as the `<main>` containing the panels. */
373
+ static root(t) {
374
+ return new g(t.locator("main").first());
375
+ }
376
+ static for(t) {
377
+ return new g(t);
378
+ }
379
+ async toggleLeft() {
380
+ return await this.leftButton().click(), this;
381
+ }
382
+ async toggleRight() {
383
+ return await this.rightButton().click(), this;
384
+ }
385
+ async isLeftOpen() {
386
+ return await this.leftButton().getAttribute("aria-expanded") === "true";
387
+ }
388
+ async isRightOpen() {
389
+ return await this.rightButton().getAttribute("aria-expanded") === "true";
390
+ }
391
+ leftPanel() {
392
+ return this.locator.locator("#drawer-left-panel");
393
+ }
394
+ rightPanel() {
395
+ return this.locator.locator("#drawer-right-panel");
396
+ }
397
+ leftButton() {
398
+ return this.locator.locator('button[aria-controls="drawer-left-panel"]');
399
+ }
400
+ rightButton() {
401
+ return this.locator.locator('button[aria-controls="drawer-right-panel"]');
402
+ }
403
+ }
404
+ export {
405
+ w as AlertHarness,
406
+ n as AutocompleteHarness,
407
+ s as BooleanHarness,
408
+ b as ButtonHarness,
409
+ p as CollapseHarness,
410
+ g as DrawerHarness,
411
+ r as Harness,
412
+ h as MarkdownHarness,
413
+ y as ModalHarness,
414
+ u as MultiSelectHarness,
415
+ o as NumberHarness,
416
+ l as SelectHarness,
417
+ c as TextAreaHarness,
418
+ i as TextHarness,
419
+ e as byRole
420
+ };