使用 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 拍摄