我如何开玩笑地测试与第三方API一起使用的自定义回调?

时间:2019-05-06 16:25:44

标签: javascript reactjs jestjs

我的代码的简化设置如下:

App.js

class App extends React.Component {
  componentDidMount() {
    const { thirdPartyAPI } = this.props;
    thirdPartyAPI.field.onValueChanged(this.handleValueChange);
  }

  handleValueChange = (value) => {
    // callback to do complex validation stuff and suchlike
    // update state
  }

  render() {
    // display stuff
  }
}

App.test.js

each([...]).
  .test('App is rendered according to...',
    async (...) => {

    const mockApi = {
      field: {
        onValueChanged: ????
      }
    }

    const AppComponent = await shallow(
      <App thirdPartyAPI={mockApi} />,
    );
  });

OnValueChanged检测用户何时更改了react-app之外的值。从用户的角度来看,这是可行的,但是开玩笑的测试给我带来了麻烦。

简单地说:我该如何测试?

我需要模拟API函数,但是我需要使用App.js中定义的回调函数handleValueChange。我已经忘记了我所阅读和观看的开玩笑教程,其中很多非常详细,但是似乎没有一个适用于这种特殊情况。

是否有可能测试此代码?如果是这样,怎么办?如果没有,我应该如何重组我的代码,以便我可以测试它?

如果有人可以指出正确的方向,我将不胜感激。

1 个答案:

答案 0 :(得分:1)

如果您以thirdPartyAPI.field.onValueChanged的形式将模拟函数传递给组件,则它将以this.handleValueChange进行调用。

模拟功能会记录调用它们的所有内容,因此您可以使用模拟功能通过mockFn.mock.calls获取this.handleValueChange

在测试中检索到this.handleValueChange后,您可以直接调用它并验证它是否按预期工作。

这是一个简单的工作示例:

import * as React from 'react';
import { shallow } from 'enzyme';

class App extends React.Component {
  constructor(...args) {
    super(...args);
    this.state = { val: 'original' };
  }

  componentDidMount() {
    const { thirdPartyAPI } = this.props;
    thirdPartyAPI.field.onValueChanged(this.handleValueChange);
  }

  handleValueChange = (value) => {
    this.setState({ val: value });
  }

  render() { return null; }
}

test('App', () => {
  const onValueChangedMock = jest.fn();
  const thirdPartyAPIMock = { field: { onValueChanged: onValueChangedMock } };

  const wrapper = shallow(<App thirdPartyAPI={thirdPartyAPIMock} />);
  expect(wrapper.state('val')).toBe('original');  // Success!

  const handleValueChange = onValueChangedMock.mock.calls[0][0];  // <= get handleValueChange...
  handleValueChange('updated');  // <= ...now call it directly

  expect(wrapper.state('val')).toBe('updated');  // Success!
})