如何使用 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
作为 value
和 key
传递。如果你想要花哨的键,你甚至可以分配由 .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
而不是 getByTestId
、read 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-testid
和 value
.
我试图给你最好的答案来理解发生了什么,但就代码而言,如果不重新考虑整个应用程序和测试就不可能修复它,就像我上面提到的,所以这是我的建议:
在组件中:
改为二维数组,以值作为索引
你没有对 selected 值做任何事情,只是控制台注销,如果你将它传递回你的父组件,将它保存到父状态并做任何你想做的事想要它,可能会在某处显示 - 这实际上对测试很重要。
selected
prop 有一个字符串,它可能需要具有您传回的值并将其保存到父级中的状态。
测试中:
React 测试库很棒,因为您的测试类似于用户使用应用程序的方式,因此您应该断言 selected 组件是否出现在您想要的位置,而不是尝试检查属性,那会按以下方式工作:
确保您呈现的组件将同时具有 select 组件和将 selected 值呈现为文本的组件。
确保将所有道具传递给使用 rtl
渲染的组件
模拟动作(推荐user-event
库,但fireEvent
也可以)
使用getByText
查看页面上是否呈现并存在该值。那将是这样的:expect(getByText('fruitName')).toBeInTheDocument();
最后,我建议查看 select 或优先级(尽可能使用 getByRole
)以及 getBy
和 queryBy
之间的区别.
我想测试 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
作为 value
和 key
传递。如果你想要花哨的键,你甚至可以分配由 .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
而不是 getByTestId
、read 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-testid
和 value
.
我试图给你最好的答案来理解发生了什么,但就代码而言,如果不重新考虑整个应用程序和测试就不可能修复它,就像我上面提到的,所以这是我的建议:
在组件中:
改为二维数组,以值作为索引
你没有对 selected 值做任何事情,只是控制台注销,如果你将它传递回你的父组件,将它保存到父状态并做任何你想做的事想要它,可能会在某处显示 - 这实际上对测试很重要。
selected
prop 有一个字符串,它可能需要具有您传回的值并将其保存到父级中的状态。
测试中:
React 测试库很棒,因为您的测试类似于用户使用应用程序的方式,因此您应该断言 selected 组件是否出现在您想要的位置,而不是尝试检查属性,那会按以下方式工作:
确保您呈现的组件将同时具有 select 组件和将 selected 值呈现为文本的组件。
确保将所有道具传递给使用
渲染的组件rtl
模拟动作(推荐
user-event
库,但fireEvent
也可以)使用
getByText
查看页面上是否呈现并存在该值。那将是这样的:expect(getByText('fruitName')).toBeInTheDocument();
最后,我建议查看 select 或优先级(尽可能使用
getByRole
)以及getBy
和queryBy
之间的区别.