【问题标题】:How to select an option from a select list with React Testing Library如何使用 React 测试库从选择列表中选择一个选项
【发布时间】:2023-03-12 00:38:01
【问题描述】:

我有一个正常的选择列表。当我选择一个选项时,我需要测试 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

标签: react-testing-library


【解决方案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,效果很好。
          猜你喜欢
          • 2018-09-26
          • 1970-01-01
          • 2020-03-21
          • 2021-03-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多