我目前正在尝试模拟react-select组件,无论我做什么,从react-testing-library中的firevent.change似乎只会在firevent.change的第一个调用上触发。
我想知道为什么更改仅触发一次以及如何解决。
我开玩笑的模拟如下:
jest.mock("react-select", () => ({ options, value, onChange }) => {
function handleChange(event) {
console.log("called");
const option = options.find(option => {
return option.value == event.currentTarget.value;
});
onChange(option);
}
return (
<select
id="uc"
data-testid="select"
value={value}
onChange={event => handleChange(event)}
>
{options?.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))}
</select>
);
});
如您所见,它是一个相当简单的选择块,我认为我应该可以打电话。
fireEvent.change(selectOptions[0], { target: { value: "0" } });
但是如果我然后将它们链接在一起,如下例所示,这将起作用:
test("Should render add another button and function", () => {
const mockSetOpen = jest.fn();
const { queryAllByTestId, getByTestId, getByLabelText, debug } = renderWithRedux(
<TabByRestraints setOpen={mockSetOpen} hidden={false} />,
{
userCatagories: userCategoriesMock,
permissionGroups: permissionGroupsMock,
roles: rolesMock
}
);
// Check that the user catagories exist and user catagories values
const selectOptions = queryAllByTestId("select");
expect(selectOptions).toHaveLength(2);
expect(getByTestId("user-category-row")).toBeTruthy();
fireEvent.change(selectOptions[0], { target: { value: "0" } });
fireEvent.change(selectOptions[1], { target: { value: "132" } });
expect(getByLabelText("Add a new user category restraint")).toBeTruthy();
});
我可以看到console.log(“ Called”)仅被触发了一次。测试失败之前,永远不会选择页面上的第二个选择。
我希望两个变更都调度一个变更事件。
fireEvent.change(selectOptions[0], { target: { value: "0" } });
fireEvent.change(selectOptions[1], { target: { value: "132" } });
但是它只设置了第一个。
非常感谢任何帮助。
您应该对选择元素进行另一个查询。我会更进一步地命名它们,以使测试更易于阅读/调试。
// it's easier to have separate ids for each select, will be easier to read/maintain the test in the future
const firstSelect = queryByTestId("select1");
fireEvent.change(firstSelect, { target: { value: "0" } });
// a rerender might have happened so you need to query for the second select after the first event.
const secondSelect = queryByTestId("select2");
fireEvent.change(secondSelect, { target: { value: "132" } });
expect(getByLabelText("Add a new user category restraint")).toBeTruthy();
render
有效但renderWithRedux
不能说明问题在于Redux状态管理。
要考虑的一件事-设置状态将队列放入React中的重新渲染,而将动作分派给Redux则将Redux自己的更新队列中的更改放入队列。 React测试工具可能不知道该如何处理。
尽管它更接近代码,但您可能需要考虑模拟dispatch
并验证其是否已收到选择更改的预期结果。这样,您可以验证代码是否正常运行,而不必担心第三方代码在做什么。 (有点讽刺的是,当renderWithRedux是实际的第三方问题时,您试图避免使用react-select。:D)
[您可能还考虑直接调用onChange处理程序,将其从组件中的select中删除,而不是触发事件。这将是减少正在测试和模拟的第三方代码量的另一种方法。