or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-utilities.mdasync.mdconfig.mdconfiguration.mddebugging.mdevents.mdindex.mdqueries.mdquery-helpers.mdrole-utilities.mdscreen.mdutilities.mdwithin.md

utilities.mddocs/

0

# Utilities

1

2

Text processing, DOM debugging, role helpers, and other utility functions for enhanced testing capabilities. These utilities provide support for text extraction, accessibility analysis, DOM formatting, and query optimization.

3

4

## Capabilities

5

6

### Text Processing

7

8

Extract and normalize text content from DOM nodes.

9

10

```typescript { .api }

11

function getNodeText(node: HTMLElement): string;

12

13

function getDefaultNormalizer(

14

options?: DefaultNormalizerOptions,

15

): NormalizerFn;

16

17

interface DefaultNormalizerOptions {

18

trim?: boolean;

19

collapseWhitespace?: boolean;

20

}

21

22

type NormalizerFn = (text: string) => string;

23

```

24

25

**Usage Examples:**

26

27

```typescript

28

import { getNodeText, getDefaultNormalizer } from "@testing-library/dom";

29

30

// Extract text from DOM node

31

const button = document.querySelector('button');

32

const buttonText = getNodeText(button);

33

console.log(buttonText); // "Click me"

34

35

// Extract text from complex nested structure

36

const card = document.querySelector('.card');

37

const cardText = getNodeText(card);

38

// Returns all text content including nested elements

39

40

// Create custom normalizer

41

const normalizer = getDefaultNormalizer({

42

trim: true,

43

collapseWhitespace: true,

44

});

45

46

const messyText = " Multiple spaces\n\nand newlines ";

47

const cleanText = normalizer(messyText);

48

console.log(cleanText); // "Multiple spaces and newlines"

49

50

// Use normalizer in queries

51

const element = getByText(container, "Some text", {

52

normalizer: getDefaultNormalizer({ trim: false }),

53

});

54

```

55

56

### DOM Debugging and Pretty Printing

57

58

Format DOM elements for debugging and console output.

59

60

```typescript { .api }

61

function prettyDOM(

62

dom?: Element | HTMLDocument,

63

maxLength?: number,

64

options?: PrettyDOMOptions,

65

): string | false;

66

67

function logDOM(

68

dom?: Element | HTMLDocument,

69

maxLength?: number,

70

options?: PrettyDOMOptions,

71

): void;

72

73

interface PrettyDOMOptions extends prettyFormat.OptionsReceived {

74

filterNode?: (node: Node) => boolean;

75

}

76

```

77

78

**Usage Examples:**

79

80

```typescript

81

import { prettyDOM, logDOM } from "@testing-library/dom";

82

83

// Format entire document

84

const formatted = prettyDOM(document.body);

85

console.log(formatted);

86

87

// Format specific element

88

const modal = document.querySelector('[role="dialog"]');

89

const modalHTML = prettyDOM(modal);

90

91

// Limit output length

92

const shortFormat = prettyDOM(modal, 500);

93

94

// Log to console directly

95

logDOM(modal); // Prints formatted HTML to console

96

97

// Custom filtering

98

const customFormatted = prettyDOM(modal, undefined, {

99

filterNode: (node) => {

100

// Exclude script and style tags

101

return !['SCRIPT', 'STYLE'].includes(node.nodeName);

102

},

103

});

104

105

// Use in test debugging

106

test("modal content", () => {

107

render(App);

108

109

const modal = getByRole(document.body, "dialog");

110

111

// Debug when test fails

112

console.log("Modal content:", prettyDOM(modal));

113

114

// Or log directly

115

logDOM(modal);

116

});

117

118

// Format with styling options

119

const styledFormat = prettyDOM(element, undefined, {

120

highlight: true,

121

theme: {

122

tag: 'cyan',

123

content: 'reset',

124

prop: 'yellow',

125

},

126

});

127

```

128

129

### Role and Accessibility Helpers

130

131

Analyze accessibility roles and states of DOM elements.

132

133

```typescript { .api }

134

function getRoles(container: HTMLElement): {

135

[index: string]: HTMLElement[];

136

};

137

138

function logRoles(

139

container: HTMLElement,

140

options?: LogRolesOptions,

141

): string;

142

143

interface LogRolesOptions {

144

hidden?: boolean;

145

}

146

147

function isInaccessible(element: Element): boolean;

148

149

function computeHeadingLevel(element: Element): number | undefined;

150

```

151

152

**Usage Examples:**

153

154

