如何使用 React 测试库从 select 列表中 select 一个选项

How to select an option from a select list with React Testing Library

我有一个正常的 select 列表。我需要测试 handleChoice 在我选择一个选项时被调用。我如何使用 React 测试库执行此操作?

  <select
    onChange={handleChoice}
    data-testid="select"
  >
    <option value="default">Make your choice</option>
    {attributes.map(item => {
      return (
        <option key={item.key} value={item.key}>
          {item.label}
        </option>
      );
    })}
  </select>

getByDisplayValue 的值为 item.label 并没有 return 任何东西,也许这是因为它在页面上不可见?

在选项中添加data-testid

  <option data-testid="select-option" key={item.key} value={item.key}>
      {item.label}
  </option>

然后,在测试调用fireEvent.change中,通过getAllByTestId获取所有选项,并检查选中的选项:

import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import App from './App';

test('Simulates selection', () => {
  const { getByTestId, getAllByTestId } = render(<App />);
  //The value should be the key of the option
  fireEvent.change(getByTestId('select'), { target: { value: 2 } })
  let options = getAllByTestId('select-option')
  expect(options[0].selected).toBeFalsy();
  expect(options[1].selected).toBeTruthy();
  expect(options[2].selected).toBeFalsy();
  //...
})

对于您的问题,getByDisplayValue 仅适用于显示值

这个解决方案对我不起作用,有用的是 userEvent。 https://testing-library.com/docs/ecosystem-user-event/

    import React from 'react';
    import { render } from '@testing-library/react';
    import userEvent from '@testing-library/user-event';
    import App from './App';
    
    test('Simulates selection', () => {
      const { getByTestId } = render(<App />);
      // where <value> is the option value without angle brackets!
      userEvent.selectOptions(getByTestId('select'), '<value>');
      expect((getByTestId('<value>') as HTMLOptionElement).selected).toBeTruthy();
      expect((getByTestId('<another value>') as HTMLOptionElement).selected).toBeFalsy();
      //...
    })

如果您有标签(您应该这样做!),您也可以放弃必须向 select 元素添加 data-testid,而只需使用 getByLabelText('Select')

此外,如果您使用 getByText.

,您可以去掉每个选项元素上的附加 data-testid
      <label for="selectId">
            Select
      </label>
      <select
        onChange={handleChoice}
        id="selectId"
      >
        <option value="default">Make your choice</option>
        {attributes.map(item => {
          return (
            <option key={item.key} value={item.key}>
              {item.label}
            </option>
          );
        })}
      </select>

然后:

    import React from 'react';
    import { render } from '@testing-library/react';
    import userEvent from '@testing-library/user-event';
    import App from './App';
    
    test('Simulates selection', () => {
      const { getByLabelText, getByText } = render(<App />);
      // where <value> is the option value without angle brackets!
      userEvent.selectOptions(getByLabelText('<your select label text>'), '<value>');
      expect((getByText('<your selected option text>') as HTMLOptionElement).selected).toBeTruthy();
      expect((getByText('<another option text>') as HTMLOptionElement).selected).toBeFalsy();
      //...
    })

这似乎是进行此类测试的更佳方法。

您也可以使用 getByText,这样您就无需添加 data-testid 属性

就我而言,我做到了

import { screen } from '@testing-library/react';

....
<select>
  <option value="foo">Foo</option>
  <option selected value="bar">Bar</option>
</select>

....

expect((screen.getByText('Foo') as HTMLOptionElement).selected).toBeFalsy();
expect((screen.getByText('Bar') as HTMLOptionElement).selected).toBeTruthy();

2021 年,您可以使用 userEvent,它是 React 测试库生态系统的一部分。它允许您编写更接近真实用户行为的测试。示例:

it('should correctly set default option', () => {
  render(<App />)
  expect(screen.getByRole('option', {name: 'Make a choice'}).selected).toBe(true)
})


it('should allow user to change country', () => {
  render(<App />)
  userEvent.selectOptions(
    // Find the select element
    screen.getByRole('combobox'),
    // Find and select the Ireland option
    screen.getByRole('option', {name: 'Ireland'}),
  )
  expect(screen.getByRole('option', {name: 'Ireland'}).selected).toBe(true)
})

查看 this article 了解有关如何使用 React 测试库测试 select 元素的更多信息。

这对我来说似乎更简单:

userEvent.selectOptions(screen.getByLabelText('County'), 'Aberdeenshire');