reactjs - 如何使用 jest.mock 模拟 useRef 并 react 测试库

标签 reactjs unit-testing jestjs react-hooks react-testing-library

我有一个测试用例,我需要模拟 useRef 以返回模拟当前值。我尝试了 jest.mock,但它返回的是 HTMLDivElement。

代码:

   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的一些属性和方法,比如offsetWidthgetBoundingClientRect()方法。 jsdom运行环境无法返回,浏览器运行环境下渲染引擎返回结果导致offsetWidthgetBoundingClientRect()<返回的属性值 方法始终为 0

所以这里我们需要 mock ref

这里的 mock ref 也比较特殊。除了使用 jest.mock() 进行部分模拟之外, ref.current 属性将在组件安装后由 react 分配。为了拦截这个操作,我们需要创建一个带有current对象属性的模拟ref对象,使用Object.defineProperty()方法为这个ref.current属性定义gettersetter,并拦截属性赋值。

jest.spyOn 方法采用 accessType 的可选第三个参数,可以是 'get' 或 'set',这在您想要监视 getter 或 setter 时很有用,分别。

例如

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

关于reactjs - 如何使用 jest.mock 模拟 useRef 并 react 测试库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66332902/

相关文章:

reactjs - 动画高度属性 tailwindcss

reactjs - 如何以编程方式清除和选择项目

php - 取消单元测试中的文件修改

unit-testing - 参数异常应该进行单元测试吗?

javascript - 如何使用 jest 测试 javascript 中的抽象函数?

jestjs - 手动模拟未被拾取

javascript - 我应该导出单例类以在 React 中使用吗?

android - React-Native 更改 iOS 和 Android 文件夹的默认位置

javascript - 如何为类型类编写单元测试?

typescript - Jest 在没有 webpack 的情况下配置 typescript