or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-testing.mdconfiguration.mdhooks.mdindex.mdinteractions.mdmatchers.mdqueries.mdrendering.md

matchers.mddocs/

0

# Jest Matchers

1

2

Extended Jest matchers specifically designed for React Native component testing and assertions. These matchers integrate with Jest's expect API to provide intuitive and readable assertions for React Native elements.

3

4

## Capabilities

5

6

### Visibility and Presence Matchers

7

8

Matchers for testing element visibility and presence in the component tree.

9

10

```typescript { .api }

11

/**

12

* Assert element is currently on the screen (in the rendered tree)

13

*/

14

expect(element).toBeOnTheScreen(): void;

15

expect(element).not.toBeOnTheScreen(): void;

16

17

/**

18

* Assert element is visible to users (considering accessibility and style)

19

*/

20

expect(element).toBeVisible(): void;

21

expect(element).not.toBeVisible(): void;

22

23

/**

24

* Assert element is empty (has no children)

25

*/

26

expect(element).toBeEmptyElement(): void;

27

expect(element).not.toBeEmptyElement(): void;

28

```

29

30

**Usage Examples:**

31

32

```typescript

33

import { render, screen } from "@testing-library/react-native";

34

35

test("visibility matchers", () => {

36

render(

37

<View>

38

<Text testID="visible-text">Visible text</Text>

39

<View testID="empty-container" />

40

<Text

41

testID="hidden-text"

42

style={{ opacity: 0 }}

43

>

44

Hidden text

45

</Text>

46

<View testID="accessibility-hidden" accessibilityElementsHidden>

47

<Text>Hidden from accessibility</Text>

48

</View>

49

</View>

50

);

51

52

const visibleText = screen.getByTestId("visible-text");

53

const emptyContainer = screen.getByTestId("empty-container");

54

const hiddenText = screen.getByTestId("hidden-text");

55

const a11yHidden = screen.getByTestId("accessibility-hidden");

56

57

// Element presence

58

expect(visibleText).toBeOnTheScreen();

59

expect(hiddenText).toBeOnTheScreen(); // Still in tree, just not visible

60

61

// Element visibility

62

expect(visibleText).toBeVisible();

63

expect(hiddenText).not.toBeVisible(); // Has opacity: 0

64

expect(a11yHidden).not.toBeVisible(); // Hidden from accessibility

65

66

// Empty elements

67

expect(emptyContainer).toBeEmptyElement();

68

expect(visibleText).not.toBeEmptyElement(); // Has text content

69

});

70

71

test("conditional rendering", () => {

72

const ConditionalComponent = ({ show }) => (

73

<View>

74

{show && <Text testID="conditional">Conditional text</Text>}

75

</View>

76

);

77

78

const { rerender } = render(<ConditionalComponent show={false} />);

79

80

// Element not present when show=false

81

expect(screen.queryByTestId("conditional")).not.toBeOnTheScreen();

82

83

rerender(<ConditionalComponent show={true} />);

84

85

// Element present when show=true

86

expect(screen.getByTestId("conditional")).toBeOnTheScreen();

87

expect(screen.getByTestId("conditional")).toBeVisible();

88

});

89

```

90

91

### State and Interaction Matchers

92

93

Matchers for testing interactive element states and accessibility properties.

94

95

```typescript { .api }

96

/**

97

* Assert element is disabled/enabled

98

*/

99

expect(element).toBeDisabled(): void;

100

expect(element).not.toBeDisabled(): void;

101

expect(element).toBeEnabled(): void;

102

expect(element).not.toBeEnabled(): void;

103

104

/**

105

* Assert element is busy (has accessibilityState.busy = true)

106

*/

107

expect(element).toBeBusy(): void;

108

expect(element).not.toBeBusy(): void;

109

110

/**

111

* Assert element is selected

112

*/

113

expect(element).toBeSelected(): void;

114

expect(element).not.toBeSelected(): void;

115

116

/**

117

* Assert element is expanded/collapsed

118

*/

119

expect(element).toBeExpanded(): void;

120

expect(element).not.toBeExpanded(): void;

121

expect(element).toBeCollapsed(): void;

122

expect(element).not.toBeCollapsed(): void;

123

```

