2016-12-22 19 views
4

私のテストでは、子コンポーネントを追加するイベントをトリガーした後で、自分のコンポーネントの1つがライフサイクルメソッドを終了するまでメインスレッドをブロックしたいと考えています(componentDidUpdate())。それ自体に。どうすればいいですか?このようなリアクションコンポーネントの更新が完了するまで待つ

何か:

describe('my <Component />',() => { 
    it('should do what I want when its button is clicked twice',() => { 
    const wrapper = mount(<Component />); 
    const button = wrapper.find('button'); 

    // This next line has some side effects that cause <Component /> to add 
    // some children components to itself... 
    button.simulate('click', mockEvent); 

    // ... so I want to wait for those children to completely go through 
    // their lifecycle methods ... 
    wrapper.instance().askReactToBlockUntilTheComponentIsFinishedUpdating(); 

    // ... so that I can be sure React is in the state I want it to be in 
    // when I further manipulate the <Component /> 
    button.simulate('click', mockEvent); 

    expect(whatIWant()).to.be.true; 
    }); 
}); 

は(私は、今、私はこの警告を得るためにこれをしたい:

Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. 

私は私のテストが引き起こすので、私はそれを取得しています信じているし、私のコンポーネントが内部の状態をReactの内部マルチスレッドマジックよりも速く変えることができるので、今度はbutton.simulate('click')を2回実行するまでにReactが新しい子コンポーネントをインスタンス化しましたが、まだマウントを完了していません。反応を完了させるための更新私のコンポーネントとその子をすると、その問題を解決するための最良の方法です)

+1

クリックハンドラは何をしますか?すべての状態の変更は、特にタイマー/非同期のものがある場合を除き、同期している必要があります。 – Jacob

+1

DOMアップデートは、あなたが変なことをしているか、Reactのエキゾチックな風味を使っていない限り、同期しています。あなたの 'setState'警告が、あなたのコンポーネント自体がマウント前に' setState'を実行していることが原因であると私は驚いていません。 – Jacob

+1

@Jacob私はサードパーティのライブラリ[React Widgets](https://jquense.github.io/react-widgets/docs/)を使用しています。私の ''はその子の1つとしてReact Widgets 'DateTimePicker'を持っていて、警告は' DateTimePicker'の中から出ているようです。残念ながら、私は自分のイベントの原因を変えることができると確信しています。コンポーネントを調べて、それが間違っていないことを確認することは簡単にできません。 – Kevin

答えて

1

setImmediate()ブロックであなたのexpect()ブロックをラップしてみてください。

describe('my <Component />',() => { 
    it('should do what I want when its button is clicked twice', (done) => { 
    const wrapper = mount(<Component />); 
    const button = wrapper.find('button'); 

    button.simulate('click', mockEvent); 
    button.simulate('click', mockEvent); 

    setImmediate(() => { 
     expect(whatIWant()).to.be.true; 
     done(); 
    }); 
    }); 
}); 

ここで何が起こっているのだ:非同期、ノードおよびほとんどのブラウザに対応するために舞台裏でイベントキューを持っている。プロミスやIOイベントのようなものが非同期に実行される必要があるときはいつでも、JS環境はそれをキューの最後に追加します。次に、同期コードが実行を終了するたびに、環境はキューをチェックし、キューの先頭にあるものを取り出して実行します。

setImmediate()は、キューの後ろに関数を追加します。現在キューにあるすべてのものが実行されたら、setImmediate()に渡された関数内のものが実行されます。したがって、どのようなReactが非同期で行っていても、setImmediate()の中にexpect()をラップすると、バックグラウンドで実行される非同期作業でReactが終了するまでテストが待たれます。ここで

は、より多くの情報についてsetImmediate()を持つ偉大な質問です:setImmediate vs. nextTick

ここノードでsetImmediate()のドキュメントです:https://nodejs.org/api/timers.html#timers_setimmediate_callback_args

+0

私はいくつかのテストでこの 'setImmediate()'トリックを試みましたが、私の質問で説明した特定の状況ではありませんでした。だからドラゴンがいて、この解決法はうまくいかないかもしれません。 – Kevin

+0

'setImmediate()'の中でアサーション( 'expect')が失敗すると、テストは' Fail'とマークするのではなくエラーで終了し、続行します。どんな仕事? – vleong

+0

@VLeong 'it'ブロックで' done'関数を使ってテストを非同期テストとして書いていますか? https://mochajs.org/#asynchronous-codeを参照してください。 – Kevin

関連する問題