模拟 React useRef 或带有酶和玩笑的功能组件内的函数?
Posted
技术标签:
【中文标题】模拟 React useRef 或带有酶和玩笑的功能组件内的函数?【英文标题】:Mock React useRef or a function inside a functional component with enzyme and jest? 【发布时间】:2020-08-30 02:55:52 【问题描述】:Codesanbox link - 包括工作组件 Child2.js 和工作测试 Child2.test.js
Child2.js
import React, useRef from "react";
export default function Child2()
const divRef = useRef();
function getDivWidth()
if (divRef.current)
console.log(divRef.current);
return divRef.current ? divRef.current.offsetWidth : "";
function getDivText()
const divWidth = getDivWidth();
if (divWidth)
if (divWidth > 100)
return "ABC";
return "123";
return "123";
return (
<>
<div id="myDiv" ref=divRef>
getDivText()
</div>
<p>Div width is: getDivWidth()</p>
</>
);
Child2.test.js
import React from "react";
import Enzyme, shallow from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import Child2 from "../src/Child2";
Enzyme.configure( adapter: new Adapter() );
it("div text is ABC when div width is more then 100 ", () =>
const wrapper = shallow(<Child2 />);
expect(wrapper.find("#myDiv").exists()).toBe(true);
expect(wrapper.find("#myDiv").text()).toBe("ABC");
);
it("div text is 123 when div width is less then 100 ", () =>
const wrapper = shallow(<Child2 />);
expect(wrapper.find("#myDiv").exists()).toBe(true);
expect(wrapper.find("#myDiv").text()).toBe("123");
);
当我运行测试时,显然 div 的 offsetWidth 为 0,因此我需要找到一种方法来模拟 useRef
以返回具有宽度的 div 元素或模拟 getDivWidth
函数以返回所需的数字为宽度。
我怎样才能做到这一点?我一直在寻找解决方案,但我被卡住了。有一些带有类组件或使用打字稿的示例,但我没有设法使用。
【问题讨论】:
【参考方案1】:您可以使用jest.mock(moduleName, factory, options) 和jest.requireActual(moduleName) API 来模拟useRef
钩子,除了其他的。也就是说react
的其他函数和方法还是原来的版本。
例如
index.jsx
:
import React, useRef from 'react';
export default function Child2()
const divRef = useRef();
function getDivWidth()
if (divRef.current)
console.log(divRef.current);
return divRef.current ? divRef.current.offsetWidth : '';
function getDivText()
const divWidth = getDivWidth();
if (divWidth)
if (divWidth > 100)
return 'ABC';
return '123';
return '123';
return (
<>
<div id="myDiv" ref=divRef>
getDivText()
</div>
<p>Div width is: getDivWidth()</p>
</>
);
index.test.jsx
:
import React, useRef from 'react';
import shallow from 'enzyme';
import Child2 from './';
jest.mock('react', () =>
const originReact = jest.requireActual('react');
const mUseRef = jest.fn();
return
...originReact,
useRef: mUseRef,
;
);
describe('61782695', () =>
it('should pass', () =>
const mRef = current: offsetWidth: 100 ;
useRef.mockReturnValueOnce(mRef);
const wrapper = shallow(<Child2></Child2>);
expect(wrapper.find('#myDiv').text()).toBe('123');
expect(wrapper.find('p').text()).toBe('Div width is: 100');
);
it('should pass - 2', () =>
const mRef = current: offsetWidth: 300 ;
useRef.mockReturnValueOnce(mRef);
const wrapper = shallow(<Child2></Child2>);
expect(wrapper.find('#myDiv').text()).toBe('ABC');
expect(wrapper.find('p').text()).toBe('Div width is: 300');
);
it('should pass - 3', () =>
const mRef = ;
useRef.mockReturnValueOnce(mRef);
const wrapper = shallow(<Child2></Child2>);
expect(wrapper.find('#myDiv').text()).toBe('123');
expect(wrapper.find('p').text()).toBe('Div width is: ');
);
);
100% 覆盖率的单元测试结果:
PASS ***/61782695/index.test.jsx (9.755s)
61782695
✓ should pass (111ms)
✓ should pass - 2 (15ms)
✓ should pass - 3 (1ms)
console.log
offsetWidth: 100
at getDivWidth (***/61782695/index.jsx:8:15)
console.log
offsetWidth: 100
at getDivWidth (***/61782695/index.jsx:8:15)
console.log
offsetWidth: 300
at getDivWidth (***/61782695/index.jsx:8:15)
console.log
offsetWidth: 300
at getDivWidth (***/61782695/index.jsx:8:15)
-----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.jsx | 100 | 100 | 100 | 100 |
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 10.885s
软件包版本:
"react": "^16.13.1",
"react-dom": "^16.13.1",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"jest": "^25.5.4",
"jest-environment-enzyme": "^7.1.2",
"jest-enzyme": "^7.1.2",
【讨论】:
非常感谢,这很有效,让我免于头疼。再问你一个问题,如果我在我的组件中添加一个useLayoutEffect
,它将读取使用divref.current.childNodes
来获取所有li
元素的宽度,我将如何更改测试?我试过了,在测试中它永远不会进入useLayoutEffect
的函数内部。在现实生活中我有这种情况,在第一次渲染时组件没有引用,在第二次渲染时我有引用,然后我使用该元数据进行组件内部的操作。
@VergilC。您需要提出一个新问题
我会收到这个打字稿错误 -> Error:(397, 21) TS2339: Property 'mockReturnValueOnce' does not exist on type '<T>() => RefObject<T>'.
任何想法如何解决这个问题?
@ChristianSaiki 模拟 React 及其类型,然后从中使用 useRef。 const mockedReact = React as jest.Mocked<typeof React>;
然后mockedReact.useRef.mockReturnValueOnce(mRef);
@MantasAstra 我收到错误mockedReact.useRef.mockReturnValueOnce is not a function
知道吗?以上是关于模拟 React useRef 或带有酶和玩笑的功能组件内的函数?的主要内容,如果未能解决你的问题,请参考以下文章
使用 Jest 和酶时如何在 React.useEffect 钩子上获得线路覆盖?