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

Posted

技术标签:

【中文标题】如何使用 React 测试库从选择列表中选择一个选项【英文标题】:How to select an option from a select list with React Testing Library 【发布时间】:2020-01-16 16:50:45 【问题描述】:

我有一个正常的选择列表。当我选择一个选项时,我需要测试 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 不返回任何内容,可能是因为它在页面上不可见?

【问题讨论】:

你试过fireEvent.change(getByTestId("select"), target: value: '&lt;item label&gt;' ); 好像不像getByTestId("select"),报错:TypeError: container.querySelectorAll is not a function 【参考方案1】:

在 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 测试库测试选择元素的更多信息。

【讨论】:

【参考方案2】:

这对我来说似乎更简单:

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

【讨论】:

【参考方案3】:

你也可以使用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();

【讨论】:

【参考方案4】:

这个解决方案对我不起作用,起作用的是 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();
      //...
    )

如果您有标签(您应该这样做!),您也可以放弃在选择元素中添加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();
      //...
    )

这似乎是进行此类测试的最佳方式。

【讨论】:

【参考方案5】:

在选项中添加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 仅适用于显示的值

【讨论】:

fireEvent.change 对我不起作用;我用了fireEvent.click,效果很好。

以上是关于如何使用 React 测试库从选择列表中选择一个选项的主要内容,如果未能解决你的问题,请参考以下文章

使用 cypress 选择 react-select 下拉列表选项

如何使用 React 只选择一个单选按钮

如何只使用React选择一个单选按钮

如何在本机反应中显示从可搜索下拉列表中选择的项目?

如何使用response从下拉选择中获取值?

如何使用 Selenium-Python 从多选列表中选择多个选项?