2017-06-26 34 views
10

単純なReactコンポーネントの簡単なテストを作成しようとしています。Jestを使用して、酵素でクリックをシミュレートするときに関数が呼び出されたことを確認します。 Jestのドキュメントによると、これを行うにはspyOnを使用できるはずです:spyOnJest 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() 
}) 
}) 

誰もが私が間違ってやっている洞察力を持っていますか?

答えて

5

ちょっとバディ私は遅く、ここで少しだが、知っているあなたは、ほぼどのようspyOn以外に何も変更せずに行われました。 スパイを使用するときは、コンポーネントプロトタイプを観察する必要があります。

スパイをクラスプロトタイプに添付し、インスタンスをレンダリング(浅いレンダリング)する順序は重要です。最初の行に

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

App.prototypeビットは、あなたが物事を動作させるために必要なものがあります。 javascript classには、new MyClass()でインスタンス化するか、MyClass.prototypeに入るまで、そのメソッドはありません。あなたの質問には、App.prototypeの方法myClickFnをスパイする必要があります。

これは、他の人がテストパスを行うために自分のアプリにプロップを渡そうとしていた人を助けてくれることを願っています。

編集: 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"); 
*/ 
+0

私はこのことに遭遇し、人は協力していないようです。私は渡すために小さなテストを取得しようとしているとそれはちょうど失敗します – Byrd

+0

@Byrdあなたが何を意味するか分かりません。冗談は働かない、 'spyOn'は動かない、あるいは何か違う?あなたの 'package.json'は、あなたがjestをどのように設定しているかについて正しく設定されていますか?あなたの声明に関する多くの質問。 – taystack

+0

誰もテストパスを作るために自分のアプリに小道具を渡すことを提案していません。私たちは、コンポーネントのカプセル化された動作をテストすることを目指しています。コンポーネント内で何かがクリックされた場合、それは検出可能な効果(プロップ関数の呼び出し、レンダリングの変更、またはコンポーネント状態の変更のいずれか)を持っていなければなりません - そうでなければ、最初にクリックハンドラを持つ点があります。私たちがテストしたくないことは、Reactが期待通りに動作することです。これはReactのテストスイートの仕事です。 –

9

あなたのテストコードでは、AppをspyOn関数に渡そうとしていますが、spyOnはクラスではなくオブジェクトでのみ動作します。一般に、ここでは2つのアプローチのうちの1つを使用する必要があります:

1)Clickハンドラが、小道具として渡された関数を呼び出しているところ。クリックハンドラは、例えば、コンポーネントにいくつかの状態を設定

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 { 

    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> 
    ); 
    } 
} 

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'); 
}) 
}) 
+1

クラスはオブジェクトです。 'spyOn'は' ClassName.prototype'で動作します – taystack

+0

クラスはオブジェクトではありません。古典的なオブジェクト指向では、オブジェクトの青写真であり、JavaScriptでは関数です。 'typeof(class A {})===" function "'クラスをインスタンス化するとき、クラスのプロトタイプに基づいてオブジェクトを作成します。クラスのプロトタイプはオブジェクトであり、私たちが望むならば、メソッドを偵察することができます。最終的には、あなたの答えに基づいて私のコメントごとに、それが呼び出されただけでなく、クリックハンドラの効果をテストしたいと考えています。 –

+0

javascriptでは、 'function'は' Object'から継承します。関数内で 'this'にアクセスする方法です。問題に戻って、質問は、呼び出された関数の効果をアサートする方法を尋ねなかったので、関数をアサートする方法を尋ねられました。いずれにしても、「」 – taystack

5

、コンポーネントの状態に関するアサーションを行うことができます。私は@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() 
}) 
}) 

ドキュメント: http://airbnb.io/enzyme/docs/api/ShallowWrapper/instance.html

+2

の小道具は必要ありません。シミュレートクリックが呼び出される前に、forceUpdateを呼び出してspy関数をインスタンスに添付してください。 instance.forceUpdate() –

+0

不思議です。上では同様のテストを行っていますが、アプリのレンダリング方法を '浅い'から '山'に変更することで修正しました。なぜこれが修正されたのか、なぜこのテストには 'マウント'が必要でないのか? – youngrrrr

+0

@youngrrrrおそらくあなたの機能はDOMに依存していますが、浅いのは製品ではありませんが、マウントは完全なDOMレンダリングです – 3stacks

関連する問題