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

index.mddocs/

0

# @testing-library/dom

1

2

Simple and complete DOM testing utilities that encourage good testing practices by querying the DOM in the way users find elements. Promotes accessibility-focused testing through queries based on ARIA roles, labels, text content, and other accessible attributes.

3

4

## Package Information

5

6

```json

7

{

8

"name": "@testing-library/dom",

9

"version": "10.4.1",

10

"install": "npm install --save-dev @testing-library/dom"

11

}

12

```

13

14

## Core Imports

15

16

```javascript

17

import {screen, within, waitFor, fireEvent} from '@testing-library/dom';

18

19

// All query methods

20

import {

21

getByRole, queryByRole, findByRole,

22

getByLabelText, queryByLabelText, findByLabelText,

23

getByPlaceholderText, queryByPlaceholderText, findByPlaceholderText,

24

getByText, queryByText, findByText,

25

getByAltText, queryByAltText, findByAltText,

26

getByTitle, queryByTitle, findByTitle,

27

getByDisplayValue, queryByDisplayValue, findByDisplayValue,

28

getByTestId, queryByTestId, findByTestId

29

} from '@testing-library/dom';

30

31

// Plural variants

32

import {

33

getAllBy*, queryAllBy*, findAllBy*

34

} from '@testing-library/dom';

35

36

// Namespace imports for grouped access

37

import {queries, queryHelpers} from '@testing-library/dom';

38

39

// Access queries through namespace

40

const element = queries.getByRole(container, 'button', {name: /submit/i});

41

42

// Access query helpers through namespace

43

const customQuery = queryHelpers.buildQueries(...);

44

```

45

46

## Core Concepts

47

48

### Query Variants

49

50

Every query has three variants with different error handling:

51

52

- **`getBy*`** - Returns element, throws if 0 or 2+ matches found

53

- **`queryBy*`** - Returns element or null if not found, throws if 2+ found

54

- **`findBy*`** - Returns Promise, waits up to 1000ms (async)

55

56

Plural variants return arrays and have different throwing behavior.

57

58

### Query Priority

59

60

Use queries in this order (most accessible to least):

61

62

1. `getByRole` - Accessible to everyone (ARIA roles)

63

2. `getByLabelText` - Form fields

64

3. `getByPlaceholderText` - Form alternative

65

4. `getByText` - Non-interactive content

66

5. `getByDisplayValue` - Current form values

67

6. `getByAltText` - Images

68

7. `getByTitle` - Title attribute

69

8. `getByTestId` - Last resort

70

71

### Screen vs Container

72

73

```javascript

74

// Use screen - queries entire document

75

const button = screen.getByRole('button', {name: /submit/i});

76

77

// Use within for scoped queries

78

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

79

const emailInput = within(form).getByLabelText('Email');

80

```

81

82

## Quick Start Examples

83

84

```javascript

85

import {screen, fireEvent, waitFor} from '@testing-library/dom';

86

87

// Basic query

88

const button = screen.getByRole('button', {name: /submit/i});

89

fireEvent.click(button);

90

91

// Form interaction

92

const email = screen.getByLabelText('Email');

93

fireEvent.change(email, {target: {value: 'user@example.com'}});

94

95

// Async content

96

await waitFor(() => {

97

expect(screen.getByText('Success')).toBeInTheDocument();

98

});

99

100

// Or use findBy directly

101

const message = await screen.findByText('Success');

102

```

103

104

## Architecture

105

106

### Query System

107

- **8 query types**: Role, LabelText, PlaceholderText, Text, DisplayValue, AltText, Title, TestId

108

- **3 variants each**: get, query, find (plus plural variants)

109

- **Screen**: Global queries bound to document.body

110

- **Within**: Scoped queries to containers

111

112

### Async Utilities

113

- `waitFor`: Poll with MutationObserver support

114

- `waitForElementToBeRemoved`: Wait for element removal

115

116

### Events

117

- `fireEvent`: Fire DOM events on elements

118

- `createEvent`: Create events without firing

