【问题标题】:How can I test that url search changed with react testing library?如何测试使用反应测试库更改的 url 搜索?
【发布时间】:2021-08-06 21:20:57
【问题描述】:

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

App.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>
  );
}

App.spec.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!"));
  });
});

问题是我得到了:

    Error: Not implemented: navigation (except hash changes)

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

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

【问题讨论】:

标签: reactjs jestjs mocking react-testing-library jsdom


【解决方案1】:

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

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

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

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

例如

App.tsx:

import React from 'react';
import { useEffect, useState } from 'react';

export default function App() {
  const [urlChanged, setUrlChanged] = useState(false);
  const handleURLSearchChange = () => {
    window.location.search = '?' + new URLSearchParams({ foo: 'bar' }).toString();
    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>
  );
}

App.test.tsx:

import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom';
import React from 'react';
import App from './App';

describe('App', () => {
  it('Reacts to url changes when touching the button', async () => {
    Object.defineProperty(window, 'location', {
      value: {
        search: '',
      },
    });
    render(<App />);
    const button = await screen.findByLabelText('change');
    let label = await screen.findByLabelText('URL Status');
    await waitFor(() => expect(label).toHaveTextContent('Not yet'));
    userEvent.click(button);
    label = await screen.findByLabelText('URL Status');
    await waitFor(() => expect(label).toHaveTextContent('Changed!'));
  });
});

测试结果:

 PASS  examples/67572637/App.test.tsx (8.34 s)
  App
    ✓ Reacts to url changes when touching the button (48 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |       75 |     100 |     100 |                   
 App.tsx  |     100 |       75 |     100 |     100 | 8                 
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        8.906 s

【讨论】:

    猜你喜欢
    • 2021-05-09
    • 2022-06-21
    • 2020-01-21
    • 1970-01-01
    • 2018-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多