反应组件中的网络请求后 Jest 函数无法触发
Jest function fails to fire after network request in react component
完整回购
https://github.com/brianbancroft/sample-testing-msw-sb-jest-rtl
使用模拟服务工作者 (msw) 响应网络请求,我有一个 React 登录组件。提交时它会发送一个网络请求,成功后它应该触发一个“handleClose”函数,它是组件的一个道具。
async function handleSubmit(event) {
event.preventDefault();
setLoading(true);
const { username, password } = event.target.elements;
try {
const response = await fetch("/login", {
method: "POST",
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
},
redirect: "follow",
referrerPolicy: "no-referrer",
body: JSON.stringify({
username: username.value,
password: password.value,
}),
});
await response.json();
if (response.status === 200) {
props.handleClose();
} else {
setInvalidUsernamePassword(true);
setLoading(false);
}
} catch (error) {
alert("Error detected", error);
}
}
当我测试时,我验证函数 handleClose
被调用。
const setup = async () => {
const handleClose = jest.fn();
const utils = await render(<Primary handleClose={handleClose} />);
const usernameField = screen.getByLabelText(/Username/);
const passwordField = screen.getByLabelText(/Password/);
const submitButton = screen.getByRole("button", {
name: /Sign In/i,
});
return {
usernameField,
passwordField,
submitButton,
handleClose,
...utils,
};
};
test("The handleClose function prop is triggered", async () => {
const { usernameField, passwordField, submitButton, handleClose } =
await setup();
fireEvent.change(usernameField, { target: { value: faker.lorem.word() } });
fireEvent.change(passwordField, { target: { value: faker.lorem.word() } });
fireEvent.click(submitButton);
expect(handleClose).toHaveBeenCalled();
});
这失败了
Expected number of calls: >= 1
Received number of calls: 0
但是,当我在异步函数开始之前调用 prop 函数时,它通过了,这告诉我这不是我将 jest.fn() 传递到组件中的方式。
我调查了是否会抛出错误(它不会),而且我也知道 msw
正在按预期工作,并且网络请求以 200 响应,除非我发送密码值“badpassword”,用于在同一文件的另一个测试中模拟不正确的电子邮件或密码。
我还转换了函数以使用 promises。没有变化。
这就是 waitFor
实用方法在 React 测试库中的用途。
https://testing-library.com/docs/dom-testing-library/api-async/
test("The handleClose function prop is triggered", async () => {
const { usernameField, passwordField, submitButton, handleClose } =
await setup();
fireEvent.change(usernameField, { target: { value: faker.lorem.word() } });
fireEvent.change(passwordField, { target: { value: faker.lorem.word() } });
await fireEvent.click(submitButton);
await waitFor(() => expect(handleClose).toHaveBeenCalled());
});
现在测试通过了。
完整回购
https://github.com/brianbancroft/sample-testing-msw-sb-jest-rtl
使用模拟服务工作者 (msw) 响应网络请求,我有一个 React 登录组件。提交时它会发送一个网络请求,成功后它应该触发一个“handleClose”函数,它是组件的一个道具。
async function handleSubmit(event) {
event.preventDefault();
setLoading(true);
const { username, password } = event.target.elements;
try {
const response = await fetch("/login", {
method: "POST",
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
},
redirect: "follow",
referrerPolicy: "no-referrer",
body: JSON.stringify({
username: username.value,
password: password.value,
}),
});
await response.json();
if (response.status === 200) {
props.handleClose();
} else {
setInvalidUsernamePassword(true);
setLoading(false);
}
} catch (error) {
alert("Error detected", error);
}
}
当我测试时,我验证函数 handleClose
被调用。
const setup = async () => {
const handleClose = jest.fn();
const utils = await render(<Primary handleClose={handleClose} />);
const usernameField = screen.getByLabelText(/Username/);
const passwordField = screen.getByLabelText(/Password/);
const submitButton = screen.getByRole("button", {
name: /Sign In/i,
});
return {
usernameField,
passwordField,
submitButton,
handleClose,
...utils,
};
};
test("The handleClose function prop is triggered", async () => {
const { usernameField, passwordField, submitButton, handleClose } =
await setup();
fireEvent.change(usernameField, { target: { value: faker.lorem.word() } });
fireEvent.change(passwordField, { target: { value: faker.lorem.word() } });
fireEvent.click(submitButton);
expect(handleClose).toHaveBeenCalled();
});
这失败了
Expected number of calls: >= 1
Received number of calls: 0
但是,当我在异步函数开始之前调用 prop 函数时,它通过了,这告诉我这不是我将 jest.fn() 传递到组件中的方式。
我调查了是否会抛出错误(它不会),而且我也知道 msw
正在按预期工作,并且网络请求以 200 响应,除非我发送密码值“badpassword”,用于在同一文件的另一个测试中模拟不正确的电子邮件或密码。
我还转换了函数以使用 promises。没有变化。
这就是 waitFor
实用方法在 React 测试库中的用途。
https://testing-library.com/docs/dom-testing-library/api-async/
test("The handleClose function prop is triggered", async () => {
const { usernameField, passwordField, submitButton, handleClose } =
await setup();
fireEvent.change(usernameField, { target: { value: faker.lorem.word() } });
fireEvent.change(passwordField, { target: { value: faker.lorem.word() } });
await fireEvent.click(submitButton);
await waitFor(() => expect(handleClose).toHaveBeenCalled());
});
现在测试通过了。