124

125

**Usage Examples:**

126

127

```typescript

128

test("interactive state matchers", () => {

129

render(

130

<View>

131

<Pressable

132

testID="disabled-button"

133

disabled={true}

134

accessibilityState={{ disabled: true }}

135

>

136

<Text>Disabled Button</Text>

137

</Pressable>

138

139

<Pressable

140

testID="enabled-button"

141

disabled={false}

142

>

143

<Text>Enabled Button</Text>

144

</Pressable>

145

146

<View

147

testID="busy-indicator"

148

accessibilityState={{ busy: true }}

149

>

150

<Text>Loading...</Text>

151

</View>

152

153

<View

154

testID="selected-item"

155

accessibilityState={{ selected: true }}

156

>

157

<Text>Selected Item</Text>

158

</View>

159

160

<View

161

testID="expanded-section"

162

accessibilityState={{ expanded: true }}

163

>

164

<Text>Expanded Section</Text>

165

</View>

166

</View>

167

);

168

169

const disabledButton = screen.getByTestId("disabled-button");

170

const enabledButton = screen.getByTestId("enabled-button");

171

const busyIndicator = screen.getByTestId("busy-indicator");

172

const selectedItem = screen.getByTestId("selected-item");

173

const expandedSection = screen.getByTestId("expanded-section");

174

175

// Disabled/enabled state

176

expect(disabledButton).toBeDisabled();

177

expect(enabledButton).toBeEnabled();

178

expect(enabledButton).not.toBeDisabled();

179

180

// Busy state

181

expect(busyIndicator).toBeBusy();

182

expect(enabledButton).not.toBeBusy();

183

184

// Selected state

185

expect(selectedItem).toBeSelected();

186

expect(disabledButton).not.toBeSelected();

187

188

// Expanded/collapsed state

189

expect(expandedSection).toBeExpanded();

190

expect(expandedSection).not.toBeCollapsed();

191

});

192

193

test("form element states", () => {

194

render(

195

<View>

196

<TextInput

197

testID="disabled-input"

198

editable={false}

199

accessibilityState={{ disabled: true }}

200

/>

201

202

<Switch

203

testID="toggle-switch"

204

value={true}

205

accessibilityState={{ checked: true }}

206

/>

207

</View>

208

);

209

210

const disabledInput = screen.getByTestId("disabled-input");

211

const toggleSwitch = screen.getByTestId("toggle-switch");

212

213

expect(disabledInput).toBeDisabled();

214

expect(toggleSwitch).toBeChecked();

215

});

216

```

217

218

### Checkbox and Selection Matchers

219

220

Specialized matchers for checkbox-like components and selection states.

221

222

```typescript { .api }

223

/**

224

* Assert element is checked (for checkboxes, switches, radio buttons)

225

*/

226

expect(element).toBeChecked(): void;

227

expect(element).not.toBeChecked(): void;

228

229

/**

230

* Assert element is partially checked (for indeterminate checkboxes)

231

*/

232

expect(element).toBePartiallyChecked(): void;

233

expect(element).not.toBePartiallyChecked(): void;

234

```

235

236

**Usage Examples:**

237

238

