如何使用 jest.mock 和 react 测试库模拟 useRef [英] How to mock useRef using jest.mock and react testing library
问题描述
我有一个测试用例,我需要模拟 useRef 以返回模拟当前值.我试过 jest.mock,但它返回一个 HTMLDivElement.
I have a test case where I need to mock useRef inorder to return a mock current value. I tried jest.mock but it returns an HTMLDivElement instead.
代码:
const ref = useRef<HTMLDivElement | null>(null);
测试:
jest.mock('react', () => {
const originReact = jest.requireActual('react');
return {
...originReact,
useRef: jest.fn(),
};
});
React.useRef.mockReturnValue({ current: {offsetWith: 100} });
模拟返回
[ { type: 'return', value: { current: [HTMLDivElement] } } ]
推荐答案
@jonrsharpe的建议是组件测试的一般原则,但是你的问题是特例,涉及到DOM的一些属性和方法,比如offsetWidth
和 getBoundingClientRect()
方法.jsdom
的运行环境无法返回和浏览器运行环境下的渲染引擎返回的结果导致offsetWidth
和getBoundingClientRect()返回的属性值
方法总是 0
.
@jonrsharpe's suggestion is the general principle of component testing, but your question is a special case, involving some properties and methods of the DOM, such as offsetWidth
and getBoundingClientRect()
methods. The runtime environment of jsdom
cannot return and the rendering engine under the browser runtime environment The returned result causes the offsetWidth
and the property values returned by the getBoundingClientRect()
method to always be 0
.
所以这里我们需要模拟ref
.
So here we need mock ref
.
这里的模拟 ref
也很特别.除了使用 jest.mock()
进行部分模拟之外,ref.current
属性将在组件安装后由 react
分配.为了拦截这个操作,我们需要创建一个带有 current
对象属性的模拟 ref
对象,使用 Object.defineProperty()
方法为这个ref.current
属性定义getter
和setter
,并拦截属性赋值.
The mock ref
here is also special. In addition to using jest.mock()
for partial mocking, the ref.current
property will be assigned by react
after the component is mounted. In order to intercept this operation, we need to create a mock ref
object with a current
object property, use the Object.defineProperty()
method to define getter
and setter
for this ref.current
property, and intercept property assignment.
jest.spyOn
方法采用 accessType 的第三个可选参数,可以是 'get' 或 'set',这在你想监视 getter 或 setter 时被证明是有用的,分别.
jest.spyOn
method takes an optional third argument of accessType that can be either 'get' or 'set', which proves to be useful when you want to spy on a getter or a setter, respectively.
例如
index.tsx
:
import React, { useEffect, useRef } from 'react';
export default function App() {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
console.log(ref.current?.offsetWidth);
}, [ref]);
return <div ref={ref}>app</div>;
}
index.test.tsx
:
import { render } from '@testing-library/react';
import React, { useRef } from 'react';
import { mocked } from 'ts-jest/utils';
import App from './';
jest.mock('react', () => {
return {
...jest.requireActual<typeof React>('react'),
useRef: jest.fn(),
};
});
const useMockRef = mocked(useRef);
describe('66332902', () => {
afterEach(() => {
jest.clearAllMocks();
});
afterAll(() => {
jest.resetAllMocks();
});
test('should mock ref and offsetWidth', () => {
const ref = { current: {} };
Object.defineProperty(ref, 'current', {
set(_current) {
if (_current) {
jest.spyOn(_current, 'offsetWidth', 'get').mockReturnValueOnce(100);
}
this._current = _current;
},
get() {
return this._current;
},
});
useMockRef.mockReturnValueOnce(ref);
render(<App />);
});
});
测试结果:(查看日志)
PASS examples/66332902/index.test.tsx (9.518 s)
66332902
✓ should mock ref and offsetWidth (39 ms)
console.log
100
at examples/66332902/index.tsx:6:13
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.106 s
这篇关于如何使用 jest.mock 和 react 测试库模拟 useRef的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!