React Testing Library: Jak pobrać referencję do elementu w komponencie?

Opublikowano: 05.08.2023 - tagi: JavaScript React Testy Komponent

Pobieranie referencji

Biblioteka React Testing Library daje programiście do ręki zestaw funkcji, które pozwalają na pobranie referencji do elementu w komponencie.

Te zapytania dzięlą się na trzy grupy:

  1. getBy - Zapytanie zwraca referencję do elementu. Dodatkowo zostanie zasygnalizowany błąd w dwóch przypadkach: jeśli referencja nie została znaleziona lub zostało znalezionych więcej niż jeden element.
  2. queryBy - Jeśli element nie został znaleziony zwróci null. To zapytanie jest przydatne kiedy potrzebujesz stestować przypadek, że dany element nie istnieje. Zasygnalizuje błąd jeśli zostało znalezionych więcej niż jeden element.
  3. findBy - Zwraca Promise, która zawiera referencję do danego elementu. Promise zostanie odrzucona jeśli element nie został odnaleziony lub jeśli znalezionych zostało więcej niż jeden element po upływie 1000 milisekund (1 sekunda). Przydaje się więc w operacjach asynchronicznych.

Jeśli potrzebujesz pobrać więcej niż jeden element po danych kryteriach możesz użyć też: getAllBy, queryAllBy, findAllBy.

Przykłady

getByRole

Służy do pobrania referencji do elementu bazując na roli, jaką pełni element w dokumencie, w rozumieniu szeroko pojętej dostępności (ang.: accessibility). Na przykład czy jest to: przycisk, nagłówek, lista itp.

Przykład:

Komponent:

export function MyComponent() {
    return (
        <>
            <div>
                <h1>My header</h1>
            </div>
        </>
    )
}

Test:

import {render, screen} from '@testing-library/react';
import {MyComponent} from "./MyComponent";

test('some test', () => {
    // given
    const { getByRole } = screen;
    render(<MyComponent />);
    const heading = getByRole('heading');

    // when - then
    expect(heading).toHaveTextContent('My header');
});

Można też pobrać element na podstawie jego nazwy:

Komponent:

import {useState} from "react";

export function MyComponent() {
    const [state, setState] = useState(0);

    return (
        <>
            <div>
                <h1>{state}</h1>
            </div>
            <div>
                <button onClick={() => setState((prevState: number) => prevState + 1)}>Increment</button>
                <button onClick={() => setState((prevState: number) => prevState - 1)}>Decrement</button>
            </div>
        </>
    )
}

Żeby zdobyć referencję dla przycisku o nazwie: Increment wystaczy napisać:

const btnIncrement = getByRole('button', { name: /Increment/i});

Zauważ, że użyte zostało tutaj wyrażenie regularne.

Można też po prostu napisać:

const btnIncrement = getByRole('button', { name: "Increment" });

getByLabelText

Dokumentacja zaleca używania tej funkcji, gdy potrzebujesz mieć dostęp do pola z formularza.

Zwykle każde pole ma własną etykietę (a przynajmniej powinno mieć). Więc naturalne jest, że będziemy szukać danego pola po jego etykiecie.

Przykład:

Komponent:

export function MyComponent() {
    return (
        <>
            <form>
                <label htmlFor="name">Name</label>
                <input id="name" value="Default name" />
            </form>
        </>
    )
}

Test:

import {render, screen} from '@testing-library/react';
import {MyComponent} from "./MyComponent";

test('should field has default value', () => {
    // given
    const { getByLabelText } = screen;
    render(<MyComponent />);
    const field = getByLabelText('Name');

    // when - then
    expect(field).toHaveValue('Default name');
});

getByDisplayValue

Jest podobne do getByLabelText różnica jest taka, że ta funkcja znajdzie Ci referencję, do elementu formularza na podstawie wartości, którą to pole zawiera.

Komponent:

export function MyComponent() {
    return (
        <>
            <form>
                <label htmlFor="name">Name</label>
                <input id="name" value="Default name" />
            </form>
        </>
    )
}

Test:

import {render, screen} from '@testing-library/react';
import {MyComponent} from "./MyComponent";

test('should field has default value', () => {
    // given
    const { getByDisplayValue } = screen;
    render(<MyComponent />);
    const field = getByDisplayValue('Default name');

    // when - then
    expect(field).toBeInTheDocument();
});

getByText

Tej funkcji należy używać, gdy chcemy pobrać referencję do elementów, które nie są interkatywne. Jak na przykład div'y, akapity itp.

Przykład:

Komponent:

import {useState} from "react";

export function MyComponent() {
    const [counter] = useState(10);

    return (
        <>
            <h1>Counter: {counter}</h1>
        </>
    )
}

Test:

import {render, screen} from '@testing-library/react';
import {MyComponent} from "./MyComponent";

test('should counter be 10 as default', () => {
    // given
    const { getByText } = screen;
    render(<MyComponent />);
    const counter = getByText('Counter: 10');

    // when - then
    expect(counter).toBeInTheDocument();
});