React函数组件中的模拟引用

时间:2019-09-05 12:51:06

标签: reactjs jestjs enzyme react-hooks

我有React函数组件,其子组件之一具有ref。引用是通过useRef创建的。

我想用浅色渲染器测试组件。我必须以某种方式模拟ref以测试其余功能。

我似乎找不到任何方法可以找到该参考并对其进行模拟。我尝试过的事情

  • 通过childs属性访问它。 React并不喜欢这样,因为ref并不是真正的道具

  • 模拟useRef。我尝试了多种方法,但当我的实现使用React.useRef

  • 时,只能让它与间谍一起工作。

我看不到其他任何方法来模仿它。在这种情况下是否必须使用mount?

我无法发布真实场景,但我构建了一个小例子

it('should test', () => {
    const mock = jest.fn();
    const component = shallow(<Comp onHandle={mock}/>);


    // @ts-ignore
    component.find('button').invoke('onClick')();

    expect(mock).toHaveBeenCalled();
});

const Comp = ({onHandle}: any) => {
    const ref = useRef(null);

    const handleClick = () => {
        if (!ref.current) return;

        onHandle();
    };

    return (<button ref={ref} onClick={handleClick}>test</button>);
};

2 个答案:

答案 0 :(得分:3)

slideshowp2的解决方案对我不起作用,因此最终使用了另一种方法:

解决方法

  1. 引入useRef可选道具,默认情况下使用react的道具
import React, { useRef as defaultUseRef } from 'react'
const component = ({ useRef = defaultUseRef }) => {
  const ref = useRef(null)
  return <RefComponent ref={ref} />
}
  1. 在测试模拟中useRef
const mockUseRef = (obj: any) => () => Object.defineProperty({}, 'current', {
  get: () => obj,
  set: () => {}
})

// in your test
...
    const useRef = mockUseRef({ refFunction: jest.fn() })
    render(
      <ScanBarcodeView onScan={handleScan} useRef={useRef} />,
    )
...

答案 1 :(得分:2)

这是我的单元测试策略,在jest.spyOn钩上使用useRef方法监视。

index.tsx

import React from 'react';

export const Comp = ({ onHandle }: any) => {
  const ref = React.useRef(null);

  const handleClick = () => {
    if (!ref.current) return;

    onHandle();
  };

  return (
    <button ref={ref} onClick={handleClick}>
      test
    </button>
  );
};

index.spec.tsx

import React from 'react';
import { shallow } from 'enzyme';
import { Comp } from './';

describe('Comp', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });
  it('should do nothing if ref does not exist', () => {
    const useRefSpy = jest.spyOn(React, 'useRef').mockReturnValueOnce({ current: null });
    const component = shallow(<Comp></Comp>);
    component.find('button').simulate('click');
    expect(useRefSpy).toBeCalledWith(null);
  });

  it('should handle click', () => {
    const useRefSpy = jest.spyOn(React, 'useRef').mockReturnValueOnce({ current: document.createElement('button') });
    const mock = jest.fn();
    const component = shallow(<Comp onHandle={mock}></Comp>);
    component.find('button').simulate('click');
    expect(useRefSpy).toBeCalledWith(null);
    expect(mock).toBeCalledTimes(1);
  });
});

覆盖率100%的单元测试结果:

 PASS  src/stackoverflow/57805917/index.spec.tsx
  Comp
    ✓ should do nothing if ref does not exist (16ms)
    ✓ should handle click (3ms)

-----------|----------|----------|----------|----------|-------------------|
File       |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files  |      100 |      100 |      100 |      100 |                   |
 index.tsx |      100 |      100 |      100 |      100 |                   |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        4.787s, estimated 11s

源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/57805917