or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-utilities.mdconfiguration.mdevents.mdindex.mdqueries.mdscoping.mduser-interactions.md

configuration.mddocs/

0

# Configuration and Utilities

1

2

Configuration options and utility functions for customizing Testing Library behavior and building custom queries. These utilities provide advanced functionality for debugging, configuration, and extending the library's capabilities.

3

4

## Capabilities

5

6

### Configuration

7

8

Global configuration options for customizing Testing Library behavior.

9

10

```typescript { .api }

11

/**

12

* Configure global Testing Library options

13

* @param options - Configuration options to set

14

*/

15

function configure(options: ConfigureOptions): void;

16

17

/**

18

* Get current Testing Library configuration

19

* @returns Current configuration object

20

*/

21

function getConfig(): Config;

22

23

/**

24

* Configuration options for Testing Library

25

*/

26

interface ConfigureOptions {

27

/** Custom attribute to use for test IDs (default: 'data-testid') */

28

testIdAttribute?: string;

29

/** Default timeout for async utilities in milliseconds (default: 1000) */

30

asyncUtilTimeout?: number;

31

/** Whether computed styles support pseudo-elements (default: false) */

32

computedStyleSupportsPseudoElements?: boolean;

33

/** Whether hidden elements should be ignored by default (default: false) */

34

defaultHidden?: boolean;

35

/** Show original stack trace in error messages (default: false) */

36

showOriginalStackTrace?: boolean;

37

/** Custom normalizer function for text matching */

38

defaultNormalizer?: (text: string) => string;

39

/** Ignore specific elements in queries (default: 'script, style') */

40

defaultIgnore?: string;

41

/** Throw errors on multiple elements found (default: true) */

42

throwSuggestions?: boolean;

43

}

44

45

/**

46

* Current configuration object

47

*/

48

interface Config {

49

testIdAttribute: string;

50

asyncUtilTimeout: number;

51

computedStyleSupportsPseudoElements: boolean;

52

defaultHidden: boolean;

53

showOriginalStackTrace: boolean;

54

defaultNormalizer: (text: string) => string;

55

defaultIgnore: string;

56

throwSuggestions: boolean;

57

}

58

```

59

60

### Query Building

61

62

Utilities for building custom query functions that follow Testing Library patterns.

63

64

```typescript { .api }

65

/**

66

* Build a complete set of query functions from a base queryAllBy function

67

* @param queryAllBy - Function that returns all matching elements

68

* @param getMultipleError - Function to generate error when multiple elements found

69

* @param getMissingError - Function to generate error when no elements found

70

* @returns Complete set of query functions (getBy, getAllBy, queryBy, queryAllBy, findBy, findAllBy)

71

*/

72

function buildQueries<T extends (...args: any[]) => HTMLElement[]>(

73

queryAllBy: T,

74

getMultipleError: (container: HTMLElement, ...args: Parameters<T>) => string,

75

getMissingError: (container: HTMLElement, ...args: Parameters<T>) => string

76

): QueryHelpers<T>;

77

78

/**

79

* Generated query functions from buildQueries

80

*/

81

interface QueryHelpers<T extends (...args: any[]) => HTMLElement[]> {

82

queryBy: (...args: Parameters<T>) => HTMLElement | null;

83

queryAllBy: T;

84

getBy: (...args: Parameters<T>) => HTMLElement;

85

getAllBy: T;

86

findBy: (...args: Parameters<T>) => Promise<HTMLElement>;

87

findAllBy: (...args: Parameters<T>) => Promise<HTMLElement[]>;

88

}

89

90

/**

91

* Object containing query helper functions

92

*/

93

declare const queryHelpers: {

94

buildQueries: typeof buildQueries;

95

getElementError: (message: string, container: HTMLElement) => Error;

96

wrapAllByQueryWithSuggestion: <T extends (...args: any[]) => HTMLElement[]>(

97

query: T,

98

queryAllByName: string,

99

container: HTMLElement

100

) => T;

101

};

102

103

/**

104

* Pre-built queries object containing all standard query functions

105

*/

106

declare const queries: {

107

queryByRole: (container: HTMLElement, role: string, options?: ByRoleOptions) => HTMLElement | null;

108

queryAllByRole: (container: HTMLElement, role: string, options?: ByRoleOptions) => HTMLElement[];

109

getByRole: (container: HTMLElement, role: string, options?: ByRoleOptions) => HTMLElement;

110

getAllByRole: (container: HTMLElement, role: string, options?: ByRoleOptions) => HTMLElement[];

111

findByRole: (container: HTMLElement, role: string, options?: ByRoleOptions) => Promise<HTMLElement>;

112

findAllByRole: (container: HTMLElement, role: string, options?: ByRoleOptions) => Promise<HTMLElement[]>;

113

// ... similar patterns for Text, TestId, LabelText, PlaceholderText, AltText, Title, DisplayValue

114

};

115

```

