@mk-kit/ui 0.37.0 → 0.38.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.
@@ -0,0 +1,344 @@
1
+ import { ComponentFixture } from '@angular/core/testing';
2
+
3
+ /**
4
+ * Filters every harness lookup accepts. `selector` narrows the host elements
5
+ * considered (e.g. a class or attribute your template sets); `text` matches
6
+ * the host's trimmed text content — a string must match exactly, a RegExp
7
+ * is tested.
8
+ */
9
+ interface MkHarnessFilters {
10
+ selector?: string;
11
+ text?: string | RegExp;
12
+ }
13
+ /** Constructor shape of every harness class: a static `hostSelector`. */
14
+ interface MkHarnessType<T extends MkHarness> {
15
+ new (host: MkTestElement, loader: MkHarnessLoader): T;
16
+ readonly hostSelector: string;
17
+ }
18
+ /** Keys accepted by `MkTestElement.sendKeys` besides printable characters. */
19
+ type MkTestKey = 'Enter' | 'Escape' | 'Tab' | 'Backspace' | 'Delete' | ' ' | 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight' | 'Home' | 'End' | 'PageUp' | 'PageDown';
20
+ /**
21
+ * A DOM element wrapped for tests: reads are synchronous, every interaction
22
+ * dispatches the same events a user would and then settles change detection
23
+ * (`fixture.detectChanges()` + `whenStable()`), so the next read sees the
24
+ * updated view.
25
+ */
26
+ declare class MkTestElement {
27
+ /** The underlying element — reach for it when a harness has no getter. */
28
+ readonly native: HTMLElement;
29
+ /** Flush change detection after an interaction. */
30
+ readonly settle: () => Promise<void>;
31
+ constructor(
32
+ /** The underlying element — reach for it when a harness has no getter. */
33
+ native: HTMLElement,
34
+ /** Flush change detection after an interaction. */
35
+ settle?: () => Promise<void>);
36
+ /** Trimmed text content with whitespace collapsed. */
37
+ text(): string;
38
+ attr(name: string): string | null;
39
+ hasClass(name: string): boolean;
40
+ /** Read a DOM property (`value`, `checked`, `open`, …). */
41
+ prop<T = unknown>(name: string): T;
42
+ matches(selector: string): boolean;
43
+ isFocused(): boolean;
44
+ /** Native `disabled`, `aria-disabled="true"` or a `--disabled` host class. */
45
+ isDisabled(): boolean;
46
+ query(selector: string): MkTestElement | null;
47
+ queryAll(selector: string): MkTestElement[];
48
+ /** Like `query`, but throws a readable error when nothing matches. */
49
+ child(selector: string): MkTestElement;
50
+ /** pointerdown → mousedown → focus → pointerup → mouseup → click, like a user. */
51
+ click(): Promise<void>;
52
+ hover(): Promise<void>;
53
+ leave(): Promise<void>;
54
+ focus(): Promise<void>;
55
+ blur(): Promise<void>;
56
+ /**
57
+ * Type into an input/textarea/contenteditable character by character —
58
+ * keydown, `value` append, `input`, keyup — then settle. Use `setValue`
59
+ * to replace the value in one go.
60
+ */
61
+ type(text: string): Promise<void>;
62
+ /** Set the value of an input/textarea/select and fire `input` + `change`. */
63
+ setValue(value: string): Promise<void>;
64
+ clear(): Promise<void>;
65
+ /** Dispatch keydown/keyup for each key. Printable single characters are also typed. */
66
+ sendKeys(...keys: Array<MkTestKey | (string & {})>): Promise<void>;
67
+ /** Dispatch any event on the element and settle. */
68
+ dispatch(event: Event): Promise<void>;
69
+ private describe;
70
+ }
71
+ /**
72
+ * Finds harnesses under a root element. Create one with
73
+ * `MkHarnessLoader.fromFixture(fixture)`; use `.document()` for content that
74
+ * mk-kit teleports into `document.body` (dialogs, toasts, menus, select
75
+ * panels) and `.within(el)` to scope lookups.
76
+ */
77
+ declare class MkHarnessLoader {
78
+ readonly root: Element;
79
+ readonly settle: () => Promise<void>;
80
+ constructor(root: Element, settle: () => Promise<void>);
81
+ /**
82
+ * Loader rooted at the fixture's host element. Every interaction runs
83
+ * `fixture.detectChanges()` and awaits `fixture.whenStable()` afterwards,
84
+ * so it works in zoneless and zone-based TestBeds alike.
85
+ */
86
+ static fromFixture(fixture: ComponentFixture<unknown>): MkHarnessLoader;
87
+ /** Same settle function, rooted at `document.body` — for overlays. */
88
+ document(): MkHarnessLoader;
89
+ within(root: Element | MkTestElement): MkHarnessLoader;
90
+ /** Wrap the root element itself. */
91
+ rootElement(): MkTestElement;
92
+ element(selector: string): MkTestElement;
93
+ elements(selector: string): MkTestElement[];
94
+ /** First matching harness; throws when there is none. */
95
+ get<T extends MkHarness>(type: MkHarnessType<T>, filters?: MkHarnessFilters): Promise<T>;
96
+ getOrNull<T extends MkHarness>(type: MkHarnessType<T>, filters?: MkHarnessFilters): Promise<T | null>;
97
+ has<T extends MkHarness>(type: MkHarnessType<T>, filters?: MkHarnessFilters): Promise<boolean>;
98
+ getAll<T extends MkHarness>(type: MkHarnessType<T>, filters?: MkHarnessFilters): Promise<T[]>;
99
+ }
100
+ declare function matchText(actual: string, expected: string | RegExp): boolean;
101
+ /**
102
+ * Base class of every mk-kit harness. Subclasses declare `hostSelector`
103
+ * and expose user-level actions (`click()`, `selectOption()`, …) and reads
104
+ * (`isChecked()`, `text()`), so specs never depend on the component's DOM.
105
+ */
106
+ declare abstract class MkHarness {
107
+ /** The component's host element. */
108
+ readonly host: MkTestElement;
109
+ protected readonly loader: MkHarnessLoader;
110
+ static readonly hostSelector: string;
111
+ constructor(
112
+ /** The component's host element. */
113
+ host: MkTestElement, loader: MkHarnessLoader);
114
+ protected settle(): Promise<void>;
115
+ /** Query inside the host. */
116
+ protected q(selector: string): MkTestElement | null;
117
+ protected qAll(selector: string): MkTestElement[];
118
+ /** Query the whole document — for panels teleported to `document.body`. */
119
+ protected qDocument(selector: string): MkTestElement | null;
120
+ /** Element referenced by an `aria-controls` / `aria-owns` id on `from`. */
121
+ protected controlled(from: MkTestElement, attribute?: string): MkTestElement | null;
122
+ }
123
+ /** Resolve "by index or by label" arguments shared by option-style harnesses. */
124
+ declare function pickBy<T>(items: T[], which: number | string | RegExp, label: (item: T) => string, what: string): T;
125
+
126
+ /** `button[mkButton]` / `a[mkButton]`. */
127
+ declare class MkButtonHarness extends MkHarness {
128
+ static readonly hostSelector = "button[mkButton], a[mkButton], .mk-button";
129
+ text(): string;
130
+ click(): Promise<void>;
131
+ focus(): Promise<void>;
132
+ isDisabled(): boolean;
133
+ isLoading(): boolean;
134
+ tone(): string | null;
135
+ /** `solid` | `soft` | `outline` | `ghost` | `link`. */
136
+ variant(): string | null;
137
+ size(): string | null;
138
+ }
139
+ /** Native `input[mkInput]` / `textarea[mkInput]`. */
140
+ declare class MkInputHarness extends MkHarness {
141
+ static readonly hostSelector = "[mkInput], .mk-input";
142
+ value(): string;
143
+ /** Replace the value (fires `input` + `change`). */
144
+ setValue(value: string): Promise<void>;
145
+ /** Append text one character at a time (keydown / input / keyup). */
146
+ type(text: string): Promise<void>;
147
+ clear(): Promise<void>;
148
+ focus(): Promise<void>;
149
+ blur(): Promise<void>;
150
+ placeholder(): string;
151
+ type_(): string;
152
+ isDisabled(): boolean;
153
+ isInvalid(): boolean;
154
+ isRequired(): boolean;
155
+ isFocused(): boolean;
156
+ }
157
+ /** `mk-checkbox`. */
158
+ declare class MkCheckboxHarness extends MkHarness {
159
+ static readonly hostSelector = "mk-checkbox";
160
+ private get input();
161
+ label(): string;
162
+ isChecked(): boolean;
163
+ isIndeterminate(): boolean;
164
+ isDisabled(): boolean;
165
+ isRequired(): boolean;
166
+ toggle(): Promise<void>;
167
+ check(): Promise<void>;
168
+ uncheck(): Promise<void>;
169
+ focus(): Promise<void>;
170
+ blur(): Promise<void>;
171
+ }
172
+ /** `mk-switch`. */
173
+ declare class MkSwitchHarness extends MkHarness {
174
+ static readonly hostSelector = "mk-switch";
175
+ private get control();
176
+ label(): string;
177
+ isChecked(): boolean;
178
+ isDisabled(): boolean;
179
+ toggle(): Promise<void>;
180
+ check(): Promise<void>;
181
+ uncheck(): Promise<void>;
182
+ focus(): Promise<void>;
183
+ }
184
+ /** One `mk-radio` inside a group. */
185
+ declare class MkRadioHarness extends MkHarness {
186
+ static readonly hostSelector = "mk-radio";
187
+ label(): string;
188
+ isChecked(): boolean;
189
+ isDisabled(): boolean;
190
+ select(): Promise<void>;
191
+ focus(): Promise<void>;
192
+ }
193
+ /** `mk-radio-group`. */
194
+ declare class MkRadioGroupHarness extends MkHarness {
195
+ static readonly hostSelector = "mk-radio-group";
196
+ radios(): Promise<MkRadioHarness[]>;
197
+ labels(): Promise<string[]>;
198
+ /** Label of the checked radio, or `null`. */
199
+ checkedLabel(): Promise<string | null>;
200
+ checkedIndex(): Promise<number>;
201
+ /** Select by index, exact label or RegExp. */
202
+ select(which: number | string | RegExp): Promise<void>;
203
+ isDisabled(): boolean;
204
+ }
205
+ interface MkSelectOptionState {
206
+ label: string;
207
+ selected: boolean;
208
+ disabled: boolean;
209
+ }
210
+ /** `mk-select` — opens the teleported listbox and picks options like a user. */
211
+ declare class MkSelectHarness extends MkHarness {
212
+ static readonly hostSelector = "mk-select";
213
+ private get trigger();
214
+ /** Label of the selected option, or `''` when only the placeholder shows. */
215
+ valueText(): string;
216
+ placeholder(): string;
217
+ isOpen(): boolean;
218
+ isDisabled(): boolean;
219
+ isInvalid(): boolean;
220
+ open(): Promise<void>;
221
+ close(): Promise<void>;
222
+ focus(): Promise<void>;
223
+ /** Options of the (opened) listbox. Opens it if needed. */
224
+ options(): Promise<MkSelectOptionState[]>;
225
+ /** Pick an option by index, exact label or RegExp (opens the list first). */
226
+ selectOption(which: number | string | RegExp): Promise<void>;
227
+ private optionElements;
228
+ }
229
+ /** `mk-form-field` — label / hint / error around any control. */
230
+ declare class MkFormFieldHarness extends MkHarness {
231
+ static readonly hostSelector = "mk-form-field";
232
+ label(): string;
233
+ hint(): string | null;
234
+ /** The visible validation message, or `null` when the field is valid/untouched. */
235
+ error(): string | null;
236
+ hasError(): boolean;
237
+ isRequired(): boolean;
238
+ /** The control inside the field, as a harness of the given type. */
239
+ control<T extends MkHarness>(type: Parameters<typeof this$1.loader.get<T>>[0]): Promise<T>;
240
+ }
241
+
242
+ /** `mk-tabs`. */
243
+ declare class MkTabsHarness extends MkHarness {
244
+ static readonly hostSelector = "mk-tabs";
245
+ private tabButtons;
246
+ labels(): string[];
247
+ selectedIndex(): number;
248
+ selectedLabel(): string | null;
249
+ /** Select by index, exact label or RegExp. */
250
+ select(which: number | string | RegExp): Promise<void>;
251
+ isDisabled(which: number | string | RegExp): boolean;
252
+ /** The visible tab panel (`mk-tab` host). */
253
+ selectedPanel(): MkTestElement | null;
254
+ /** Text of the visible panel. */
255
+ selectedPanelText(): string;
256
+ }
257
+ /**
258
+ * A `[mkMenuTriggerFor]` trigger and the `mk-menu` panel it opens. The host
259
+ * is matched by the trigger's `aria-haspopup="menu"` (the directive's
260
+ * attribute is an input binding, so it is not in the DOM).
261
+ */
262
+ declare class MkMenuHarness extends MkHarness {
263
+ static readonly hostSelector = "[aria-haspopup=\"menu\"]";
264
+ isOpen(): boolean;
265
+ open(): Promise<void>;
266
+ close(): Promise<void>;
267
+ /** The teleported panel (`[role="menu"]`), or `null` while closed. */
268
+ panel(): MkTestElement | null;
269
+ /** Item texts of the open menu (opens it if needed). Submenu panels excluded. */
270
+ items(): Promise<string[]>;
271
+ /** Click an item by index, exact text or RegExp (opens the menu first). */
272
+ clickItem(which: number | string | RegExp): Promise<void>;
273
+ isItemDisabled(which: number | string | RegExp): Promise<boolean>;
274
+ private itemElements;
275
+ }
276
+
277
+ /** One data row of `mk-table`. */
278
+ declare class MkTableRowHarness extends MkHarness {
279
+ static readonly hostSelector = "tr.mk-table__row";
280
+ /** Cell texts of the data columns (expand / select cells excluded). */
281
+ cells(): string[];
282
+ cell(index: number): string;
283
+ isSelected(): boolean;
284
+ isExpanded(): boolean;
285
+ click(): Promise<void>;
286
+ /** Toggle the selection checkbox (throws when the table is not `selectable`). */
287
+ toggleSelected(): Promise<void>;
288
+ /** Toggle the expand / tree control of the row. */
289
+ toggleExpanded(): Promise<void>;
290
+ private dataCells;
291
+ }
292
+ /** `mk-table`. */
293
+ declare class MkTableHarness extends MkHarness {
294
+ static readonly hostSelector = "mk-table";
295
+ /** Header labels of the data columns, in display order. */
296
+ headers(): string[];
297
+ rows(): Promise<MkTableRowHarness[]>;
298
+ rowCount(): Promise<number>;
299
+ /** Every data cell as text: `rows()[r].cells()`. */
300
+ cellTexts(): Promise<string[][]>;
301
+ /** Click a sortable header (by index, exact label or RegExp). */
302
+ sortBy(which: number | string | RegExp): Promise<void>;
303
+ /** `'ascending' | 'descending' | 'none' | null` (null = not sortable). */
304
+ sortDirection(which: number | string | RegExp): string | null;
305
+ selectedRowCount(): Promise<number>;
306
+ /** Toggle the header "select all" checkbox. */
307
+ toggleAll(): Promise<void>;
308
+ isEmpty(): boolean;
309
+ private headerCells;
310
+ }
311
+
312
+ /**
313
+ * A dialog opened by `MkDialogService` (`open()`, `confirm()`, `alert()`,
314
+ * `prompt()`). Dialogs live in `document.body`, so look them up through
315
+ * `loader.document()`.
316
+ */
317
+ declare class MkDialogHarness extends MkHarness {
318
+ static readonly hostSelector = ".mk-overlay-panel[role=\"dialog\"], .mk-overlay-panel[role=\"alertdialog\"]";
319
+ title(): string;
320
+ bodyText(): string;
321
+ /** Texts of every button in the dialog (header close excluded). */
322
+ buttons(): string[];
323
+ /** Click a button by index, exact text or RegExp. */
324
+ clickButton(which: number | string | RegExp): Promise<void>;
325
+ /** The header × button. */
326
+ close(): Promise<void>;
327
+ pressEscape(): Promise<void>;
328
+ /** The prompt dialog's text field, if any. */
329
+ input(): MkTestElement | null;
330
+ private buttonElements;
331
+ }
332
+ /** One toast shown by `MkToastService` (lives in `document.body` — use `loader.document()`). */
333
+ declare class MkToastHarness extends MkHarness {
334
+ static readonly hostSelector = "mk-toast";
335
+ title(): string | null;
336
+ message(): string;
337
+ tone(): string | null;
338
+ actionLabel(): string | null;
339
+ clickAction(): Promise<void>;
340
+ dismiss(): Promise<void>;
341
+ }
342
+
343
+ export { MkButtonHarness, MkCheckboxHarness, MkDialogHarness, MkFormFieldHarness, MkHarness, MkHarnessLoader, MkInputHarness, MkMenuHarness, MkRadioGroupHarness, MkRadioHarness, MkSelectHarness, MkSwitchHarness, MkTableHarness, MkTableRowHarness, MkTabsHarness, MkTestElement, MkToastHarness, matchText, pickBy };
344
+ export type { MkHarnessFilters, MkHarnessType, MkSelectOptionState, MkTestKey };
@@ -17,4 +17,5 @@ export * from '@mk-kit/ui/context-menu';
17
17
  export * from '@mk-kit/ui/layout';
18
18
  export * from '@mk-kit/ui/chat';
19
19
  export * from '@mk-kit/ui/query-builder';
20
+ export * from '@mk-kit/ui/dynamic-form';
20
21
  export * from '@mk-kit/ui/media';