```typescript

239

test("checkbox matchers", () => {

240

const CheckboxComponent = ({ checked, indeterminate }) => (

241

<Pressable

242

testID="checkbox"

243

accessibilityRole="checkbox"

244

accessibilityState={{

245

checked: indeterminate ? "mixed" : checked

246

}}

247

>

248

<Text>{indeterminate ? "[-]" : checked ? "[×]" : "[ ]"}</Text>

249

</Pressable>

250

);

251

252

// Unchecked checkbox

253

const { rerender } = render(

254

<CheckboxComponent checked={false} indeterminate={false} />

255

);

256

257

const checkbox = screen.getByTestId("checkbox");

258

expect(checkbox).not.toBeChecked();

259

expect(checkbox).not.toBePartiallyChecked();

260

261

// Checked checkbox

262

rerender(<CheckboxComponent checked={true} indeterminate={false} />);

263

expect(checkbox).toBeChecked();

264

expect(checkbox).not.toBePartiallyChecked();

265

266

// Indeterminate checkbox

267

rerender(<CheckboxComponent checked={false} indeterminate={true} />);

268

expect(checkbox).toBePartiallyChecked();

269

expect(checkbox).not.toBeChecked();

270

});

271

272

test("switch component", () => {

273

render(

274

<Switch

275

testID="notification-switch"

276

value={true}

277

accessibilityLabel="Enable notifications"

278

accessibilityState={{ checked: true }}

279

/>

280

);

281

282

const notificationSwitch = screen.getByTestId("notification-switch");

283

expect(notificationSwitch).toBeChecked();

284

});

285

```

286

287

### Content and Text Matchers

288

289

Matchers for testing text content and display values.

290

291

```typescript { .api }

292

/**

293

* Assert element has specific text content

294

* @param text - Expected text content (string or RegExp)

295

*/

296

expect(element).toHaveTextContent(text: string | RegExp): void;

297

expect(element).not.toHaveTextContent(text: string | RegExp): void;

298

299

/**

300

* Assert form element has specific display value

301

* @param value - Expected display value (string or RegExp)

302

*/

303

expect(element).toHaveDisplayValue(value: string | RegExp): void;

304

expect(element).not.toHaveDisplayValue(value: string | RegExp): void;

305

```

306

307

**Usage Examples:**

308

309

```typescript

310

test("text content matchers", () => {

311

render(

312

<View>

313

<Text testID="greeting">Hello, World!</Text>

314

<Text testID="user-name">John Doe</Text>

315

<Text testID="empty-text"></Text>

316

<View testID="container">

317

<Text>First line</Text>

318

<Text>Second line</Text>

319

</View>

320

</View>

321

);

322

323

const greeting = screen.getByTestId("greeting");

324

const userName = screen.getByTestId("user-name");

325

const emptyText = screen.getByTestId("empty-text");

326

const container = screen.getByTestId("container");

327

328

// Exact text content

329

expect(greeting).toHaveTextContent("Hello, World!");

330

expect(userName).toHaveTextContent("John Doe");

331

332

// RegExp matching

333

expect(greeting).toHaveTextContent(/hello.*world/i);

334

expect(userName).toHaveTextContent(/john/i);

335

336

// Empty content

337

expect(emptyText).toHaveTextContent("");

338

expect(emptyText).not.toHaveTextContent("anything");

339

340

// Container with multiple text elements

341

expect(container).toHaveTextContent("First line Second line");

342

expect(container).toHaveTextContent(/first.*second/i);

343

});

344

345

test("display value matchers", () => {

346

render(

347

<View>

348

<TextInput

349

testID="email-input"

350

value="user@example.com"

351

placeholder="Email"

352

/>

353

354

<TextInput

355

testID="empty-input"

356

value=""

357

placeholder="Empty input"

358

/>

359

360

<Text testID="display-text">Current value: 42</Text>

361

</View>

362

);

363

364

const emailInput = screen.getByTestId("email-input");

365

const emptyInput = screen.getByTestId("empty-input");

366

const displayText = screen.getByTestId("display-text");

367

368

// Input values

369

expect(emailInput).toHaveDisplayValue("user@example.com");

370

expect(emailInput).toHaveDisplayValue(/@example\.com$/);

371

expect(emptyInput).toHaveDisplayValue("");

372

373

// Text element values

374

expect(displayText).toHaveDisplayValue("Current value: 42");

375

expect(displayText).toHaveDisplayValue(/value: \d+/);

376

377

// Negative assertions

378

expect(emailInput).not.toHaveDisplayValue("wrong@email.com");

379

expect(emptyInput).not.toHaveDisplayValue("something");

380

});

381

```

