我最近必须为打开新浏览器窗口的 React 组件编写一个测试。为了打开新窗口,我在代码中使用了 window.open() 。这使得该组件易于编写,但我必须以不同的方式思考如何为此编写测试。
有关 window.open() 方法的更多信息,请参阅 mdn 网络文档。
为了设置位或背景,我有一个 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 ( <form onSubmit={onSubmit}> <label htmlFor="name">Name</label> <input name="name"> <p>Now we have our component, lets think about the test for it.</p> <h2> What I’d normally test </h2> <p>Normally I would test what has been rendered in my component, using assertions such as expect the component to have text content or assert the url is what is expected (using window.location.href), but I quickly realised that approach won’t work in jest for this example.</p> <p>Window.open opens a new browser window, so it doesn’t affect the component we are testing. We can’t see what is inside the new window or what its url is as it is outside of the scope of the component we are testing.</p> <p>So how do we test something that is outside of what we can see? We don’t actually need to test that a new window is opened as that would be testing the window interface’s functionality and not our code. Instead, we just need to test that the window.open method is called.</p> <h2> Mocking window.open() </h2> <p>Therefore we need to mock window.open() and test that it was called inside our code.<br> </p> <pre class="brush:php;toolbar:false">// 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(<MyForm baseURL="http://example.com" />); 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
以上是使用 Jest 在 JavaScript 中测试 window.open()的详细内容。更多信息请关注PHP中文网其他相关文章!