---
# System prepended metadata

title: React Testing Librbary & Jest part 5 Matchers in Jest
tags: [Jest, React Testing Library, React]

---

React Testing Librbary & Jest part 5 Matchers in Jest
===

![](https://i.imgur.com/GYOSSUa.png)


---

###### tags: `React Testing Library`, `Jest`, `React`

## Create custom matchers

Somtimes we might encounter cases like to check for example buttons in a form, but component changes all the time, therefore to have a flexible test can reduce time to replicate or rewrite the test.

Let's say we want to check if there're 2 buttons in form.

```javascript=
// FormData.jsx
const FormData = () => {
	return (
		<form aria-label="form">
			<button>Save</button>
			<button>Cancel</button>
		</form>
	);
};

export default FormData;
```

We can use `winthin` matcher in Jest to check buttons inside `form`.

```javascript=
// FromData.test.js
import { render, screen, within } from '@testing-library/react';
import FormData from '../components/FormData';

test('2 buttons in the form', () => {
	render(<FormData />);

	const form = screen.getByRole('form');
	const buttons = within(form).getAllByRole('button');

	expect(buttons).toHaveLength(2);
});
```

Test above is valid, but what if we need to add addtional html outside of `form` and add extra button.

```javascript
// FormData.jsx
const FormData = () => {
	return (
		<div>
			<button>Go Back</button>
			<form aria-label="form">
				<button>Save</button>
				<button>Cancel</button>
			</form>
		</div>
	);
};

export default FormData;
```

When we amend code like this, our test is still passed, but what if we have multiple code amendments and we need to write the exact same test code repeatly, how about we create a custom matcher to check whatever the elements or the number we need to check, we can leverage a custom matcher to check for us.

```javascript
// FormData.test.js

import { render, screen, within } from '@testing-library/react';
import FormData from '../components/FormData';


const toContainRole = (container, role, quantity = 1) => {
	const elements = within(container).queryAllByRole(role);
	if (elements.length === quantity) {
		return {
			pass: true,
		};
	}
	return {
		pass: false,
		message: `Expect to find ${quantity} ${role}, found ${elements.length} instead`,
	};
};

expect.extend({ toContainRole });

test('2 buttons in the form', () => {
	render(<FormData />);

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

	expect(form).toContainRole('button', 2);
});
```

Let's try if I want to check if there're 2 `li` inside a `ul`, we simply change `form` to `list` and `getByRole('list')`, this is to find `ul`, then pass `listitem` as role and quantity of 2.

```javascript=
// FormData.test.js

test('2 buttons in the form', () => {
	render(<FormData />);

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

	expect(list).toContainRole('listitem', 2);
});
```