116

117

### Text Utilities

118

119

Utilities for working with element text content and normalization.

120

121

```typescript { .api }

122

/**

123

* Get the text content of a node, including descendant text

124

* @param node - Node to get text from

125

* @returns Text content of the node

126

*/

127

function getNodeText(node: Node): string;

128

129

/**

130

* Get the default text normalizer function

131

* @param options - Normalization options

132

* @returns Normalizer function

133

*/

134

function getDefaultNormalizer(options?: NormalizerOptions): (text: string) => string;

135

136

/**

137

* Options for text normalization

138

*/

139

interface NormalizerOptions {

140

/** Remove leading and trailing whitespace (default: true) */

141

trim?: boolean;

142

/** Collapse consecutive whitespace to single spaces (default: true) */

143

collapseWhitespace?: boolean;

144

}

145

```

146

147

### Accessibility Utilities

148

149

Utilities for working with accessibility features and ARIA roles.

150

151

```typescript { .api }

152

/**

153

* Get all available ARIA roles for an element

154

* @param element - Element to get roles for

155

* @returns Array of available roles

156

*/

157

function getRoles(element: HTMLElement): string[];

158

159

/**

160

* Check if an element is inaccessible (hidden from screen readers)

161

* @param element - Element to check

162

* @returns True if element is inaccessible

163

*/

164

function isInaccessible(element: HTMLElement): boolean;

165

166

/**

167

* Get suggested query method for finding an element

168

* @param element - Element to get suggestion for

169

* @param variant - Query variant to suggest (get, query, find)

170

* @param method - Specific method preference

171

* @returns Suggested query method as string

172

*/

173

function getSuggestedQuery(

174

element: HTMLElement,

175

variant?: 'get' | 'query' | 'find',

176

method?: string

177

): string;

178

```

179

180

### Debugging Utilities

181

182

Utilities for debugging and inspecting DOM elements during testing.

183

184

```typescript { .api }

185

/**

186

* Pretty-print DOM elements for debugging

187

* @param element - Element to pretty-print

188

* @param maxLength - Maximum length of output (default: 7000)

189

* @param options - Pretty printing options

190

* @returns Formatted string representation of element

191

*/

192

function prettyDOM(

193

element?: Element | HTMLDocument | null,

194

maxLength?: number,

195

options?: PrettyDOMOptions

196

): string;

197

198

/**

199

* Log DOM tree to console

200

* @param element - Element to log (defaults to document.body)

201

* @param maxLength - Maximum length of output

202

* @param options - Pretty printing options

203

*/

204

function logDOM(

205

element?: Element | HTMLDocument | null,

206

maxLength?: number,

207

options?: PrettyDOMOptions

208

): void;

209

210

/**

211

* Log available ARIA roles to console

212

* @param element - Container element (defaults to document.body)

213

*/

214

function logRoles(element?: Element | HTMLDocument): void;

215

216

/**

217

* Options for pretty DOM printing

218

*/

219

interface PrettyDOMOptions {

220

/** Highlight matching elements */

221

highlight?: boolean;

222

/** Filter out certain elements */

223

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

224

}

225

226

/**

227

* Pretty format values for display (from pretty-format library)

228

* @param value - Value to format

229

* @param options - Formatting options

230

* @returns Formatted string representation

231

*/

232

function prettyFormat(value: any, options?: PrettyFormatOptions): string;

233

234

/**

235

* Options for pretty formatting

236

*/

237

interface PrettyFormatOptions {

238

/** Maximum depth to traverse (default: Infinity) */

239

maxDepth?: number;

240

/** Minimum number of elements to trigger multi-line (default: Infinity) */

241

min?: boolean;

242

/** Include function names (default: false) */

243

printFunctionName?: boolean;

244

}

245

```

