Testing Library React is a library that allows us to test React components in a more user-friendly way, simulating the behavior of a user interacting with the component.
- Here we have all the objects of the @testing-library/react package
| Object | Description | Example |
|---|---|---|
| render | is used to render the component in a virtual DOM, so we can test it without having to render it in the real DOM. | const {container} = render(<CounterApp value={initialValue} />); expect(container).toMatchSnapshot(); |
| screen | is a global object that contains all the queries that we can use to get the elements of the component rendered previously with render. | render(<CounterApp value={initialValue} />); expect(screen.getByText(initialValue)).toBeTruthy(); |
| fireEvent | is a function that simulate the events of the DOM, in this case we simulate the click event | fireEvent.click(screen.getByText("+1")); expect(screen.getByText(initialValue + 1)).toBeTruthy(); |
| waitFor | is used to wait for an asynchronous operation to complete, for example when fetching data | await waitFor(() => { expect(screen.getAllByRole("generic", {name: "card-grid"}).length).toBe(2); }); |
| renderHook | is used to test custom React hooks in isolation. We have to put result.current in every asyncronous process where we want to get the current values, but it's not neccesary if you don't any any asyncronous process in your hook | const { result } = renderHook(() => useFetchGifs(category)); await waitFor(() => { const { isLoading } = result.current; expect(isLoading).toBeFalsy(); }) const { gifs } = result.current; expect(gifs.length).toBeGreaterThan(0); |
| within | within allows to search within a specific element | const brand = within(header).getByText(/proshop/i); expect(brand).toBeInTheDocument(); |
- Here we have all the objects of the react-dom/test-utils package
| Object | Description | Example |
|---|---|---|
| act | act function ensure that all updates to the component or hook state are processed and applied before making assertions in your tests. It is used to wrap code that triggers state updates, such as calling state-updating functions or dispatching actions | const { result } = renderHook(() => useCounter(initialValue)); act(() => { result.current.handleAddCounter(); }); expect(result.current.counter).toBe(initialValue + 1); |
- Here we have all the methods of the object screen
| Method | Description | Example |
|---|---|---|
| screen.getByText() | is used to find an element with the specified text content | expect(screen.getByText(/your cart is empty/i)).toBeInTheDocument(); |
| screen.debug() | is a function that show the component rendered in the console until now, it is useful to see the component rendered and check if the values are correct | render(<CounterApp value={initialValue} />); fireEvent.click(screen.getByText("-1")); screen.debug(); |
| screen.getByText() | is a function that get the element by the text that we pass as parameter | expect(screen.getByText(initialValue - 1)).toBeTruthy(); |
| screen.getByRole() | is a function that get the element by the role that we pass as parameter. The accessible name is determined by: * The text content of the element (for headings, buttons, etc.) * The associated <label> (for inputs) * The aria-label or aria-labelledby attribute * The alt attribute (for images) |
expect(screen.getByRole("heading", {level: 2}).innerHTML).toContain(String(initialValue - 1)); |
| screen.getAllByText() | is a function that returns an array of elements that match the text content. | render(<FirstApp title={title} subTitle={subTitle} />); expect(screen.getAllByText(subTitle)).toBeTruthy(); expect(screen.getAllByText(subTitle).length).toBe(2); |
| screen.getByLabelText() | is a function that find form elements (like , <textarea>, etc.) by their accessible name, which is typically derived from: - A <label> element: The text content of a <label> associated with the form element (via for attribute or nesting). - The aria-label attribute: If the form element has an aria-label, it will use that as the accessible name. - The aria-labelledby attribute: If the form element references another element's ID via aria-labelledby, it will use the text content of that referenced element. |
<TextField ...attributes inputProps={{'aria-label': "password"}} const passwordInput = screen.getByLabelText(/password/i); |
| screen.queryByLabelText() | Unlike getByLabelText, which throws an error if the element is not found, queryByLabelText is safer to use when you expect that the element might not exist. It's usually used with .not.toBeInTheDocument() | expect(screen.queryByLabelText("alert-search")).not.toBeInTheDocument(); |
| screen.findByText() | Unlike getByText, which returns immediately and throws an error if the element is not found, findByText will wait for the element to appear in the DOM before throwing an error. For example, after a useEffect. All The sentences that is beginning with the word "find" are asyncronous | const hamburguer = await screen.findByText(/hamburger/i); expect(hamburguer).toBeInTheDocument(); |
- Here we have all the roles of the getByRole method
Accesible Names: More Info
| Roles | Description | Example |
|---|---|---|
| listitem | identifies an element as an item within a list. li elements automatically have the listitem role by default. | expect(within(getSection()).getAllByRole("listitem")).toHaveLength(1); |
| list | is used to get the ul, ol or menu tags or any element with the role list | expect(screen.getByRole("listbox")).toBeInTheDocument(); |
| listbox | No native HTML element has the listbox role by default. | const getListOptions = () => screen.getByRole("listbox", {name: /rows per page/i}); |
| table | is used to get the table element or any element with the role table | const getTable = () => screen.getByRole("table"); |
| columnheader | is assigned to the th tag when it is used inside a thead or tr in an HTML table. | const getTableHeaders = () => within(getTable()).getAllByRole("columnheader"); |
| cell | is used to get the td element or any element with the role cell | const getTableCells = () => within(getTable()).getAllByRole("cell"); |
| row | is used to get the tr element or any element with the role row | const getRowsTable = () => within(getTable()).getAllByRole("row"); |
| combobox | is used to get select elements or any element with the role "combobox" | <Select inputProps={{"aria-label": "cart-item-quantity-select"}}> const select = within(firstProduct).getByRole("combobox", { name: "cart-item-quantity-select"}); |
| presentation | is used to get the options wrapper of the select element such as the div that contains the options | <Select MenuProps={{"aria-label": "cart-item-quantity-options"}}> const optionsWrapper = screen.getByRole("presentation", {name: "cart-item-quantity-options"}); |
| option | is used to get all the options tags inside the select element or any element with the role "option" | const options = within(optionsWrapper).getAllByRole("option"); expect(options.length).toBeGreaterThan(0); |
| banner | is used for header elements | const header = screen.getByRole("banner"); |
| textbox | is any input with type text | screen.getByRole('textbox'); |
| form | is the form tag | screen.getByRole('form'); |
| heading | is any h1, h2, h3, h4, h5 or h6 tag | expect(screen.getByRole("heading", {level: 2}).innerHTML).toContain(String(initialValue - 1)); |
| generic | is used to select elements wich doesn't have a specific semantic role as div, span, etc | expect(screen.getAllByRole("generic", {name: "card-grid"}).length).toBe(2); |
| img | is the default role of the img tag | expect(screen.getAllByRole('img').length).toBe(gifs.length); |
| button | is commonly associated with elements or elements with role="button" | screen.getByRole("button", {name: "Next quote"}); |
| contentinfo | is most commonly applied to <footer> elements, because this element is explicitly given the contentinfo role. |
expect(screen.getAllByRole("contentinfo", {name: "quote"}).length).toBe(1); |
| link | it searches for elements with the role of "link", which corresponds to (anchor) elements or elements with role="link". | const linkTag = screen.getByRole("link", {name: /home/i}); |
| heading | The heading role specifically targets elements that are considered headings, such as h1, h2, etc. | expect(screen.getByRole("heading", {level: 1})).toBeTruthy(); |
| progressbar | The progressbar role refers to a tag html <progress> or a component that has the role progressbar as role="progressbar" |
expect(screen.queryByRole("progressbar", {name: "/loading/i"})).not.toBeInTheDocument(); |
| alert | is used to get the element with the role "alert", which is used to display messages. | expect(screen.getByRole("alert", {name: "message-general"})).toBeInTheDocument(); |
- Here we have all the methods of fireEvent object
| Method | Description | Example |
|---|---|---|
| fireEvent.click() | the method click is used to simulate a click event on an element | fireEvent.click(screen.getByText("+1")); |
| fireEvent.change() | the method change is used to change the value of the input | fireEvent.change(inputToChangeValue, {target: {value: valueToChange}}) expect(inputToChangeValue.value).toBe(valueToChange); |
| fireEvent.submit() | the method submit is used to trigger the submit event of the form | fireEvent.submit(formToTriggerSubmit, {preventDefault(){}}); |
- Here we have all the events of the @testing-library/user-event package
userEvent: it simulates real user interactions more accurately. It triggers all the events that would occur during a real user action (e.g., mousedown, mouseup, click, focus), making your tests more realistic and reliable.
| Event | Description | Example |
|---|---|---|
| click | simulates a user clicking on an element in a way that closely mimics real user behavior in the browser. | const button = screen.getByRole("button", {name: /login/i}); await userEvent.click(button); |
| type | is primarily the input event, it simulates typing one character at a time | await userEvent.type(screen.getByRole("textbox", {name: /searchText/i}), "batman"); |
| clear | Selects the text inside an or <textarea> and deletes it. | userEvent.clear(screen.getByRole('textbox')) expect(screen.getByRole('textbox')).toHaveValue('') |
| submit | submit does not exist in the @testing-library/user-event library. If you want to simulate a form submission, you can use the fireEvent.submit method or trigger the submit button into a form | await userEvent.click(screen.getByRole("button", {name: /search/i})); |
| upload | Uploads file to an "". For uploading multiple files use "" with the multiple attribute and the second upload argument as an array. | const file = new File(['hello'], 'hello.png', {type: 'image/png'}) const input = screen.getByLabelText(/upload file/i) userEvent.upload(input, file) expect(input.files[0]).toStrictEqual(file) |
| tab | Simulates a user pressing the tab key to move focus to the next element. This is useful to test the validation of the fields when the user leaves the field | await userEvent.tab(); |
| selectOptions | Simulates a user selecting an option in a select element (combobox) | await userEvent.selectOptions(screen.getByRole("combobox", {name: /type/i}), "clothing"); |
- Here we have all the object to test routes in the react-router-dom package
import {MemoryRouter} from "react-router-dom";| Objects | Description | Example |
|---|---|---|
| MemoryRouter | is specifically designed for testing and provides more control over the routing behavior. If you don't provide any value for the initialEntries prop in MemoryRouter, it will default to the root route ('/'). This means that the initial route for your test will be the root route. | <MemoryRouter initialEntries={["/login"]}> <MainApp /> </MemoryRouter> |