382

383

### Accessibility Matchers

384

385

Matchers for testing accessibility properties and labels.

386

387

```typescript { .api }

388

/**

389

* Assert element has specific accessible name

390

* @param name - Expected accessible name (string or RegExp)

391

*/

392

expect(element).toHaveAccessibleName(name: string | RegExp): void;

393

expect(element).not.toHaveAccessibleName(name: string | RegExp): void;

394

395

/**

396

* Assert element has specific accessibility value

397

* @param value - Expected accessibility value object

398

*/

399

expect(element).toHaveAccessibilityValue(value: {

400

min?: number;

401

max?: number;

402

now?: number;

403

text?: string;

404

}): void;

405

expect(element).not.toHaveAccessibilityValue(value: object): void;

406

```

407

408

**Usage Examples:**

409

410

```typescript

411

test("accessibility matchers", () => {

412

render(

413

<View>

414

<Pressable

415

testID="submit-button"

416

accessibilityLabel="Submit form"

417

accessibilityHint="Tap to submit the form"

418

>

419

<Text>Submit</Text>

420

</Pressable>

421

422

<Slider

423

testID="volume-slider"

424

minimumValue={0}

425

maximumValue={100}

426

value={75}

427

accessibilityLabel="Volume control"

428

accessibilityValue={{

429

min: 0,

430

max: 100,

431

now: 75,

432

text: "75 percent"

433

}}

434

/>

435

436

<TextInput

437

testID="name-input"

438

accessibilityLabel="Full name"

439

placeholder="Enter your full name"

440

/>

441

</View>

442

);

443

444

const submitButton = screen.getByTestId("submit-button");

445

const volumeSlider = screen.getByTestId("volume-slider");

446

const nameInput = screen.getByTestId("name-input");

447

448

// Accessible names

449

expect(submitButton).toHaveAccessibleName("Submit form");

450

expect(submitButton).toHaveAccessibleName(/submit/i);

451

expect(volumeSlider).toHaveAccessibleName("Volume control");

452

expect(nameInput).toHaveAccessibleName("Full name");

453

454

// Accessibility values

455

expect(volumeSlider).toHaveAccessibilityValue({

456

min: 0,

457

max: 100,

458

now: 75,

459

text: "75 percent"

460

});

461

462

// Partial accessibility value matching

463

expect(volumeSlider).toHaveAccessibilityValue({ now: 75 });

464

expect(volumeSlider).toHaveAccessibilityValue({ text: "75 percent" });

465

466

// Negative assertions

467

expect(submitButton).not.toHaveAccessibleName("Cancel");

468

expect(volumeSlider).not.toHaveAccessibilityValue({ now: 50 });

469

});

470

471

test("accessibility value updates", () => {

472

const ProgressComponent = ({ progress }) => (

473

<View

474

testID="progress-bar"

475

accessibilityRole="progressbar"

476

accessibilityValue={{

477

min: 0,

478

max: 100,

479

now: progress,

480

text: `${progress}% complete`

481

}}

482

/>

483

);

484

485

const { rerender } = render(<ProgressComponent progress={25} />);

486

487

const progressBar = screen.getByTestId("progress-bar");

488

489

// Initial progress

490

expect(progressBar).toHaveAccessibilityValue({

491

now: 25,

492

text: "25% complete"

493

});

494

495

// Updated progress

496

rerender(<ProgressComponent progress={75} />);

497

expect(progressBar).toHaveAccessibilityValue({

498

now: 75,

499

text: "75% complete"

500

});

501

});

502

```

503

504

### Property and Style Matchers

505

506

Matchers for testing component props and styles.

507

508

