使用 Jest 在 JavaScript 中测试 window.open()
我最近必须为打开新浏览器窗口的 React 组件编写测试。为了打开新窗口,我在代码中使用了 window.open()。这使得组件易于编写,但我必须以不同的方式思考如何为此编写测试。
有关 window.open() 方法的更多信息请参阅 mdn web 文档。
为了设置位或背景,我使用了一个 React 组件,该组件包含一个带有几个输入的简单表单。当用户完成输入并提交表单时,它会打开一个指向指定 URL 的新窗口,并将输入作为 URL 参数。
要测试的组件
以下是该组件的一个非常简化的版本,仅供演示。我建议使用类似 react-hook-form 的东西来为表单添加验证。
// MyForm.js
import React, { useState } from "react";
const MyForm = ({ baseURL }) => {
const [name, setName] = useState("");
const [subject, setSubject] = useState("");
const onSubmit = () => {
window.open(
`${baseURL}?name=${encodeURIComponent(name)}&subject=${encodeURIComponent(
subject
)}`,
"_blank"
);
};
return (
);
};
export default MyForm;现在我们有了组件,让我们考虑对它进行测试。
我通常会测试什么
通常我会测试我的组件中呈现的内容,使用断言,例如期望组件具有文本内容或断言 url 是预期的(使用 window.location.href),但我很快意识到这种方法对于这个例子来说是行不通的。
Window.open 打开一个新的浏览器窗口,因此它不会影响我们正在测试的组件。我们看不到新窗口里面有什么,也看不到它的 URL 是什么,因为它超出了我们正在测试的组件的范围。
那么我们如何测试我们无法看到的东西呢?我们实际上不需要测试是否打开了新窗口,因为那样会测试窗口界面的功能而不是我们的代码。相反,我们只需要测试是否调用了 window.open 方法。
模拟 window.open()
因此我们需要模拟 window.open() 并测试它是否在我们的代码中被调用。
// Mock window.open global.open = jest.fn();
现在我们可以设置输入中的值,提交表单,然后测试是否调用了 window.open。我们可以使用 fireEvent 来设置输入的值并按下提交按钮。
fireEvent.input(screen.getByLabelText("Name"), {
target: {
value: "Test Name",
},
});
fireEvent.input(screen.getByLabelText("Subject"), {
target: {
value: "An example subject",
},
});
fireEvent.submit(
screen.getByRole("button", { name: "Submit (opens in new window)" })
);值得一读文档,了解 fireEvent 的注意事项。根据你的使用情况,你可能希望使用用户事件。
我们希望等待方法运行。我们可以使用 waitFor() 来实现。
await waitFor(() => {
expect(global.open).toHaveBeenCalled();
});为了确保我们不会打开大量新窗口,我们可以检查只调用一次 window.open。
await waitFor(() => {
expect(global.open).toHaveBeenCalledTimes(1);
});我们还可以检查调用该方法的参数,将我们期望的 URL 作为第一个参数传递,将目标作为第二个参数传递。
await waitFor(() => {
expect(global.open).toHaveBeenCalledWith(
"http://example.com?name=Test%20Name&subject=An%20example%20subject",
"_blank"
);
});完整的测试文件
这是完整的测试文件,供您参考。
// MyForm.test.js
import React from "react";
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import MyForm from "./MyForm";
describe("MyForm test", () => {
beforeEach(() => {
// Mock window.open
global.open = jest.fn();
});
it("opens a new window with the correct url", async () => {
render( );
fireEvent.input(screen.getByLabelText("Name"), {
target: {
value: "Test Name",
},
});
fireEvent.input(screen.getByLabelText("Subject"), {
target: {
value: "An example subject",
},
});
fireEvent.submit(
screen.getByRole("button", { name: "Submit (opens in new window)" })
);
await waitFor(() => {
expect(global.open).toHaveBeenCalled();
expect(global.open).toHaveBeenCalledTimes(1);
expect(global.open).toHaveBeenCalledWith(
"http://example.com?name=Test%20Name&subject=An%20example%20subject",
"_blank"
);
});
});
});照片由 stockSnap 上的 energepic.com 拍摄