Jest spyOn函数调用

时间:2017-06-26 22:10:30

标签: javascript reactjs testing jestjs enzyme

我试图为一个简单的React组件编写一个简单的测试,我想用Jest来确认当我用酶模拟点击时调用了一个函数。根据Jest文档,我应该可以使用spyOn来执行此操作:spyOn

然而,当我尝试这个时,我不断得到TypeError: Cannot read property '_isMockFunction' of undefined,这意味着我的间谍未定义。我的代码如下所示:

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {

  myClickFunc = () => {
      console.log('clickity clickcty')
  }
  render() {
    return (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h2>Welcome to React</h2>
        </div>
        <p className="App-intro" onClick={this.myClickFunc}>
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
      </div>
    );
  }
}

export default App;

并在我的测试文件中:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { shallow, mount, render } from 'enzyme'

describe('my sweet test', () => {
 it('clicks it', () => {
    const spy = jest.spyOn(App, 'myClickFunc')
    const app = shallow(<App />)
    const p = app.find('.App-intro')
    p.simulate('click')
    expect(spy).toHaveBeenCalled()
 })
})

任何人都能洞察我做错了什么?

3 个答案:

答案 0 :(得分:32)

嘿伙计我知道我在这里有点迟了,但除了你spyOn之外,你几乎没有任何改变。 使用间谍时,您有两种选择:spyOn App.prototype或组件component.instance()

const spy = jest.spyOn(Class.prototype,“method”)

将间谍附加到类原型上并渲染(浅渲染)实例的顺序非常重要。

const spy = jest.spyOn(App.prototype, "myClickFn");
const instance = shallow(<App />);

第一行的App.prototype位是您需要的东西。在您使用class对其进行实例化之前,javascript new MyClass()没有任何方法,或者您可以使用MyClass.prototype。对于您的特定问题,您只需要监视App.prototype方法myClickFn

jest.spyOn(component.instance(),“method”)

const component = shallow(<App />);
const spy = jest.spyOn(component.instance(), "myClickFn");

此方法需要shallow/render/mount的{​​{1}}个实例可用。基本上React.Component正在寻找劫持并推入spyOn的东西。它可能是:

普通jest.fn()

object

A const obj = {a: x => (true)}; const spy = jest.spyOn(obj, "a");

class

class Foo { bar() {} } const nope = jest.spyOn(Foo, "bar"); // THROWS ERROR. Foo has no "bar" method. // Only an instance of Foo has "bar". const fooSpy = jest.spyOn(Foo.prototype, "bar"); // Any call to "bar" will trigger this spy; prototype or instance const fooInstance = new Foo(); const fooInstanceSpy = jest.spyOn(fooInstance, "bar"); // Any call fooInstance makes to "bar" will trigger this spy.

React.Component instance

const component = shallow(<App />); /* component.instance() -> {myClickFn: f(), render: f(), ...etc} */ const spy = jest.spyOn(component.instance(), "myClickFn");

React.Component.prototype

我已经使用并看过这两种方法。当我有/* App.prototype -> {myClickFn: f(), render: f(), ...etc} */ const spy = jest.spyOn(App.prototype, "myClickFn"); // Any call to "myClickFn" from any instance of App will trigger this spy. beforeEach()块时,我可能会采用第一种方法。如果我只需要一个快速的间谍,我将使用第二个。请记住附加间谍的顺序。

编辑: 如果您想检查beforeAll()的副作用,可以在单独的测试中调用它。

myClickFn

答案 1 :(得分:14)

你几乎就在那里。虽然我同意@Alex Young关于为此使用道具的答案,但在尝试窥探该方法之前,您只需要引用 SELECT drawid,contact,dnd,mem.name, count(*) as numPayments,NULL numPaidPayments ,NULL PAID_CONTACT,NULL NAME_PAID FROM mem LEFT JOIN payment ON (mem.drawid = payment.draw) GROUP BY drawid HAVING numPayments < 4 UNION SELECT NULL drawid,NULL contact, NULL dnd, NULL name,NULL numPayments,COUNT(*) as numPaidPayments ,contact PAID_CONTACT,mem.name NAME_PAID FROM mem INNER JOIN payment ON (mem.drawid = payment.draw) GROUP BY drawid HAVING numPaidPayments >= 4

instance

文档: http://airbnb.io/enzyme/docs/api/ShallowWrapper/instance.html

答案 2 :(得分:11)

在您的测试代码中,您尝试将App传递给spyOn函数,但spyOn只能处理对象,而不能处理类。通常,您需要使用以下两种方法之一:

1)点击处理程序调用作为prop传递的函数,例如

class App extends Component {

  myClickFunc = () => {
      console.log('clickity clickcty');
      this.props.someCallback();
  }
  render() {
    return (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h2>Welcome to React</h2>
        </div>
        <p className="App-intro" onClick={this.myClickFunc}>
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
      </div>
    );
  }
}

您现在可以将间谍函数作为prop传递给组件,并断言它被调用:

describe('my sweet test', () => {
 it('clicks it', () => {
    const spy = jest.fn();
    const app = shallow(<App someCallback={spy} />)
    const p = app.find('.App-intro')
    p.simulate('click')
    expect(spy).toHaveBeenCalled()
 })
})

2)点击处理程序在组件上设置某些状态,例如

class App extends Component {
  state = {
      aProperty: 'first'
  }

  myClickFunc = () => {
      console.log('clickity clickcty');
      this.setState({
          aProperty: 'second'
      });
  }
  render() {
    return (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h2>Welcome to React</h2>
        </div>
        <p className="App-intro" onClick={this.myClickFunc}>
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
      </div>
    );
  }
}

您现在可以对组件的状态进行断言,即

describe('my sweet test', () => {
 it('clicks it', () => {
    const app = shallow(<App />)
    const p = app.find('.App-intro')
    p.simulate('click')
    expect(app.state('aProperty')).toEqual('second');
 })
})