```typescript { .api }

509

/**

510

* Assert element has specific prop with optional value

511

* @param prop - Prop name to check

512

* @param value - Optional expected prop value

513

*/

514

expect(element).toHaveProp(prop: string, value?: any): void;

515

expect(element).not.toHaveProp(prop: string, value?: any): void;

516

517

/**

518

* Assert element has specific styles

519

* @param styles - Expected style object

520

*/

521

expect(element).toHaveStyle(styles: object): void;

522

expect(element).not.toHaveStyle(styles: object): void;

523

```

524

525

**Usage Examples:**

526

527

```typescript

528

test("prop matchers", () => {

529

render(

530

<View>

531

<TextInput

532

testID="styled-input"

533

placeholder="Enter text"

534

multiline={true}

535

numberOfLines={4}

536

keyboardType="email-address"

537

autoCapitalize="none"

538

/>

539

540

<Pressable

541

testID="custom-button"

542

disabled={false}

543

onPress={() => {}}

544

customProp="custom-value"

545

>

546

<Text>Button</Text>

547

</Pressable>

548

</View>

549

);

550

551

const styledInput = screen.getByTestId("styled-input");

552

const customButton = screen.getByTestId("custom-button");

553

554

// Check prop existence

555

expect(styledInput).toHaveProp("placeholder");

556

expect(styledInput).toHaveProp("multiline");

557

expect(customButton).toHaveProp("onPress");

558

559

// Check prop values

560

expect(styledInput).toHaveProp("placeholder", "Enter text");

561

expect(styledInput).toHaveProp("multiline", true);

562

expect(styledInput).toHaveProp("numberOfLines", 4);

563

expect(styledInput).toHaveProp("keyboardType", "email-address");

564

expect(customButton).toHaveProp("disabled", false);

565

expect(customButton).toHaveProp("customProp", "custom-value");

566

567

// Negative assertions

568

expect(styledInput).not.toHaveProp("nonexistent");

569

expect(styledInput).not.toHaveProp("multiline", false);

570

expect(customButton).not.toHaveProp("disabled", true);

571

});

572

573

test("style matchers", () => {

574

render(

575

<View>

576

<View

577

testID="styled-view"

578

style={{

579

backgroundColor: "blue",

580

padding: 10,

581

margin: 5,

582

borderRadius: 8,

583

flexDirection: "row"

584

}}

585

/>

586

587

<Text

588

testID="styled-text"

589

style={[

590

{ fontSize: 16, color: "red" },

591

{ fontWeight: "bold" }

592

]}

593

>

594

Styled Text

595

</Text>

596

</View>

597

);

598

599

const styledView = screen.getByTestId("styled-view");

600

const styledText = screen.getByTestId("styled-text");

601

602

// Single style properties

603

expect(styledView).toHaveStyle({ backgroundColor: "blue" });

604

expect(styledView).toHaveStyle({ padding: 10 });

605

expect(styledText).toHaveStyle({ fontSize: 16 });

606

expect(styledText).toHaveStyle({ color: "red" });

607

608

// Multiple style properties

609

expect(styledView).toHaveStyle({

610

backgroundColor: "blue",

611

padding: 10,

612

margin: 5

613

});

614

615

expect(styledText).toHaveStyle({

616

fontSize: 16,

617

color: "red",

618

fontWeight: "bold"

619

});

620

621

// Negative assertions

622

expect(styledView).not.toHaveStyle({ backgroundColor: "red" });

623

expect(styledView).not.toHaveStyle({ padding: 20 });

624

expect(styledText).not.toHaveStyle({ fontSize: 20 });

625

});

626

```

627

628

### Element Relationship Matchers

629

630

Matchers for testing element containment and hierarchy.

631

632

```typescript { .api }

633

/**

634

* Assert element contains another element

635

* @param element - Element that should be contained

636

*/

637

expect(container).toContainElement(element: ReactTestInstance): void;

638

expect(container).not.toContainElement(element: ReactTestInstance): void;

639

```

640

641

**Usage Examples:**

