如何测试使用 React 测试库更改的 url 搜索?

Dam*_*ira 5 mocking jsdom reactjs jestjs react-testing-library

我有一个对 url 搜索更改做出反应的组件,以及一个更改 url 搜索的按钮。我想测试当我单击按钮时,组件会做出相应的反应。这是一个codesandbox:https ://codesandbox.io/s/react-testing-library-url-change-test-b5zq1 。

应用程序.js

export default function App() {
  const [urlChanged, setUrlChanged] = useState(false);
  const handleURLSearchChange = () => {
    window.location.search = new URLSearchParams({ foo: "bar" });
  };
  useEffect(() => {
    if (window.location.search.length !== 0) {
      setUrlChanged(true);
    }
  }, []);
  return (
    <div>
      <button aria-label="change" onClick={handleURLSearchChange}>
        Change URL search
      </button>
      <p aria-label="URL Status">{urlChanged ? "Changed!" : "Not yet"}</p>
    </div>
  );
}

Run Code Online (Sandbox Code Playgroud)

应用程序规范.js

describe("App", () => {
  it("Reacts to url changes when touching the button", async () => {
    render(<App />);
    const button = await screen.findByLabelText("change");
    userEvent.click(button);
    const label = await screen.findByLabelText("URL Status");
    await waitFor(() => expect(label).toHaveTextContent("Changed!"));
  });
});

Run Code Online (Sandbox Code Playgroud)

问题是我得到:

    Error: Not implemented: navigation (except hash changes)

Run Code Online (Sandbox Code Playgroud)

注意:只有当我下载沙箱并运行 npm install 和 npm test 时,我才能看到此错误。

我是否必须使用 setter 和 getter 来模拟 window.location 对象?更好的方法是什么?

sli*_*wp2 1

您的组件代码实现存在一些问题。

\n

如果第二个参数是空数组,则只会执行一次,因此更改事件处理程序中useEffect的值不会再次触发。您需要检查事件处理程序来决定是否设置 的值。window.location.searchhandleURLSearchChangeuseEffectlocation.searchurlChanged

\n

正如 @jonrsharpe 的评论所说,JSDOM 不支持导航。我们需要使用 来模拟它Object.defineProperty()

\n

此外,类的实例URLSearchParams不能分配给window.location.search. 用于.toString()将其转换为字符串。

\n

例如

\n

App.tsx

\n
import React from 'react';\nimport { useEffect, useState } from 'react';\n\nexport default function App() {\n  const [urlChanged, setUrlChanged] = useState(false);\n  const handleURLSearchChange = () => {\n    window.location.search = '?' + new URLSearchParams({ foo: 'bar' }).toString();\n    if (window.location.search.length !== 0) {\n      setUrlChanged(true);\n    }\n  };\n\n  return (\n    <div>\n      <button aria-label="change" onClick={handleURLSearchChange}>\n        Change URL search\n      </button>\n      <p aria-label="URL Status">{urlChanged ? 'Changed!' : 'Not yet'}</p>\n    </div>\n  );\n}\n
Run Code Online (Sandbox Code Playgroud)\n

App.test.tsx

\n
import { render, screen, waitFor } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport '@testing-library/jest-dom';\nimport React from 'react';\nimport App from './App';\n\ndescribe('App', () => {\n  it('Reacts to url changes when touching the button', async () => {\n    Object.defineProperty(window, 'location', {\n      value: {\n        search: '',\n      },\n    });\n    render(<App />);\n    const button = await screen.findByLabelText('change');\n    let label = await screen.findByLabelText('URL Status');\n    await waitFor(() => expect(label).toHaveTextContent('Not yet'));\n    userEvent.click(button);\n    label = await screen.findByLabelText('URL Status');\n    await waitFor(() => expect(label).toHaveTextContent('Changed!'));\n  });\n});\n
Run Code Online (Sandbox Code Playgroud)\n

测试结果:

\n
 PASS  examples/67572637/App.test.tsx (8.34 s)\n  App\n    \xe2\x9c\x93 Reacts to url changes when touching the button (48 ms)\n\n----------|---------|----------|---------|---------|-------------------\nFile      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s \n----------|---------|----------|---------|---------|-------------------\nAll files |     100 |       75 |     100 |     100 |                   \n App.tsx  |     100 |       75 |     100 |     100 | 8                 \n----------|---------|----------|---------|---------|-------------------\nTest Suites: 1 passed, 1 total\nTests:       1 passed, 1 total\nSnapshots:   0 total\nTime:        8.906 s\n
Run Code Online (Sandbox Code Playgroud)\n