不能监视原始值; undefined given - 在连接组件的 onChange 中测试函数执行

Cannot spyOn on a primitive value; undefined given - Testing a function execution in onChange in connected component

测试新手,这是一个使用 redux 的连接组件。我正在测试是否调用了 maskPromoCode 函数。使用当前的测试代码,错误显示:无法监视原始值;给定未定义

不明白为什么。谢谢

组件:

class Textbox extends React.Component {
  constructor(props) {
      super(props);
  }

 onChange(e) {
    e.preventDefault();
    this.setState({
      value: this.maskPromoCode(e.target.value) 
    })
 }

  maskPromoCode(value) {...}

  render() {
    return (
      <>
        <input
          ...
          onChange={e => this.onChange(e)} 
        />  
      </>
    );
  }
}
const mapDispatchToProps = { setError, setPwError };
export default connect(null, mapDispatchToProps)(Textbox);

测试文件

it('invokes the maskPromoCode function with event value', () => {
    const funcMock = jest.spyOn(Textbox.prototype, 'maskPromoCode');
    
    const wrapper = mount(
      <Provider store={store}>
        <Textbox {...baseProps} name="redeem-promo" />
      </Provider>
    );

    const inputField = wrapper.find('input');
    const event = {
      target: {
        value: 'event value',
      },
    };
    inputField.simulate('change', event);
    expect(funcMock).toHaveBeenCalledWith(event.target.value);
  });
  1. Textbox组件被connect函数包裹,变成了没有prototype的HOC,我猜你在测试中导入了HOC文件。测试文件中导入的 TextBox 组件是一个 HOC。所以 TextBox.prototypeundefined,这就是 jest.spyOn 抛出错误的原因。

  2. maskPromoCode方法如果坚持要用jest.spyOn(),可以用jest.spyOn(Textbox.WrappedComponent.prototype, 'maskPromoCode')。 HOC上有一个WrappedComponent static 属性,所以可以得到原始组件class.

  3. 建议:如果使用 jest.spyOn(...),您正在测试实现细节,您应该测试组件行为。

例如

Textbox.jsx:

import React from 'react';
import { connect } from 'react-redux';

class Textbox extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: '131' };
  }

  onChange(e) {
    e.preventDefault();
    this.setState({ value: this.maskPromoCode(e.target.value) });
  }

  maskPromoCode(value) {
    return '***';
  }

  render() {
    return (
      <>
        <input value={this.state.value} onChange={(e) => this.onChange(e)} />
      </>
    );
  }
}
export default connect(null, null)(Textbox);

Textbox.test.jsx:

import Textbox from './Textbox';
import React from 'react';
import configureStore from 'redux-mock-store';
import { Provider } from 'react-redux';

describe('70795348', () => {
  it('invokes the maskPromoCode function with event value', () => {
    console.log(Textbox.WrappedComponent.prototype.maskPromoCode);
    const mockStore = configureStore();
    const store = mockStore();
    const wrapper = mount(
      <Provider store={store}>
        <Textbox name="redeem-promo" />
      </Provider>
    );
    expect(wrapper.find('input').instance().value).toBe('131');
    const event = { target: { value: 'event value' } };
    wrapper.find('input').simulate('change', event);
    expect(wrapper.find('input').instance().value).toBe('***');
  });
});

测试结果:

 PASS  Whosebug/70795348/Textbox.test.jsx
  70795348
    ✓ invokes the maskPromoCode function with event value (40 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.729 s, estimated 9 s