2017-02-15 9 views
3

私はこれを把握することはできません。私はcreate-react-appを使用しています。テストランナーJestに組み込まれています。すべての同期コードでは本当にうまくいくようですが、約束を守るとうまく動作しないようです。テストJestと非同期で反応し、作成する - 反応 - アプリケーション

反応コンポーネントには、送信をシミュレートできるフォームがあります。

リアクションコンポーネントのコードスニペット。

//Top of the page 
import {auth} from '../../lib/API_V2' 
// ... // 

// Handle submit runs when the form is submitted 
handleSubmit = (event) => { 
    console.log('submit') 
    event.preventDefault() 
    this.setState(prevState => ({ 
    ...prevState, 
    loading: true 
    })) 
    console.log('stateSet') 
    auth(this.state.userName, this.state.password) 
    .then(results => { 
     // NEVER RUNS 
     console.log('then') 
     // stuff omitted 
     this.setState(prevState => ({ 
     ...prevState, 
     loading: false 
     })) 
     this.props.afterAuth() 
    }) 
    .catch(() => { 
    // also never runs 
    // omitted 
    this.setState(prevState => ({ 
     ...prevState, 
     loading: false 
    })) 
    this.props.afterAuth() 
    }) 
} 

テストコード

jest.mock('../../lib/API_V2') 
it.only(`should mock a login`,() => { 
    const myMock = jest.fn() 
    const authComp = mount(<AuthComponent afterAuth={myMock}/>) 

    authComp.find('.userName').simulate('change', {target: {value: 'userName'}}) 
    authComp.find('.password').simulate('change', {target: {value: 'password'}}) 
    expect(authComp.state().userName).toEqual('userName') 
    expect(authComp.state().password).toEqual('password') 
    authComp.find('[type="submit"]').get(0).click() 
    expect(myMock.mock.calls.length).toBe(1) // FAILS 
}) 

API libには、約束を返します。それを使用する代わりに私はそれの隣に__mocks__/API_V2.jsを持っています。このように見える

function auth (lastname, accountNumber) { 
    console.log('yay!?') 
    return new Promise((resolve) => { 
    resolve({ 
     accountNumber, 
     lastName: lastname 
    }) 
    }) 
}  

私の模擬テストコードは決して実行されていないようです。私が模擬機能をログに記録すると、function auth() {return mockConstructor.apply(this,arguments);}

私は指示https://facebook.github.io/jest/docs/tutorial-async.htmlに従ってみましたが、私の模擬方法が呼び出されていないようです。そしてどちらも実際の方法ではありません。代わりにauth()への私の呼び出しは未定義を返します。

誰もが考えている?

- 補足情報 -

src 
    Components 
    AuthComponent 
     AuthComponent.js 
     AuthComponent.test.js 
     index.js 
    Lib 
    API_V2 
     API_V2.js 
     index.js 
     __mocks__ 
     API_V2.js 
+0

私はそれを手動でモックの代わりに使用して終了__mocks__ディレクトリ。 jest.mock( '../../ lib/API_V2、()=> {認証:機能...}) – TheMcMurder

答えて

3

私はあなたがこの問題に関連するバグを打つていると思う:https://github.com/facebook/jest/issues/2070

あなたが実際にAPI_V2/index.jsと呼ばれるファイルをインポートしようとしているので、あなたが必要モックにindex.js。しかし、それはあなたが模擬しようとするのindex.jsファイルの有効なモックになるので、本当に悪い時間を過ごすつもりです。

現時点でこれを行うための最善の方法は、たとえ、依存性注入を使用して、モックから新しい約束で{ auth }

+0

私の経験では、警告で私を悩ませましたが、同じ名前のモックは「スワップ」しませんでした。 –

+0

>ただし、あなたがしようとするすべてのindex.jsファイルに対して有効なモックになるので、本当に悪い時間を過ごすことになります。 これは正しいとは思わない。彼が 'Lib/API_V2/__ mocks __/index.js'に入れて' Lib/API_V2/index.js'をモックするだけの場合 – kentcdodds

+0

残念ながら、参照されているバグを見てください。うざい。たぶんファイルの名前を変更するのでしょうか? ;-) – kentcdodds

2

を使用する必要があるものは何でもモックを渡すためにあなたのコードの一部を書き換えることですすぐに解決すると、この解決は同期して行われません。プロミスコールバックは常にキューに入れられたマイクロタスクとして実行されるため、テストでクリックをシミュレートすると、モック内のPromiseコールバックはまだ実行されていません(したがってmyMockもまだ呼び出されていません)。これがあなたの期待が失敗する理由です。

この問題を回避するには、setTimeoutを使用します(ややハッキー)。 setTimeoutはタスクをエンキューし、タスクは常にマイクロタスクの後に実行されます。 冗談はitコールバックからの約束を返す介して、非同期テストをサポートしていますので、あなたが書いたかもしれません:

jest.mock('../../lib/API_V2') 
it.only(`should mock a login`,() => new Promise(resolve => { 
    const myMock = jest.fn() 
    const authComp = mount(<AuthComponent afterAuth={myMock}/>) 

    authComp.find('.userName').simulate('change', {target: {value: 'userName'}}) 
    authComp.find('.password').simulate('change', {target: {value: 'password'}}) 
    expect(authComp.state().userName).toEqual('userName') 
    expect(authComp.state().password).toEqual('password') 
    authComp.find('[type="submit"]').get(0).click() 
    setTimeout(() => { 
    expect(myMock.mock.calls.length).toBe(1) 
    resolve() // Tell jest this test is done running 
    }, 0); 
})) 

タスクおよびマイクロタスクは、ここでどのように動作するかの良い説明があります:https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

関連する問題