Простой компонент множественного выбора:

import React from 'react'

type Props = {
  onSelectedValuesChange: (value: string[]) => void
}

export default function MultiSelect({onSelectedValuesChange}: Props) {

  function onSelectOptions(event: React.ChangeEvent<HTMLSelectElement>) {
    const selectedOptions = event.target.selectedOptions;
    const selectedValues = Array.from(selectedOptions).map((it) => it.value);
    console.log("### selected values: ", selectedValues);
    onSelectedValuesChange(selectedValues);
  }


  return <select multiple data-testid="select-multiple"
                 onChange={onSelectOptions} style={{width: '100px'}}>
    <option data-testid="val1" value="1">1</option>
    <option data-testid="val2" value="2">2</option>
    <option data-testid="val3" value="3">3</option>
  </select>
};

Когда пользователь выбирает какие-либо параметры, он отправляет выбранные значения в функцию обратного вызова onSelectedValuesChange.

Я хочу протестировать его и использовать @testing-library/user-event для имитации вариантов выбора пользователем.

const mockOnChange = jest.fn()
const {getByTestId} = render(<MultiSelect onSelectedValuesChange={mockOnChange}/>)

userEvent.selectOptions(getByTestId("select-multiple"), ["1", "3"]);

// (1) here are correct
expect((getByTestId("val1") as HTMLOptionElement).selected).toBe(true);
expect((getByTestId("val2") as HTMLOptionElement).selected).toBe(false);
expect((getByTestId("val3") as HTMLOptionElement).selected).toBe(true);

// (2) but here is failed ???
expect(mockOnChange).toHaveBeenLastCalledWith(["1", "3"]);

Часть (1) в коде работает, как ожидалось, но часть (2) не работает. Обратный вызов mockOnChange получает только ["1"] в качестве передаваемых параметров.

Также могут быть полезны некоторые сообщения в консоли:

    expect(jest.fn()).toHaveBeenLastCalledWith(...expected)

    Expected: ["1", "3"]
    Received
           1: ["1"]
    ->     2
              Array [
                "1",
            -   "3",
              ],

    Number of calls: 2

      18 | 
      19 |     // but here is failed ???
    > 20 |     expect(mockOnChange).toHaveBeenLastCalledWith(["1", "3"]);
         |                          ^
      21 |   });
      22 | })
      23 | 

      at Object.it (src/MultiSelect.test.tsx:20:26)

  console.log src/MultiSelect.tsx:12
    ### selected values:  [ '1' ]

  console.log src/MultiSelect.tsx:12
    ### selected values:  [ '1' ]

Мы видим, что onSelectOptions был вызван 2 раза, но аргументы всегда равны ['1'].

Я что-нибудь неправильно использовал?

Вот небольшая, но полная демонстрация этой проблемы: https://github.com/freewind-demos/typescript-react-testing-library--user-event--multiple-select--demo

1
Freewind 20 Ноя 2019 в 10:21

1 ответ

Я исправил неудачные тесты, обновив Jest с помощью npm install jest@latest. Похоже, это просто ошибка старой версии JSDOM, а не user-event.

Запрос на вытягивание для демонстрации с исправлениями

0
Nick McCurdy 9 Июн 2020 в 03:25