```typescript

155

import { getRoles, logRoles, isInaccessible, computeHeadingLevel } from "@testing-library/dom";

156

157

// Get all roles in container

158

const container = document.body;

159

const roles = getRoles(container);

160

161

console.log(roles);

162

// {

163

// button: [<button>Submit</button>, <button>Cancel</button>],

164

// textbox: [<input type="text">],

165

// heading: [<h1>Title</h1>, <h2>Subtitle</h2>],

166

// list: [<ul>...</ul>],

167

// listitem: [<li>Item 1</li>, <li>Item 2</li>]

168

// }

169

170

// Log roles to console

171

logRoles(container);

172

// Prints formatted list of all roles and their elements

173

174

// Include hidden elements

175

logRoles(container, { hidden: true });

176

177

// Check if element is accessible

178

const hiddenDiv = document.querySelector('.visually-hidden');

179

const isHidden = isInaccessible(hiddenDiv);

180

console.log(isHidden); // true or false

181

182

// Get heading level

183

const heading = document.querySelector('h2');

184

const level = computeHeadingLevel(heading);

185

console.log(level); // 2

186

187

const ariaHeading = document.querySelector('[role="heading"][aria-level="3"]');

188

const ariaLevel = computeHeadingLevel(ariaHeading);

189

console.log(ariaLevel); // 3

190

191

// Accessibility testing workflow

192

function analyzeAccessibility(container) {

193

console.log("=== Accessibility Analysis ===");

194

195

// Show all roles

196

console.log("Available roles:");

197

logRoles(container);

198

199

// Check for inaccessible elements

200

const allElements = container.querySelectorAll('*');

201

const inaccessibleElements = Array.from(allElements).filter(isInaccessible);

202

203

console.log("Inaccessible elements:", inaccessibleElements.length);

204

205

// Analyze heading structure

206

const headings = container.querySelectorAll('h1, h2, h3, h4, h5, h6, [role="heading"]');

207

console.log("Heading structure:");

208

headings.forEach(heading => {

209

const level = computeHeadingLevel(heading);

210

const text = getNodeText(heading);

211

console.log(` Level ${level}: ${text}`);

212

});

213

}

214

```

215

216

### Query Suggestions

217

218

Get recommended queries for elements to improve test maintainability.

219

220

```typescript { .api }

221

function getSuggestedQuery(

222

element: HTMLElement,

223

variant?: Variant,

224

method?: Method,

225

): Suggestion | undefined;

226

227

interface Suggestion {

228

queryName: string;

229

queryMethod: string;

230

queryArgs: QueryArgs;

231

variant: string;

232

warning?: string;

233

toString(): string;

234

}

235

236

type Variant = 'find' | 'findAll' | 'get' | 'getAll' | 'query' | 'queryAll';

237

type Method = 'AltText' | 'alttext' | 'DisplayValue' | 'displayvalue' | 'LabelText' | 'labeltext' | 'PlaceholderText' | 'placeholdertext' | 'Role' | 'role' | 'TestId' | 'testid' | 'Text' | 'text' | 'Title' | 'title';

238

type QueryArgs = [string, QueryOptions?];

239

240

interface QueryOptions {

241

[key: string]: RegExp | boolean;

242

}

243

```

244

245

**Usage Examples:**

246

247

```typescript

248

import { getSuggestedQuery } from "@testing-library/dom";

249

250

// Get suggestion for button element

251

const button = document.querySelector('button[data-testid="submit-btn"]');

252

const suggestion = getSuggestedQuery(button);

253

254

if (suggestion) {

255

console.log(suggestion.toString());

256

// Might suggest: getByRole('button', { name: 'Submit' })

257

// instead of getByTestId('submit-btn')

258

259

console.log("Query method:", suggestion.queryMethod);

260

console.log("Query args:", suggestion.queryArgs);

261

262

if (suggestion.warning) {

263

console.log("Warning:", suggestion.warning);

264

}

265

}

266

267

// Get specific variant suggestion

268

const getAllSuggestion = getSuggestedQuery(button, 'getAll');

269

const findSuggestion = getSuggestedQuery(button, 'find');

270

271

// Get suggestion for specific method

272

const roleSuggestion = getSuggestedQuery(button, 'get', 'Role');

273

const textSuggestion = getSuggestedQuery(button, 'get', 'Text');

274

275

// Use in test optimization

276

function optimizeQuery(element) {

277

const suggestion = getSuggestedQuery(element);

278

279

if (suggestion) {

280

console.log("Current query could be improved:");

281

console.log("Suggested:", suggestion.toString());

282

283

if (suggestion.warning) {

284

console.log("Note:", suggestion.warning);

285

}

286

} else {

287

console.log("No better query suggestion available");

288

}

289

}

290

291

// Batch analyze elements

292

function analyzeQueries(container) {

293

const testIdElements = container.querySelectorAll('[data-testid]');

294

295

console.log("Query optimization suggestions:");

296

testIdElements.forEach((element, index) => {

297

const testId = element.getAttribute('data-testid');

298

const suggestion = getSuggestedQuery(element);

299

300

console.log(`\n${index + 1}. Element with testid="${testId}"`);

301

302

if (suggestion) {

303

console.log(` Better query: ${suggestion.toString()}`);

304

} else {

305

console.log(" No better alternative found");

306

}

307

});

308

}

309

```

