自定义钩子:如何测试组件卸载时不调用的集合状态



卸载组件时不调用测试集状态

我有一个自定义钩子,它在页面加载时调用一个承诺来设置数据。为了确保在组件卸载时不会调用数据/错误的设置状态,我正在使用取消请求,如下所示:


function useService() {
const [data, setData] = useState([]);
const [error, setError] = useState("");
const [loading, setLoading] = useState({});
const [cancelRequest, setCancelRequest] = useState(false);
const getMessgaes = async () => {
setLoading(true);
try {
const res = await getChatLog();
if (!cancelRequest) {
setData(res);
setLoading(false);
}
} catch (e) {
if (!cancelRequest) {
setError(e);
setLoading(false);
}
}
};
useEffect(() => {
getMessgaes();
return () => {
setCancelRequest(true);
};
}, []);

return {
data, error, loading, cancelRequest
}
}

我的测试是:

it("if component is unmounted before response then set data is not called", async () => {
getChatLog.mockImplementation(() => {
setTimeout(()=>{
Promise.reject("error");
},500);
});
const {result, unmount, waitForNextUpdate} = renderHook(() => useService());
expect(result.current.cancelRequest).toEqual(false);
unmount();
expect(result.current.cancelRequest).toEqual(true);
await waitForNextUpdate();
expect(getChatLog).toHaveBeenCalledTimes(3);
expect(result.current.error).toEqual("");
});

但是我收到错误:


Warning: An update to TestHook inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
in TestHook
in Suspense

有人可以指导如何测试吗?

谢谢

首先,永远不要在useEffect钩子的清理函数中调用setState(),就像 componentWillUnmount(( 一样。

您不应该在componentWillUnmount()调用 setState((,因为组件永远不会被重新渲染。卸载组件实例后,将永远不会再次挂载该实例。

因此,清理useEffect测试代码没有意义。

其次,使用带有延迟的setTimeout()进行模拟实现也没有意义,我们不需要在测试用例中延迟它,它使测试用例变慢,我们必须为它模拟计时器。您可以改用mock.mockRejectedValueOnce('error')

最后,您应该在断言之前await waitForNextUpdate()解决警告:Warning: An update to TestComponent inside a test was not wrapped in act(...).

例如

useService.ts

import { useEffect, useState } from 'react';
import { getChatLog } from './getChatLog';
export function useService() {
const [data, setData] = useState<string[]>([]);
const [error, setError] = useState('');
const [loading, setLoading] = useState({});
const [cancelRequest, setCancelRequest] = useState(false);
const getMessgaes = async () => {
setLoading(true);
try {
const res = await getChatLog();
if (!cancelRequest) {
setData(res);
setLoading(false);
}
} catch (e) {
if (!cancelRequest) {
setError(e);
setLoading(false);
}
}
};
useEffect(() => {
getMessgaes();
}, []);
return { data, error, loading, cancelRequest };
}

getChatLog.ts

export async function getChatLog() {
return ['real data'];
}

useService.test.ts

import { renderHook } from '@testing-library/react-hooks';
import { useService } from './useService';
import { getChatLog } from './getChatLog';
import { mocked } from 'ts-jest/utils';
jest.mock('./getChatLog');
describe('58026328', () => {
test('should pass', async () => {
const mGetChatLog = mocked(getChatLog);
mGetChatLog.mockRejectedValueOnce('error');
const { result, waitForNextUpdate } = renderHook(useService);
await waitForNextUpdate();
expect(result.current.cancelRequest).toEqual(false);
});
});

测试结果:

PASS  examples/58026328/useService.test.ts
58026328
✓ should pass (20 ms)
---------------|---------|----------|---------|---------|-------------------
File           | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
---------------|---------|----------|---------|---------|-------------------
All files      |   82.61 |       25 |      80 |   81.82 |                   
getChatLog.ts |      50 |      100 |       0 |      50 | 2                 
useService.ts |   85.71 |       25 |     100 |      85 | 14-16             
---------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.56 s, estimated 13 s

相关内容

  • 没有找到相关文章

最新更新