Jam*_*mes 5 unit-testing reactjs jestjs react-testing-library react-hooks
我有一个测试用例,我需要模拟 useRef 才能返回模拟当前值。我尝试了 jest.mock 但它返回一个 HTMLDivElement 。
代码:
const ref = useRef<HTMLDivElement | null>(null);
Run Code Online (Sandbox Code Playgroud)
测试:
jest.mock('react', () => {
const originReact = jest.requireActual('react');
return {
...originReact,
useRef: jest.fn(),
};
});
React.useRef.mockReturnValue({ current: {offsetWith: 100} });
Run Code Online (Sandbox Code Playgroud)
模拟回报
[ { type: 'return', value: { current: [HTMLDivElement] } } ]
Run Code Online (Sandbox Code Playgroud)
@jonrsharpe的建议是组件测试的一般原则,但你的问题是一个特例,涉及DOM的一些属性和方法,例如offsetWidth和getBoundingClientRect()方法。无法返回的运行环境jsdom和浏览器运行环境下的渲染引擎返回的结果导致方法offsetWidth返回的属性值getBoundingClientRect()始终为0。
所以这里我们需要mockref。
这里的mockref也很特别。除了用于jest.mock()部分模拟之外,该属性还将在组件安装后ref.current分配。react为了拦截这个操作,我们需要创建一个ref带有对象属性的mock对象current,使用Object.defineProperty()方法来定义这个属性的getterand ,并拦截属性赋值。setterref.current
jest.spyOn方法采用 accessType 的可选第三个参数,该参数可以是“get”或“set”,当您想要分别监视 getter 或 setter 时,这被证明是有用的。
例如
\nindex.tsx:
import React, { useEffect, useRef } from 'react';\n\nexport default function App() {\n const ref = useRef<HTMLDivElement>(null);\n useEffect(() => {\n console.log(ref.current?.offsetWidth);\n }, [ref]);\n return <div ref={ref}>app</div>;\n}\nRun Code Online (Sandbox Code Playgroud)\nindex.test.tsx:
import { render } from '@testing-library/react';\nimport React, { useRef } from 'react';\nimport { mocked } from 'ts-jest/utils';\nimport App from './';\n\njest.mock('react', () => {\n return {\n ...jest.requireActual<typeof React>('react'),\n useRef: jest.fn(),\n };\n});\n\nconst useMockRef = mocked(useRef);\n\ndescribe('66332902', () => {\n afterEach(() => {\n jest.clearAllMocks();\n });\n afterAll(() => {\n jest.resetAllMocks();\n });\n test('should mock ref and offsetWidth', () => {\n const ref = { current: {} };\n Object.defineProperty(ref, 'current', {\n set(_current) {\n if (_current) {\n jest.spyOn(_current, 'offsetWidth', 'get').mockReturnValueOnce(100);\n }\n this._current = _current;\n },\n get() {\n return this._current;\n },\n });\n useMockRef.mockReturnValueOnce(ref);\n render(<App />);\n });\n});\nRun Code Online (Sandbox Code Playgroud)\n测试结果:(见日志)
\n PASS examples/66332902/index.test.tsx (9.518 s)\n 66332902\n \xe2\x9c\x93 should mock ref and offsetWidth (39 ms)\n\n console.log\n 100\n\n at examples/66332902/index.tsx:6:13\n\nTest Suites: 1 passed, 1 total\nTests: 1 passed, 1 total\nSnapshots: 0 total\nTime: 10.106 s\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
24884 次 |
| 最近记录: |