React Testing Librbary & Jest part 3 Findling Element with query functions
===

---
###### tags: `React Testing Library`, `Jest`, `React`
## Query functions
1. Accessed through `screen` object.
3. Begin with `get`, `query`, `find`, i.e. `getBy`, `queryBy`, `findBy`
## Try to use these query functions
### Test case:
1. Find a list
2. Find three listitem
3. Find a textbox which is not exists
### Find a textbox which is not exists
```javascript!
// ColorList.js
const ColorList = () => {
return (
<ul>
<li>Black</li>
<li>Pink</li>
<li>Indigo</li>
</ul>
);
};
export default ColorList;
```
```javascript!
// ColorList.test.js
import { render, screen } from '@testing-library/react';
import ColorList from '../components/ColorList';
test('getBy, queryBy, findBy finding 0 elements', async () => {
render(<ColorList />);
// Using getBy, if not matched, it would throw an error
expect(() => screen.getByRole('textbox')).toThrow();
// Using queryBy, if no matched, it would be null
expect(screen.queryByRole('textbox')).toEqual(null);
// Using findBy, it's asynchronous, need to use async await
// This would fail the test
// Returns a promise that gets rejected
await screen.findByRole('textbox');
});
```
We can implement this workaround to pass the test.
```javascript!
import { render, screen } from '@testing-library/react';
import ColorList from '../components/ColorList';
test('getBy, queryBy, findBy finding 0 elements', async () => {
render(<ColorList />);
// expect(() => screen.getByRole('textbox')).toThrow();
// expect(screen.queryByRole('textbox')).toEqual(null);
let errorThrown = false;
try {
await screen.findByRole('textbox');
} catch (error) {
errorThrown = true;
}
expect(errorThrown).toEqual(true);
});
```
- Create a variable `errorThrown` and assign to `false`;
- try to await the promise to see if there's `textbox` in the component.
- Because there's no `textbox`, it will go to the catch block and we reassign erroThrown to be `true`.
- We expect `errorThrown` is equals to `true`.
### Find 1 element in component
```javascript!
test('Find 1 element in the component', async () => {
render(<ColorList />);
expect(screen.getByRole('list')).toBeInTheDocument();
expect(screen.queryByRole('list')).toBeInTheDocument();
expect(await screen.findByRole('list')).toBeInTheDocument();
});
```
Here we can see there's an red squiggly line, it's not an error, it's eslint `testing-library/prefer-presence-queries` suggests that using `getByRole` for checking element is present.

### Find > 1 elements
We can use `getBy` || `queryBy` || `findBy` to test, but since these three are meant to find 1 element, we
can expect there're error occurded.
```javascript!
test('find more then 1 elements', async () => {
render(<ColorList />);
expect(() => screen.getByRole('listitem')).toThrow();
expect(() => queryByRole('listitem')).toThrow();
let errorThrown = false;
try {
await screen.findByRole('listitem');
} catch (error) {
errorThrown = true;
}
expect(errorThrown).toEqual(true);
});
```
Another approach is to use `getAllBy`, `queryAllBy` and `findAlBy` to target multiple elements,
we can check if the length is correct.
```javascript!
test('find more then 1 elements', async () => {
render(<ColorList />);
expect(screen.getAllByRole('listitem')).toHaveLength(3);
expect(screen.queryAllByRole('listitem')).toHaveLength(3);
expect(await screen.findAllByRole('listitem')).toHaveLength(3);
});
```
## When to use them ? Do we need an assertion ?
In cases if we try to find element which is not exists, we usually use `getBy`, and then write an assertion in the end,
but using `getBy` will throw an error without having an assertion,so what's the point of having one?
### Compare these two tests:
```javascript!
// Using getByRole
test('getBy, queryBy, findBy finding 0 elements', async () => {
render(<ColorList />);
const textBoxEle = screen.getByRole('textbox');
});
```
```javascript!
// Using queryBRole
test('getBy, queryBy, findBy finding 0 elements', async () => {
render(<ColorList />);
const textBoxEle = screen.queryByRole('textbox');
});
```
Let's take a look at the cheatsheet to see the difference.

We can see that using `getBy` will throw an error if no match, but using `queryBy` will return `null`, this can cause unexpected test result, the one using `queryByRole` was passed, which was not what we want, therefore, having an assertion to make sure the result remains the same.
### To summarize:
| Goal of test | Use |
| -------------------------------------- | ------------------ |
| Prove an element exists | getBy, getAllBy |
|Prove an element does not exist | queryBy, queryAllBy|
|Make sure an element eventually exists | findBy, findAllBy |
## When to use Async queries (findBy, findAllBy)
If elements inside of the component needed to be fetched.
Here is the component we tried to fetch color list.
```javascript
// LoadColor.jsx
import { useState, useEffect } from 'react';
// Create a function to simulate fetch data
const fetchColorList = () => {
return Promise.resolve(['red', 'blue', 'green']);
};
const LoadColorList = () => {
const [colors, setColors] = useState([]);
useEffect(() => {
fetchColorList().then((color) => setColors(color));
}, []);
const renderColors = colors.map((color) => {
return <li>{color}</li>;
});
return <ul>{renderColors}</ul>;
};
export default LoadColorList;
```
Now let's try to use none async query function.
```javascript
import LoadColorList from '../components/LoadColorList';
test('find all listitem in the component', () => {
render(<LoadColorList />);
const listItems = screen.getAllByRole('listitem');
expect(listItems).toHaveLength(3);
});
```
This test is failed due to it checked component too early, let's change `getAllByRole` to async `findAllByRole`.
```javascript=
import { render, screen } from '@testing-library/react';
import LoadColorList from '../components/LoadColorList';
test('find all listitem in the component', async () => {
render(<LoadColorList />);
const listItems = await screen.findAllByRole('listitem');
expect(listItems).toHaveLength(3);
});
```
> [Jest-toThrow(error)](https://jestjs.io/docs/expect#tothrowerror)
> [Cheatsheet](https://testing-library.com/docs/dom-testing-library/cheatsheet/#queries)