642

643

```typescript

644

test("containment matchers", () => {

645

render(

646

<View testID="outer-container">

647

<View testID="inner-container">

648

<Text testID="nested-text">Nested content</Text>

649

<Pressable testID="nested-button">

650

<Text>Button</Text>

651

</Pressable>

652

</View>

653

<Text testID="sibling-text">Sibling content</Text>

654

</View>

655

);

656

657

const outerContainer = screen.getByTestId("outer-container");

658

const innerContainer = screen.getByTestId("inner-container");

659

const nestedText = screen.getByTestId("nested-text");

660

const nestedButton = screen.getByTestId("nested-button");

661

const siblingText = screen.getByTestId("sibling-text");

662

663

// Direct containment

664

expect(outerContainer).toContainElement(innerContainer);

665

expect(outerContainer).toContainElement(siblingText);

666

expect(innerContainer).toContainElement(nestedText);

667

expect(innerContainer).toContainElement(nestedButton);

668

669

// Nested containment (transitive)

670

expect(outerContainer).toContainElement(nestedText);

671

expect(outerContainer).toContainElement(nestedButton);

672

673

// Negative containment

674

expect(innerContainer).not.toContainElement(siblingText);

675

expect(nestedText).not.toContainElement(nestedButton);

676

expect(siblingText).not.toContainElement(nestedText);

677

});

678

679

test("dynamic containment", () => {

680

const DynamicContainer = ({ showNested }) => (

681

<View testID="dynamic-container">

682

<Text testID="always-present">Always here</Text>

683

{showNested && (

684

<View testID="conditional-nested">

685

<Text testID="nested-content">Conditional content</Text>

686

</View>

687

)}

688

</View>

689

);

690

691

const { rerender } = render(<DynamicContainer showNested={false} />);

692

693

const container = screen.getByTestId("dynamic-container");

694

const alwaysPresent = screen.getByTestId("always-present");

695

696

// Always present element

697

expect(container).toContainElement(alwaysPresent);

698

699

// Conditional element not present initially

700

expect(screen.queryByTestId("conditional-nested")).not.toBeOnTheScreen();

701

702

// Show nested content

703

rerender(<DynamicContainer showNested={true} />);

704

705

const conditionalNested = screen.getByTestId("conditional-nested");

706

const nestedContent = screen.getByTestId("nested-content");

707

708

// Conditional elements now present and contained

709

expect(container).toContainElement(conditionalNested);

710

expect(container).toContainElement(nestedContent);

711

expect(conditionalNested).toContainElement(nestedContent);

712

});

713

```

714

715

## Custom Matcher Configuration

716

717

While the library provides comprehensive built-in matchers, you can also extend functionality if needed.

718

719

```typescript { .api }

720

/**

721

* Jest matcher result type for custom matchers

722

*/

723

interface MatcherResult {

724

pass: boolean;

725

message: () => string;

726

}

727

728

/**

729

* Custom matcher function signature

730

*/

731

type CustomMatcher<T = ReactTestInstance> = (

732

received: T,

733

...args: any[]

734

) => MatcherResult;

735

```

736

737

**Usage Examples:**

738

739

```typescript

740

// Custom matcher example (typically in test setup file)

741

expect.extend({

742

toHaveCustomProperty(received, expectedValue) {

743

const pass = received.props.customProperty === expectedValue;

744

745

return {

746

pass,

747

message: () =>

748

pass

749

? `Expected element not to have customProperty: ${expectedValue}`

750

: `Expected element to have customProperty: ${expectedValue}, but got: ${received.props.customProperty}`

751

};

752

}

753

});

754

755

// Usage in tests

756

test("custom matcher", () => {

757

render(

758

<View testID="custom-element" customProperty="special-value">

759

<Text>Custom Element</Text>

760

</View>

761

);

762

763

const element = screen.getByTestId("custom-element");

764

expect(element).toHaveCustomProperty("special-value");

765

});

766

```