问题描述
我有一个对 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 对象?什么是更好的方法?
解决方法
您的组件代码实现存在一些问题。
如果第二个参数是一个空数组,useEffect
只会执行一次,所以在事件处理器window.location.search
中改变handleURLSearchChange
的值不会再次触发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