9

我正在使用 Typescript 和 hooks 开发一个 React 应用程序,并且我正在尝试使用 Enzyme 和 Jest 来测试功能组件。我无法使用 jest.spyOn 来测试我的组件中的方法。jest.spyOn 方法无法正确解析并在悬停时显示以下消息

““validateBeforeSave”类型的参数不能分配给“context”|“setState”|“forceUpdate”|“render”|“componentDidMount”|“shouldComponentUpdate”|“componentWillUnmount”|“componentDidCatch”|“ getSnapshotBeforeUpdate" | ... 6 更多 ... | "UNSAFE_componentWillUpdate"'.ts(2345)"

我试图将实例转换为“任何”-

const instance = wrapper.instance() as any;

这当然忽略了编译时的问题,但是测试会抛出一个运行时错误,即组件上不存在函数。

无法窥探 validateBeforeSave 属性,因为它不是函数;给定的未定义

// Some function Component

const SomeComponent = (props: IMyComponentProps) => {
  const { classes } = props;

  // Component has state
  const [count, setCount] = useState(0);

  function validateBeforeSave(){

  }

  function handleClick() {
  validateBeforeSave();
  .
  .
  .
  }

  return (
   <div>
      <Button>
      className="saveBtn"
      onClick={handleClick}
      </Button>
    </div>
  );

  };

  // Unit test
  describe('SomeComponent' () => {
  it('validates model on button click', () => {
      const wrapper = mount(
        <MuiThemeProvider theme={theme}>
          <SomeComponent/>
        </MuiThemeProvider>,
      );
  const instance = wrapper.instance();
      const spy = jest.spyOn(instance, "validateBeforeSave");
  wrapper
        .find('.saveBtn')
        .at(0)
        .simulate('click');
      expect(spy).toHaveBeenCalledTimes(1);
    });
  }

我在这里想念什么?spyOn 如何与函数组件一起工作?

我使用 create-react-app 模板创建了应用程序,它具有测试包的这些依赖项

"devDependencies": {
    "ts-jest": "^23.10.3",
    "@types/jest": "24.0.9",
    "@types/enzyme": "^3.9.1",
    "@types/enzyme-adapter-react-16": "^1.0.2",
    "enzyme": "^3.9.0",
    "enzyme-adapter-react-16": "^1.11.2",
    "enzyme-to-json": "^3.3.5",
  }
4

3 回答 3

5

您的validateBeforeSave函数在内部声明,SomeComponent使其成为外部无法访问的封闭/私有范围函数。您可以将该函数作为道具传递,然后您可以创建间谍并将其作为道具值在您的测试中传递,并测试传递的道具函数(间谍)是否被调用

所以你会修改你的函数有点像这样:

// some validator function
function validateBeforeSave(){
  ...
}

// Some function Component

const SomeComponent = (props: IMyComponentProps) => {
  const { classes, validateBeforeSave } = props;

  // Component has state
  const [count, setCount] = useState(0);


  function handleClick() {
  validateBeforeSave();
  .
  .
  .
  }

  return (
   <div>
      <Button>
      className="saveBtn"
      onClick={handleClick}
      </Button>
    </div>
  );

};

在你的单元测试中,像这样:

  // Unit test
  describe('SomeComponent' () => {
  it('validates model on button click', () => {
      const validateSpy = jest.fn();
      const wrapper = mount(
        <MuiThemeProvider theme={theme}>
          <SomeComponent validateSpy={validateSpy}/>
        </MuiThemeProvider>,
      );
      const instance = wrapper.instance();
      wrapper
        .find('.saveBtn')
        .at(0)
        .simulate('click');
      expect(validateSpy).toHaveBeenCalledTimes(1);
    });
  }
于 2019-05-24T18:17:03.737 回答
2

我也面临同样的问题 - 我确实喜欢下面 -

import * as React from 'react';

const SampleComponent = () => {
  const sampleMethod = () => {
    console.log('hello world');
  };

  return <button onClick={sampleMethod} type="button">Click Me</button>;
};

export default SampleComponent;

测试 -

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

describe('SampleComponent', () => {
  test('should handle click correctly', () => {
    const logSpy = jest.spyOn(console, 'log');
    const wrapper = shallow(<SampleComponent></SampleComponent>);
    const button = wrapper.find('button');
    expect(button.text()).toBe('Click Me');
    button.simulate('click');
    expect(logSpy).toBeCalledWith('hello world');
  });
});

我们可以监视console.log,断言它是否被调用

检查 - https://stackoverflow.com/a/58637912/10734622

于 2020-02-03T09:25:44.020 回答
0

我在使用 React 16.xx 模拟回调 prop 方法时遇到了类似的问题,酶实例方法返回 null,你可以做的是直接将 jest.fn() 作为 prop 传递。

例子:

  it('should invoke callback with proper data upon checkbox click', () => {
    const spyCheckboxClick = jest.fn((id, item) => ({
      id,
      item,
    }))
    const component: any = enzyme.mount(
      <SectionColumn {...{
        ...mockProps,
        onCheckboxClick: spyCheckboxClick,
      }} />
    );
    expect(spyCheckboxClick).toHaveBeenCalledTimes(0);
    // perform click to checkbox
    const checkboxComponent = component.find('StyledCheckbox');
    const input = checkboxComponent.first().children();
    input.simulate('change');
    expect(spyCheckboxClick).toHaveBeenCalledTimes(1);
    expect(spyCheckboxClick()).toEqual(null)
 });
于 2021-02-16T12:19:06.227 回答