246

247

### Error Handling

248

249

Utilities for error handling and reporting.

250

251

```typescript { .api }

252

/**

253

* Get detailed error message for element queries

254

* @param message - Base error message

255

* @param container - Container element that was searched

256

* @returns Enhanced error object with debugging information

257

*/

258

function getElementError(message: string, container: HTMLElement): Error;

259

```

260

261

## Usage Examples

262

263

### Basic Configuration

264

265

```typescript

266

import { configure, getConfig } from "@storybook/testing-library";

267

268

export const ConfigurationExample = {

269

play: async () => {

270

// Configure Testing Library

271

configure({

272

testIdAttribute: 'data-test-id', // Use custom test ID attribute

273

asyncUtilTimeout: 2000, // Increase default timeout to 2 seconds

274

defaultHidden: true, // Include hidden elements by default

275

showOriginalStackTrace: true // Show full stack traces in errors

276

});

277

278

// Get current configuration

279

const config = getConfig();

280

console.log('Current timeout:', config.asyncUtilTimeout);

281

console.log('Test ID attribute:', config.testIdAttribute);

282

}

283

};

284

```

285

286

### Custom Text Normalizer

287

288

```typescript

289

import { configure, getDefaultNormalizer } from "@storybook/testing-library";

290

291

export const CustomNormalizerExample = {

292

play: async () => {

293

// Create custom normalizer that removes extra characters

294

const customNormalizer = getDefaultNormalizer({

295

trim: true,

296

collapseWhitespace: true

297

});

298

299

// Apply custom normalizer globally

300

configure({

301

defaultNormalizer: (text: string) => {

302

// First apply default normalization

303

const normalized = customNormalizer(text);

304

// Then apply custom logic

305

return normalized.replace(/[^\w\s]/gi, ''); // Remove special characters

306

}

307

});

308

}

309

};

310

```

311

312

### Building Custom Queries

313

314

```typescript

315

import { buildQueries, within } from "@storybook/testing-library";

316

317

// Build custom query for elements with specific CSS class

318

const queryAllByClass = (container: HTMLElement, className: string) => {

319

return Array.from(container.querySelectorAll(`.${className}`));

320

};

321

322

const getMultipleError = (container: HTMLElement, className: string) =>

323

`Found multiple elements with class: ${className}`;

324

325

const getMissingError = (container: HTMLElement, className: string) =>

326

`Unable to find element with class: ${className}`;

327

328

const [

329

queryByClass,

330

getAllByClass,

331

getByClass,

332

findAllByClass,

333

findByClass,

334

queryAllByClass

335

] = buildQueries(queryAllByClass, getMultipleError, getMissingError);

336

337

export const CustomQueriesExample = {

338

play: async ({ canvasElement }) => {

339

const canvas = within(canvasElement);

340

341

// Use custom queries (need to bind to container manually)

342

const errorElement = getByClass(canvasElement, 'error-message');

343

const warningElements = getAllByClass(canvasElement, 'warning');

344

const optionalElement = queryByClass(canvasElement, 'optional');

345

346

expect(errorElement).toBeInTheDocument();

347

expect(warningElements).toHaveLength(2);

348

expect(optionalElement).toBeNull();

349

}

350

};

351

```

352

353

### Debugging with Pretty DOM

354

355

```typescript

356

import { within, prettyDOM, logDOM, logRoles } from "@storybook/testing-library";

357

358

export const DebuggingExample = {

359

play: async ({ canvasElement }) => {

360

const canvas = within(canvasElement);

361

362

// Pretty print specific element

363

const form = canvas.getByRole('form');

364

console.log('Form HTML:', prettyDOM(form));

365

366

// Log entire DOM tree

367

logDOM(canvasElement);

368

369

// Log available roles

370

logRoles(canvasElement);

371

372

// Pretty print with options

373

const table = canvas.getByRole('table');

374

console.log('Table (limited):', prettyDOM(table, 1000, {

375

highlight: true,

376

filterNode: (node) => node.nodeType === Node.ELEMENT_NODE

377

}));

378

}

379

};

380

```

