Javascript 调用 Jest spyOn 函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44769404/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Jest spyOn function called
提问by Max Millington
I'm trying to write a simple test for a simple React component, and I want to use Jest to confirm that a function has been called when I simulate a click with enzyme. According to the Jest docs, I should be able to use spyOnto do this: spyOn.
我正在尝试为一个简单的 React 组件编写一个简单的测试,我想使用 Jest 来确认当我用酶模拟点击时已经调用了一个函数。根据 Jest 文档,我应该可以使用spyOn:spyOn。
However, when I try this, I keep getting TypeError: Cannot read property '_isMockFunction' of undefinedwhich I take to mean that my spy is undefined. My code looks like this:
然而,当我尝试这个时,我不断得到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;
and in my test file:
在我的测试文件中:
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()
})
})
Anyone have an insight into what I'm doing wrong?
任何人都知道我做错了什么?
回答by taystack
Hey buddy I know I'm a bit late here, but you were almost done without any changes besides how you spyOn.
When you use the spy, you have two options: spyOnthe App.prototype, or component component.instance().
嘿,伙计,我知道我在这里有点晚了,但除了你的方式之外,你几乎没有任何变化spyOn。当您使用的间谍,你有两个选择:spyOn在App.prototype或组件component.instance()。
const spy = jest.spyOn(Class.prototype, "method")
const spy = jest.spyOn(Class.prototype, "method")
The order of attaching the spy on the class prototype and rendering (shallow rendering) your instance is important.
在类原型上附加间谍和渲染(浅渲染)实例的顺序很重要。
const spy = jest.spyOn(App.prototype, "myClickFn");
const instance = shallow(<App />);
The App.prototypebit on the first line there are what you needed to make things work. A javascript classdoesn't have any of its methods until you instantiate it with new MyClass(), or you dip into the MyClass.prototype. For your particular question, you just needed to spy on the App.prototypemethod myClickFn.
在App.prototype第一行位有你需要的东西,使事情的工作。一个 javascriptclass没有任何方法,直到你用 实例化它new MyClass(),或者你浸入MyClass.prototype. 对于您的特定问题,您只需要监视App.prototype方法myClickFn。
jest.spyOn(component.instance(), "method")
jest.spyOn(component.instance(), "方法")
const component = shallow(<App />);
const spy = jest.spyOn(component.instance(), "myClickFn");
This method requires a shallow/render/mountinstance of a React.Componentto be available. Essentially spyOnis just looking for something to hiHyman and shove into a jest.fn(). It could be:
此方法需要 a 的shallow/render/mount实例React.Component可用。本质spyOn上只是在寻找可以劫持并推入jest.fn(). 它可能是:
A plain object:
一个平原object:
const obj = {a: x => (true)};
const spy = jest.spyOn(obj, "a");
A class:
答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.
Or a React.Component instance:
或者一个React.Component instance:
const component = shallow(<App />);
/*
component.instance()
-> {myClickFn: f(), render: f(), ...etc}
*/
const spy = jest.spyOn(component.instance(), "myClickFn");
Or a React.Component.prototype:
或者一个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.
I've used and seen both methods. When I have a beforeEach()or beforeAll()block, I might go with the first approach. If I just need a quick spy, I'll use the second. Just mind the order of attaching the spy.
我已经使用并看到了这两种方法。当我有一个beforeEach()orbeforeAll()块时,我可能会采用第一种方法。如果我只需要一个快速间谍,我会使用第二个。只需注意附加间谍的顺序即可。
EDIT:
If you want to check the side effects of your myClickFnyou can just invoke it in a separate test.
编辑:如果你想检查你的副作用,myClickFn你可以在单独的测试中调用它。
const app = shallow(<App />);
app.instance().myClickFn()
/*
Now assert your function does what it is supposed to do...
eg.
expect(app.state("foo")).toEqual("bar");
*/
回答by CharlieBrown
You're almost there. Although I agree with @Alex Young answer about using props for that, you simply need a reference to the instancebefore trying to spy on the method.
您快到了。尽管我同意 @Alex Young 关于为此使用道具的回答,但instance在尝试监视该方法之前,您只需要参考。
describe('my sweet test', () => {
it('clicks it', () => {
const app = shallow(<App />)
const instance = app.instance()
const spy = jest.spyOn(instance, 'myClickFunc')
instance.forceUpdate();
const p = app.find('.App-intro')
p.simulate('click')
expect(spy).toHaveBeenCalled()
})
})
Docs: http://airbnb.io/enzyme/docs/api/ShallowWrapper/instance.html
文档:http: //airbnb.io/enzyme/docs/api/ShallowWrapper/instance.html
回答by Alex Young
In your test code your are trying to pass Appto the spyOn function, but spyOn will only work with objects, not classes. Generally you need to use one of two approaches here:
在您的测试代码中,您试图传递App给 spyOn 函数,但 spyOn 仅适用于对象,而不适用于类。通常,您需要在此处使用以下两种方法之一:
1) Where the click handler calls a function passed as a prop, e.g.
1)点击处理程序调用作为道具传递的函数,例如
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>
);
}
}
You can now pass in a spy function as a prop to the component, and assert that it is called:
您现在可以将 spy 函数作为 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) Where the click handler sets some state on the component, e.g.
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>
);
}
}
You can now make assertions about the state of the component, i.e.
您现在可以对组件的状态进行断言,即
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');
})
})