310

311

### Query Building Utilities

312

313

Low-level utilities for building custom queries.

314

315

```typescript { .api }

316

type QueryByAttribute = (

317

attribute: string,

318

container: HTMLElement,

319

id: Matcher,

320

options?: MatcherOptions,

321

) => HTMLElement | null;

322

323

type AllByAttribute = (

324

attribute: string,

325

container: HTMLElement,

326

id: Matcher,

327

options?: MatcherOptions,

328

) => HTMLElement[];

329

330

declare const queryByAttribute: QueryByAttribute;

331

declare const queryAllByAttribute: AllByAttribute;

332

333

function getElementError(

334

message: string | null,

335

container: HTMLElement,

336

): Error;

337

338

function buildQueries<Arguments extends any[]>(

339

queryAllBy: GetAllBy<Arguments>,

340

getMultipleError: GetErrorFunction<Arguments>,

341

getMissingError: GetErrorFunction<Arguments>,

342

): BuiltQueryMethods<Arguments>;

343

344

type BuiltQueryMethods<Arguments extends any[]> = [

345

QueryBy<Arguments>,

346

GetAllBy<Arguments>,

347

GetBy<Arguments>,

348

FindAllBy<Arguments>,

349

FindBy<Arguments>,

350

];

351

```

352

353

**Usage Examples:**

354

355

```typescript

356

import { queryByAttribute, queryAllByAttribute, buildQueries } from "@testing-library/dom";

357

358

// Query by custom attribute

359

const elementByDataId = queryByAttribute('data-id', container, 'user-123');

360

const elementsByClass = queryAllByAttribute('class', container, 'btn-primary');

361

362

// Build custom query set

363

const queryAllByDataId = (container, id, options) =>

364

queryAllByAttribute('data-id', container, id, options);

365

366

const getMultipleError = (container, id) =>

367

`Found multiple elements with data-id="${id}"`;

368

369

const getMissingError = (container, id) =>

370

`Unable to find element with data-id="${id}"`;

371

372

const [

373

queryByDataId,

374

getAllByDataId,

375

getByDataId,

376

findAllByDataId,

377

findByDataId,

378

] = buildQueries(queryAllByDataId, getMultipleError, getMissingError);

379

380

// Use custom queries

381

const user = getByDataId(container, 'user-123');

382

const allUsers = getAllByDataId(container, /user-\d+/);

383

const maybeUser = queryByDataId(container, 'user-456');

384

```

385

386

## Types

387

388

```typescript { .api }

389

// Text processing types

390

type NormalizerFn = (text: string) => string;

391

392

interface DefaultNormalizerOptions {

393

trim?: boolean;

394

collapseWhitespace?: boolean;

395

}

396

397

// Pretty DOM types

398

interface PrettyDOMOptions extends prettyFormat.OptionsReceived {

399

filterNode?: (node: Node) => boolean;

400

}

401

402

// Role helpers types

403

interface LogRolesOptions {

404

hidden?: boolean;

405

}

406

407

// Suggestion types

408

interface Suggestion {

409

queryName: string;

410

queryMethod: string;

411

queryArgs: QueryArgs;

412

variant: string;

413

warning?: string;

414

toString(): string;

415

}

416

417

type Variant = 'find' | 'findAll' | 'get' | 'getAll' | 'query' | 'queryAll';

418

type Method = 'AltText' | 'alttext' | 'DisplayValue' | 'displayvalue' | 'LabelText' | 'labeltext' | 'PlaceholderText' | 'placeholdertext' | 'Role' | 'role' | 'TestId' | 'testid' | 'Text' | 'text' | 'Title' | 'title';

419

type QueryArgs = [string, QueryOptions?];

420

421

interface QueryOptions {

422

[key: string]: RegExp | boolean;

423

}

424

425

// Query building types

426

type QueryByAttribute = (

427

attribute: string,

428

container: HTMLElement,

429

id: Matcher,

430

options?: MatcherOptions,

431

) => HTMLElement | null;

432

433

type AllByAttribute = (

434

attribute: string,

435

container: HTMLElement,

436

id: Matcher,

437

options?: MatcherOptions,

438

) => HTMLElement[];

439

440

type GetErrorFunction<Arguments extends any[] = [string]> = (

441

c: Element | null,

442

...args: Arguments

443

) => string;

444

```