React Testing Librbary & Jest part 3 Findling Element with query functions === ![](https://i.imgur.com/GYOSSUa.png) --- ###### 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. ![](https://i.imgur.com/pBulALc.png) ### 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. ![](https://i.imgur.com/n8WCbHZ.png) 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)