119

120

### Utilities

121

- **Debugging**: `prettyDOM`, `logDOM`, `screen.debug`, `logTestingPlaygroundURL`

122

- **Configuration**: `configure`, `getConfig`

123

- **Role tools**: `getRoles`, `logRoles`, `isInaccessible`, `computeHeadingLevel`

124

- **Query builders**: `buildQueries`, `queryByAttribute`, `queryAllByAttribute`

125

- **Text tools**: `getNodeText`, `getDefaultNormalizer`

126

- **Query suggestions**: `getSuggestedQuery` for better query recommendations

127

128

## Detailed Documentation

129

130

- [Queries](./queries.md) - All query methods and types

131

- [Events](./events.md) - Event simulation

132

- [Async](./async.md) - Async utilities

133

- [Screen](./screen.md) - Screen object API

134

- [Within](./within.md) - Scoped queries

135

- [Config](./config.md) - Configuration

136

- [Debugging](./debugging.md) - Debug utilities

137

- [Query Helpers](./query-helpers.md) - Custom queries

138

- [Role Utilities](./role-utilities.md) - ARIA utilities

139

140

## Additional Utilities

141

142

### Text Utilities

143

144

Extract text content as users perceive it.

145

146

```typescript

147

function getNodeText(node: HTMLElement): string;

148

```

149

150

Usage:

151

```javascript

152

import {getNodeText} from '@testing-library/dom';

153

154

const element = screen.getByRole('button');

155

const text = getNodeText(element); // Returns visible text content

156

```

157

158

### Matcher Utilities

159

160

Text normalization for customizing query behavior.

161

162

```typescript

163

function getDefaultNormalizer(

164

options?: DefaultNormalizerOptions

165

): NormalizerFn;

166

167

interface DefaultNormalizerOptions {

168

trim?: boolean; // Default: true

169

collapseWhitespace?: boolean; // Default: true

170

}

171

172

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

173

```

174

175

Usage:

176

```javascript

177

import {getDefaultNormalizer, getByText} from '@testing-library/dom';

178

179

// Custom normalizer

180

const normalizer = getDefaultNormalizer({trim: false});

181

const element = getByText(container, 'Text', {normalizer});

182

183

// Case-insensitive matching

184

const caseInsensitive = (text) => text.toLowerCase();

185

const element = getByText(container, 'submit', {normalizer: caseInsensitive});

186

```

187

188

### Query Suggestions

189

190

Get suggested better queries for improving test quality.

191

192

```typescript

193

function getSuggestedQuery(

194

element: HTMLElement,

195

variant?: Variant,

196

method?: Method

197

): Suggestion | undefined;

198

199

interface Suggestion {

200

queryName: string;

201

queryMethod: string;

202

queryArgs: QueryArgs;

203

variant: string;

204

warning?: string;

205

toString(): string;

206

}

207

208

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

209

210

type Method = 'Role' | 'LabelText' | 'PlaceholderText' | 'Text' |

211

'DisplayValue' | 'AltText' | 'Title' | 'TestId';

212

```

213

214

Usage:

215

```javascript

216

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

217

218

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

219

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

220

221

if (suggestion) {

222

console.log(suggestion.toString());

223

// "getByRole('button', {name: /submit/i})"

224

}

225

226

// Use with throwSuggestions config

227

import {configure} from '@testing-library/dom';

228

configure({throwSuggestions: true});

229

230

// Errors now include better query suggestions

231

```

232

233

## TypeScript Support

234

235

All APIs are fully typed. The library provides TypeScript definitions with generic types for element narrowing.

236

237

```typescript

238

import {screen} from '@testing-library/dom';

239

240

// Automatically typed as HTMLElement

241

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

242

243

// Narrow to specific element type

244

const button = screen.getByRole('button') as HTMLButtonElement;

245

246

// Or use generic

247

const button = screen.getByRole<HTMLButtonElement>('button');

248

```

249

250

## Common Patterns

251

252

### Form Testing

253

254

