跳到主要内容

hook 的单元测试

注意

对 Reactive Data Client 这类模块使用 jest.mock 时要小心。去掉预期的导出可能导致难以追踪的错误,例如 TypeError: Class extends value undefined is not a function or null。

你可以改用部分 mock,或者更好的做法是对你的 endpoint 使用 mockResolvedValue。

hook 让你可以把复杂的行为从组件中抽离出来,变成简洁、可组合的函数。这可能会让测试组件行为变得容易得多。但如果你想使用 Reactive Data Client 提供的 hook,又该怎么做呢?

我们提供了一些简单的工具来减少单元测试的样板代码,它们是对 @testing-library/react-hooks 的 renderHook() 的封装。

我们需要一个 renderDataHook() 函数,它会同时在 Provider 和 Suspense 边界的上下文中渲染。

这些通常在测试初始化时完成。每个测试结束后会自动执行清理。

备注

renderDataHook() 会创建一个带有全新 manager 实例的 Provider context。这意味着每次调用 renderDataHook() 都会得到全新的缓存状态和 manager 状态。

在 node < 18 中为 fetch 添加 polyfill​

Node 默认不自带 fetch,因此我们必须为它添加 polyfill。

npm install --save-dev whatwg-fetch

Jest​

// jest.config.js
module.exports = {
// other things
setupFiles: ['./testSetup.js'],
};
// testSetup.js
require('whatwg-fetch');

示例:​

import nock from 'nock';
import { useSuspense } from '@data-client/react';
import { renderDataHook } from '@data-client/test';
import { ArticleResource } from '../resources/Article';

describe('useSuspense()', () => {
beforeEach(() => {
nock(/.*/)
.persist()
.defaultReplyHeaders({
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json',
})
.options(/.*/)
.reply(200)
.get(`/article/0`)
.reply(403, {});
});

afterEach(() => {
nock.cleanAll();
});

it('should throw errors on bad network', async () => {
const { result, waitFor } = renderDataHook(() => {
return useSuspense(ArticleResource.get, {
title: '0',
});
});
expect(result.current).toBeUndefined();
await waitFor(() => expect(result.current).toBeDefined());
expect(result.error).toBeDefined();
expect((result.error as any).status).toBe(403);
});
});