React Testing Library: Jak zasymulować wybór opcji z listy?

Opublikowano: 16.09.2023 - tagi: JavaScript React Testowanie Test Komponent Formularz Kontrolka Lista

Lista jednego wyboru

Do pracy z listami biblioteka user-event udostępnia dwie funkcje: selectOptions i deselectOptions.

W tym wpisie do testów posłużę się takim przykładem:

import {useState} from "react";

const mealMap = {
    1: "Kebab",
    2: "Salad",
    3: "Soup"
}
export function MyComponent({mealId}) {
    const [meal, setMeal] = useState(mealId);

    const onListChange = e => {
        setMeal(e.target.value);
    }

    return (
        <>
            { meal &&
                <div>
                    Here we go! Your meal: {mealMap[meal]}
                </div>
            }
            <div>
                <label htmlFor="meal">Choose your meal:</label>
                <select id="meal" onChange={onListChange}>
                    <option value=""></option>
                    <option value="1">A</option>
                    <option value="2">B</option>
                    <option value="3">C</option>
                </select>
            </div>
        </>
    )
}

Wybieranie opcji — selectOptions

Test:

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

const { getByText, getByLabelText } = screen;

test('should display meal chosen by user', async () => {
    // given
    render(<MyComponent />);
    const select = getByLabelText('Choose your meal:');

    // when
    await userEvent.selectOptions(select, ['1'])

    // then
    expect(getByText('Here we go! Your meal: Kebab')).toBeInTheDocument();
});

Odznaczanie opcji

Jeśli masz listę jednego wyboru, to jak można przetestować odznaczanie opcji? Musisz zrobić dwie rzeczy.

Do swojej listy dodaj pustą opcję:

<option value=""></option>

Następnie za pomocą metody selectOptions przekaż pusty string.

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

const { queryByText, getByLabelText } = screen;

test('should deselect meal', async () => {
    // given
    render(<MyComponent mealId='3' />);
    const select = getByLabelText('Choose your meal:');

    // when
    await userEvent.selectOptions(select, [''])

    // then
    expect(queryByText('Here we go! Your meal: Soup')).not.toBeInTheDocument();
});

Lista wielokrotnego wyboru

Za pomocą atrybutu multiple sprawisz, że użytkownik będzie mógł wybrać więcej niż jedną opcję.

Komponent:

export function MyComponent() {
   return (
        <>
            <label htmlFor="meal">Choose your meal:</label>
            <select id="meal" multiple>
                <option value="1">Kebab</option>
                <option value="2">Salad</option>
                <option value="3">Soup</option>
            </select>
        </>
    )
}

Zaznaczanie wielu opcji — selectOptions

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

const { getByText, getByLabelText } = screen;

test('should choose many meals', async () => {
    // given
    render(<MyComponent />)
    const select = getByLabelText('Choose your meal:');

    // when
    await userEvent.selectOptions(select, ['2', '3'])

    // then
    expect(getByText('Salad').selected).toBeTruthy();
    expect(getByText('Soup').selected).toBeTruthy();
    expect(getByText('Kebab').selected).toBeFalsy();
});

Odznaczanie wielu opcji — deselectOptions

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

const { getByText, getByLabelText } = screen;

test('should deselect many meals', async () => {
    // given
    render(<MyComponent />)
    const select = getByLabelText('Choose your meal:');
    await userEvent.selectOptions(select, ['1', '2', '3']);

    // when
    await userEvent.deselectOptions(select, ['1', '3'])

    // then
    expect(getByText('Salad').selected).toBeTruthy();
    expect(getByText('Soup').selected).toBeFalsy();
    expect(getByText('Kebab').selected).toBeFalsy();
});