0
# Utilities
1
2
Development tools for debugging element queries, DOM inspection, and test development with pretty-printing and error formatting to improve the debugging experience.
3
4
## Capabilities
5
6
### Debug Function
7
8
Console logging utility for inspecting elements and locators during test development.
9
10
```typescript { .api }
11
/**
12
* Console debug utility for elements and locators. Logs element information
13
* to the console with pretty-printed DOM structure.
14
* @param element - Element(s) or locator(s) to debug, or null/undefined
15
* @param maxLength - Maximum length of output (default based on environment)
16
* @param options - Pretty-printing options
17
*/
18
function debug(
19
element?: Element | Locator | null | (Element | Locator)[],
20
maxLength?: number,
21
options?: PrettyDOMOptions
22
): void;
23
```
24
25
**Usage Examples:**
26
27
```typescript
28
import { debug } from "@vitest/browser/utils";
29
import { page } from "@vitest/browser/context";
30
31
// Debug single element
32
const button = page.getByRole("button").element();
33
debug(button);
34
35
// Debug locator
36
const form = page.getByRole("form");
37
debug(form);
38
39
// Debug multiple elements
40
const inputs = page.getByRole("textbox").elements();
41
debug(inputs);
42
43
// Debug with custom length limit
44
debug(page.getByTestId("complex-component"), 500);
45
46
// Debug with options
47
debug(button, 1000, {
48
highlight: true,
49
printFunctionNames: false
50
});
51
52
// Debug null/undefined (shows "null" or "undefined")
53
const maybeElement = page.getByText("Nonexistent").query();
54
debug(maybeElement); // Logs: "Unable to find element"
55
56
// Debug in test context
57
test("form validation", async () => {
58
const form = page.getByRole("form");
59
const submitButton = form.getByRole("button", { name: "Submit" });
60
61
// Debug elements before interaction
62
debug(form, undefined, { highlight: true });
63
debug(submitButton);
64
65
await userEvent.click(submitButton);
66
67
// Debug state after interaction
68
const errorMessages = page.getByRole("alert").elements();
69
debug(errorMessages);
70
});
71
```
72
73
### Pretty DOM Function
74
75
Format DOM elements as readable strings for logging and test output.
76
77
```typescript { .api }
78
/**
79
* Pretty-print DOM elements as formatted strings
80
* @param dom - Element or locator to format, or null/undefined
81
* @param maxLength - Maximum length of output string
82
* @param options - Pretty-printing formatting options
83
* @returns Formatted string representation of the DOM element
84
*/
85
function prettyDOM(
86
dom?: Element | Locator | undefined | null,
87
maxLength?: number,
88
options?: PrettyDOMOptions
89
): string;
90
```
91
92
**Usage Examples:**
93
94
```typescript
95
import { prettyDOM } from "@vitest/browser/utils";
96
import { page } from "@vitest/browser/context";
97
98
// Format element as string
99
const button = page.getByRole("button").element();
100
const buttonHTML = prettyDOM(button);
101
console.log("Button HTML:", buttonHTML);
102
103
// Format with length limit
104
const longContent = page.getByTestId("content").element();
105
const truncatedHTML = prettyDOM(longContent, 200);
106
107
// Format locator
108
const form = page.getByRole("form");
109
const formHTML = prettyDOM(form);
110
111
// Use in test assertions
112
test("element structure", () => {
113
const menu = page.getByRole("menu").element();
114
const menuHTML = prettyDOM(menu);
115
116
expect(menuHTML).toContain('role="menuitem"');
117
expect(menuHTML).toContain('aria-expanded="true"');
118
});
119
120
// Custom formatting options
121
const customHTML = prettyDOM(button, 500, {
122
highlight: false,
123
printFunctionNames: true
124
});
125
126
// Handle null/undefined
127
const missingElement = page.getByText("Does not exist").query();
128
const result = prettyDOM(missingElement); // Returns empty string or error message
129
```
130
131
### Element Error Function
132
133
Create formatted error messages for missing elements with helpful debugging information.
134
135
```typescript { .api }
136
/**
137
* Create error for missing elements with helpful debugging context
138
* @param selector - Selector string that was used to find the element
139
* @param container - Container element that was searched (optional)
140
* @returns Error object with formatted message and debugging information
141
*/
142
function getElementError(selector: string, container?: Element): Error;
143
```
144
145
**Usage Examples:**
146
147
```typescript
148
import { getElementError } from "@vitest/browser/utils";
149
import { page } from "@vitest/browser/context";
150
151
// Create helpful error for missing elements
152
const findButtonSafely = (buttonText: string) => {
153
const button = page.getByText(buttonText).query();
154
155
if (!button) {
156
throw getElementError(`text="${buttonText}"`);
157
}
158
159
return button;
160
};
161
162
// Use with custom container
163
const findInContainer = (selector: string, container: Element) => {
164
const element = container.querySelector(selector);
165
166
if (!element) {
167
throw getElementError(selector, container);
168
}
169
170
return element;
171
};
172
173
// Enhanced error reporting in custom functions
174
const waitForElement = async (locator: Locator, timeout = 5000) => {
175
const startTime = Date.now();
176
177
while (Date.now() - startTime < timeout) {
178
const element = locator.query();
179
if (element) return element;
180
181
await new Promise(resolve => setTimeout(resolve, 100));
182
}
183
184
// Create informative error
185
throw getElementError(locator.selector);
186
};
187
188
// Integration with test helpers
189
const assertElementExists = (selector: string, message?: string) => {
190
const element = document.querySelector(selector);
191
192
if (!element) {
193
const error = getElementError(selector);
194
if (message) {
195
error.message = `${message}\n\n${error.message}`;
196
}
197
throw error;
198
}
199
200
return element;
201
};
202
```
203
204
### Element Locator Selectors
205
206
Create locator selector methods from existing DOM elements.
207
208
```typescript { .api }
209
/**
210
* Create locator selectors for an existing DOM element
211
* @param element - DOM element to create selectors for
212
* @returns LocatorSelectors object with all selector methods scoped to the element
213
*/
214
function getElementLocatorSelectors(element: Element): LocatorSelectors;
215
```
216
217
**Usage Examples:**
218
219
```typescript
220
import { getElementLocatorSelectors } from "@vitest/browser/utils";
221
222
// Create selectors for existing element
223
const form = document.querySelector("#login-form");
224
const formSelectors = getElementLocatorSelectors(form);
225
226
// Use selector methods scoped to the element
227
const usernameInput = formSelectors.getByLabelText("Username");
228
const submitButton = formSelectors.getByRole("button", { name: "Submit" });
229
const errorAlert = formSelectors.getByRole("alert");
230
231
// Useful for component testing
232
test("login form component", async () => {
233
// Mount component (framework-specific)
234
const component = mountLoginForm();
235
const formElement = component.container.querySelector("form");
236
237
// Create scoped selectors
238
const form = getElementLocatorSelectors(formElement);
239
240
// Test interactions within the component
241
await userEvent.fill(form.getByLabelText("Username"), "testuser");
242
await userEvent.fill(form.getByLabelText("Password"), "password");
243
await userEvent.click(form.getByRole("button", { name: "Login" }));
244
245
// Assert results
246
expect(form.getByText("Welcome testuser")).toBeVisible();
247
});
248
249
// Integration with page object pattern
250
class LoginPage {
251
private selectors: LocatorSelectors;
252
253
constructor(container: Element) {
254
this.selectors = getElementLocatorSelectors(container);
255
}
256
257
async login(username: string, password: string) {
258
await userEvent.fill(this.selectors.getByLabelText("Username"), username);
259
await userEvent.fill(this.selectors.getByLabelText("Password"), password);
260
await userEvent.click(this.selectors.getByRole("button", { name: "Login" }));
261
}
262
263
getErrorMessage() {
264
return this.selectors.getByRole("alert");
265
}
266
}
267
```
268
269
### Debugging Workflows
270
271
Common debugging patterns and workflows using the utilities.
272
273
**Element Discovery:**
274
275
```typescript
276
import { debug, prettyDOM } from "@vitest/browser/utils";
277
import { page } from "@vitest/browser/context";
278
279
// Debug element discovery process
280
test("find submit button", async () => {
281
// Debug entire form structure
282
debug(page.getByRole("form"));
283
284
// Try different selector strategies
285
console.log("By role:", prettyDOM(page.getByRole("button", { name: "Submit" })));
286
console.log("By text:", prettyDOM(page.getByText("Submit")));
287
console.log("By test ID:", prettyDOM(page.getByTestId("submit-btn")));
288
289
// Debug what's actually available
290
const allButtons = page.getByRole("button").elements();
291
console.log(`Found ${allButtons.length} buttons:`);
292
allButtons.forEach((btn, i) => {
293
console.log(`Button ${i + 1}:`, prettyDOM(btn, 100));
294
});
295
});
296
```
297
298
**State Debugging:**
299
300
```typescript
301
// Debug element state changes
302
test("form validation states", async () => {
303
const form = page.getByRole("form");
304
const input = form.getByLabelText("Email");
305
306
console.log("Initial state:");
307
debug(input);
308
309
await userEvent.fill(input, "invalid-email");
310
311
console.log("After invalid input:");
312
debug(input);
313
debug(form.getByRole("alert")); // Error message
314
315
await userEvent.clear(input);
316
await userEvent.fill(input, "valid@example.com");
317
318
console.log("After valid input:");
319
debug(input);
320
});
321
```
322
323
**Error Investigation:**
324
325
```typescript
326
import { getElementError, debug } from "@vitest/browser/utils";
327
328
// Enhanced error reporting
329
const findElementWithDebug = (selector: string) => {
330
try {
331
return page.locator(selector).element();
332
} catch (error) {
333
console.log("Element not found. Available elements:");
334
debug(document.body, 1000);
335
336
throw getElementError(selector);
337
}
338
};
339
340
// Test debugging helper
341
const debugTest = async (testName: string, testFn: () => Promise<void>) => {
342
console.log(`\n=== Debugging: ${testName} ===`);
343
344
try {
345
await testFn();
346
console.log("✅ Test passed");
347
} catch (error) {
348
console.log("❌ Test failed:");
349
console.log("Current page state:");
350
debug(document.body, 2000);
351
throw error;
352
}
353
};
354
```
355
356
### Performance Debugging
357
358
Use utilities to investigate performance issues.
359
360
```typescript
361
import { prettyDOM } from "@vitest/browser/utils";
362
363
// Measure DOM complexity
364
const measureDOMComplexity = (element: Element) => {
365
const html = prettyDOM(element);
366
const elementCount = (html.match(/<[^>]+>/g) || []).length;
367
const textLength = html.length;
368
369
console.log(`DOM Complexity:
370
- Elements: ${elementCount}
371
- Text length: ${textLength}
372
- Estimated complexity: ${elementCount * 10 + textLength}`);
373
};
374
375
// Debug slow selector performance
376
const debugSlowSelector = async (selector: string) => {
377
const start = performance.now();
378
const elements = document.querySelectorAll(selector);
379
const end = performance.now();
380
381
console.log(`Selector "${selector}":
382
- Found: ${elements.length} elements
383
- Time: ${(end - start).toFixed(2)}ms`);
384
385
if (elements.length > 0) {
386
console.log("First element:", prettyDOM(elements[0], 200));
387
}
388
};
389
```
390
391
## Types
392
393
Utility function types and options:
394
395
```typescript { .api }
396
/**
397
* Options for pretty-printing DOM elements
398
*/
399
interface PrettyDOMOptions {
400
/** Whether to highlight the element in output */
401
highlight?: boolean;
402
/** Whether to include function names in output */
403
printFunctionNames?: boolean;
404
/** Additional formatting options (specific to implementation) */
405
[key: string]: any;
406
}
407
408
/**
409
* Locator selector methods interface
410
*/
411
interface LocatorSelectors {
412
getByRole(role: string, options?: LocatorByRoleOptions): Locator;
413
getByLabelText(text: string | RegExp, options?: LocatorOptions): Locator;
414
getByAltText(text: string | RegExp, options?: LocatorOptions): Locator;
415
getByPlaceholder(text: string | RegExp, options?: LocatorOptions): Locator;
416
getByText(text: string | RegExp, options?: LocatorOptions): Locator;
417
getByTitle(text: string | RegExp, options?: LocatorOptions): Locator;
418
getByTestId(text: string | RegExp): Locator;
419
}
420
```