如何使用 jest.mock 和 react 测试库模拟 useRef [英] How to mock useRef using jest.mock and react testing library

查看:80
本文介绍了如何使用 jest.mock 和 react 测试库模拟 useRef的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个测试用例,我需要模拟 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的一些属性和方法,比如offsetWidthgetBoundingClientRect() 方法.jsdom的运行环境无法返回和浏览器运行环境下的渲染引擎返回的结果导致offsetWidthgetBoundingClientRect()返回的属性值 方法总是 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属性定义gettersetter,并拦截属性赋值.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