381

382

### Accessibility Utilities

383

384

```typescript

385

import { within, getRoles, isInaccessible, getSuggestedQuery } from "@storybook/testing-library";

386

387

export const AccessibilityExample = {

388

play: async ({ canvasElement }) => {

389

const canvas = within(canvasElement);

390

391

// Check available roles

392

const button = canvas.getByRole('button');

393

const availableRoles = getRoles(button);

394

console.log('Available roles for button:', availableRoles);

395

396

// Check if element is accessible

397

const hiddenElement = canvas.getByTestId('hidden-element');

398

const isHidden = isInaccessible(hiddenElement);

399

console.log('Element is inaccessible:', isHidden);

400

401

// Get suggested query

402

const input = canvas.getByLabelText(/username/i);

403

const suggestion = getSuggestedQuery(input, 'get');

404

console.log('Suggested query:', suggestion);

405

}

406

};

407

```

408

409

### Text Utilities

410

411

```typescript

412

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

413

414

export const TextUtilitiesExample = {

415

play: async ({ canvasElement }) => {

416

const canvas = within(canvasElement);

417

418

// Get text content including nested elements

419

const container = canvas.getByTestId('text-container');

420

const fullText = getNodeText(container);

421

console.log('Full text content:', fullText);

422

423

// Use custom normalizer

424

const normalizer = getDefaultNormalizer({

425

trim: true,

426

collapseWhitespace: true

427

});

428

429

const rawText = ' Hello World \n\n ';

430

const normalizedText = normalizer(rawText);

431

console.log('Normalized text:', normalizedText); // "Hello World"

432

}

433

};

434

```

435

436

### Error Handling

437

438

```typescript

439

import { within, getElementError } from "@storybook/testing-library";

440

441

export const ErrorHandlingExample = {

442

play: async ({ canvasElement }) => {

443

const canvas = within(canvasElement);

444

445

try {

446

// This will throw if element not found

447

canvas.getByText(/non-existent text/i);

448

} catch (error) {

449

// Enhance error with debugging info

450

const enhancedError = getElementError(

451

'Custom error message: Element not found',

452

canvasElement

453

);

454

console.error('Enhanced error:', enhancedError.message);

455

}

456

}

457

};

458

```

459

460

### Advanced Configuration

461

462

```typescript

463

import { configure } from "@storybook/testing-library";

464

465

export const AdvancedConfigExample = {

466

play: async () => {

467

configure({

468

// Use custom test ID attribute

469

testIdAttribute: 'data-cy',

470

471

// Increase timeout for slow operations

472

asyncUtilTimeout: 5000,

473

474

// Custom text normalizer

475

defaultNormalizer: (text: string) => {

476

return text

477

.toLowerCase()

478

.replace(/\s+/g, ' ')

479

.trim()

480

.replace(/[^\w\s]/g, '');

481

},

482

483

// Include hidden elements in queries

484

defaultHidden: false,

485

486

// Show full error stack traces

487

showOriginalStackTrace: true,

488

489

// Custom ignore pattern

490

defaultIgnore: 'script, style, [data-ignore]',

491

492

// Disable query suggestions

493

throwSuggestions: false

494

});

495

}

496

};

497

```

498

499

### Performance Optimization

500

501

```typescript

502

import { configure, within } from "@storybook/testing-library";

503

504

export const PerformanceExample = {

505

play: async ({ canvasElement }) => {

506

// Configure for better performance

507

configure({

508

asyncUtilTimeout: 500, // Shorter timeout for fast tests

509

computedStyleSupportsPseudoElements: false, // Disable if not needed

510

throwSuggestions: false // Reduce error message computation

511

});

512

513

const canvas = within(canvasElement);

514

515

// Use more specific queries for better performance

516

const button = canvas.getByRole('button', { name: /exact text/i });

517

const input = canvas.getByLabelText(/specific label/i);

518

519

expect(button).toBeInTheDocument();

520

expect(input).toBeInTheDocument();

521

}

522

};

523

```