```javascript

255

import {screen, fireEvent} from '@testing-library/dom';

256

257

// Fill form

258

fireEvent.change(screen.getByLabelText('Name'), {target: {value: 'John'}});

259

fireEvent.change(screen.getByLabelText('Email'), {target: {value: 'john@example.com'}});

260

fireEvent.click(screen.getByRole('button', {name: /submit/i}));

261

262

// Verify result

263

expect(screen.getByText('Thank you')).toBeInTheDocument();

264

```

265

266

### Modal Testing

267

268

```javascript

269

import {screen, within, fireEvent} from '@testing-library/dom';

270

271

fireEvent.click(screen.getByRole('button', {name: /open/i}));

272

273

const modal = screen.getByRole('dialog');

274

expect(within(modal).getByText('Modal Title')).toBeInTheDocument();

275

276

fireEvent.click(within(modal).getByRole('button', {name: /close/i}));

277

```

278

279

### Async Content

280

281

```javascript

282

import {screen, fireEvent, waitFor} from '@testing-library/dom';

283

284

fireEvent.click(screen.getByRole('button', {name: /load/i}));

285

286

// Wait for loading to complete

287

await waitFor(() => {

288

expect(screen.queryByText('Loading')).not.toBeInTheDocument();

289

});

290

291

// Verify loaded content

292

expect(screen.getByText('Data loaded')).toBeInTheDocument();

293

```

294

295

## Matchers

296

297

All text-based queries accept a `Matcher` type:

298

299

```typescript

300

type Matcher = string | RegExp | number | MatcherFunction;

301

302

type MatcherFunction = (content: string, element: Element | null) => boolean;

303

304

type ByRoleMatcher = ARIARole | string;

305

306

// Matcher options

307

interface MatcherOptions {

308

exact?: boolean; // Exact string match (default: false)

309

trim?: boolean; // Trim whitespace (default: true)

310

collapseWhitespace?: boolean; // Collapse whitespace (default: true)

311

normalizer?: NormalizerFn; // Custom text normalizer

312

suggest?: boolean; // Include query suggestions in errors

313

}

314

315

interface SelectorMatcherOptions extends MatcherOptions {

316

selector?: string; // CSS selector to narrow results

317

ignore?: boolean | string; // CSS selectors to ignore

318

}

319

```

320

321

Examples:

322

```javascript

323

// String (substring match)

324

getByText(container, 'Submit');

325

326

// Regex

327

getByText(container, /submit/i);

328

329

// Number

330

getByText(container, 42);

331

332

// Function

333

getByText(container, (content, el) => content.startsWith('Total:'));

334

335

// Exact match

336

getByText(container, 'Submit', {exact: true});

337

338

// With selector

339

getByText(container, 'Click me', {selector: 'button'});

340

341

// With normalizer

342

getByText(container, 'submit', {

343

normalizer: str => str.toLowerCase()

344

});

345

```

346

347

## Core Types

348

349

Common type definitions used throughout the library:

350

351

```typescript

352

// Query function types

353

type BoundFunction<T> = T extends (

354

container: HTMLElement,

355

...args: infer P

356

) => infer R

357

? (...args: P) => R

358

: never;

359

360

interface Queries {

361

[T: string]: Query;

362

}

363

364

type Query = (

365

container: HTMLElement,

366

...args: any[]

367

) => Error | HTMLElement | HTMLElement[] | Promise<HTMLElement[]> | Promise<HTMLElement> | null;

368

369

// Wait options for async utilities

370

interface waitForOptions {

371

container?: HTMLElement; // Element to observe (default: document)

372

timeout?: number; // Max wait in ms (default: 1000)

373

interval?: number; // Polling interval in ms (default: 50)

374

onTimeout?: (error: Error) => Error; // Custom timeout error

375

mutationObserverOptions?: MutationObserverInit;

376

}

377

378

// Query arguments

379

type QueryArgs = [string, QueryOptions?];

380

381

interface QueryOptions {

382

[key: string]: RegExp | boolean;

383

}

384

```

385

386