or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assertions.mdcommands.mdcontext.mdindex.mdinteractions.mdlocators.mdproviders.mdserver.mdutilities.md

utilities.mddocs/

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

```