如何使用 React 测试库测试 select 选项逻辑

How to test select option logic with React Testing Library

我想测试 Select 组件的选择逻辑。 https://codesandbox.io/s/eager-violet-kkw0x?file=/src/App.js

我找到这个片段来测试模拟。

test("simulates selection", () => {
  const { getByTestId, getAllByTestId } = render(<Select />);

  fireEvent.change(getAllByTestId("select"), { target: { value: 2 } });
  let options = getAllByTestId("select-option");
  expect(options[0].selected).toBeFalsy();
  expect(options[1].selected).toBeTruthy();
  expect(options[2].selected).toBeFalsy();
});

但是,它失败了 TypeError: Cannot read property 'map' of undefined。这是怎么回事?谢谢。

简短回答:您需要确保在您的值未定义时进行条件检查以跳过。您可以在 values.map(...

之前坚持 values &&

其次,我真的看不出仅仅为了索引而使用二维数组的价值。您可以将水果列表存储在数组中,并使用简单的映射进行迭代,将 value 作为 valuekey 传递。如果你想要花哨的键,你甚至可以分配由 .map()'s index 生成的数字增量以及值,这是花哨的版本:

        {values && values.map((index, value) => (
            <option key={`${index}-${value}`} value={value} data-testid="select">
                {value}
            </option>
        ))}

上面会生成一个键,如 fruit-1、anotherfruit-2 等,但是您可以只使用水果名称,无论您做什么,请确保您不要只使用索引号不是一个好习惯。这就是当你有一个简单数组时的全部,正如我所说,你不需要二维数组。

展望未来,您的测试中存在很多问题,代码中也存在一些问题,因此除非重新构想整个代码并进行测试,否则它将无法正常工作,但是我会尽力尝试解释其中的一些问题问题并指出正确的方向:

问题的第一行是:
fireEvent.change(getAllByTestId("select"), { target: { value: 2 } });

你要select一个元素,也就是<select />所以你要用getByTestId而不是getAllByTestId,你也把id弄错了,是 select-option.

正确的格式如下:

fireEvent.change(getByTestId("select-option"), { target: { value: 2 } });

快速说明一下,虽然上面的方法有效,但还有其他更好的方法,我建议查看 user-event 库而不是 fireEvent,但最重要的是,使用getByRole 而不是 getByTestIdread why

下一个问题是您没有将 props 传递给 select 组件,因此渲染时没有 <option> 元素。你不能用像 TypeScript 这样的东西来犯这个错误,因为它会警告你,但是 JavaScript 不会,所以..需要传入道具:

 const props = {
        callback: jest.fn(),
        values: [
            "grapefruit", "coconut", "lime", "mango"
        ],
        selected: 'lime'
    }

    const { getByTestId, getAllByTestId } = render(<Select {...props} />);

下一步,在收集选项时,您又用错了 ID(我想您混淆了两者),我也建议使用 queryAll 而不是 getAll,这是因为 queryAll 会 return 一个空数组,而 getAll 会抛出错误。

const options = queryAllByTestId("select");

最后你的断言也全错了。你的选项 不会有 一个 selected 属性然后你可以布尔值评估。您的选项有两个属性 data-testidvalue.

我试图给你最好的答案来理解发生了什么,但就代码而言,如果不重新考虑整个应用程序和测试就不可能修复它,就像我上面提到的,所以这是我的建议:

在组件中:

  • 改为二维数组,以值作为索引

  • 你没有对 selected 值做任何事情,只是控制台注销,如果你将它传递回你的父组件,将它保存到父状态并做任何你想做的事想要它,可能会在某处显示 - 这实际上对测试很重要。

  • selected prop 有一个字符串,它可能需要具有您传回的值并将其保存到父级中的状态。

测试中:

React 测试库很棒,因为您的测试类似于用户使用应用程序的方式,因此您应该断言 selected 组件是否出现在您想要的位置,而不是尝试检查属性,那会按以下方式工作:

  • 确保您呈现的组件将同时具有 select 组件和将 selected 值呈现为文本的组件。

  • 确保将所有道具传递给使用 rtl

    渲染的组件
  • 模拟动作(推荐user-event库,但fireEvent也可以)

  • 使用getByText查看页面上是否呈现并存在该值。那将是这样的:expect(getByText('fruitName')).toBeInTheDocument();

  • 最后,我建议查看 select 或优先级(尽可能使用 getByRole)以及 getByqueryBy 之间的区别.