2017-01-17 8 views
5

ReactコンポーネントでFileReaderを使用して、ユーザーが選択したファイルの内容を<input type="file"/>要素からインポートできるかどうかをテストします。私の下のコードは、壊れたテストの作業コンポーネントを示しています。Jest/Enzymeを使用してReactでファイルタイプ入力の変更ハンドラをテストするにはどうすればよいですか?

私のテストでは、ブロブもFileReaderで「読み込み」できるため、ファイルの代わりにブロブを使用しようとしています。それは有効なアプローチですか?また、問題の一部がreader.onloadが非同期であり、私のテストではこれを考慮する必要があると思われます。どこか約束が必要ですか?あるいは、おそらくFileReaderjest.fn()を使用して模擬する必要がありますか?

標準的なリアクションスタックを使用するのが本当に好きです。特にJestとEnzymeを使い、ジャスミンやシノンなどは使用しないでください。ではできませんが、Jest/Enzymeで行うことができますが、とは別の方法で行うこともありますまた助けてください。

MyComponent.js:

import React from 'react'; 
class MyComponent extends React.Component { 
    constructor(props) { 
     super(props); 
     this.state = {fileContents: ''}; 
     this.changeHandler = this.changeHandler.bind(this); 
    } 
    changeHandler(evt) { 
     const reader = new FileReader(); 
     reader.onload =() => { 
      this.setState({fileContents: reader.result}); 
      console.log('file contents:', this.state.fileContents); 
     }; 
     reader.readAsText(evt.target.files[0]); 
    } 
    render() { 
     return <input type="file" onChange={this.changeHandler}/>; 
    } 
} 
export default MyComponent; 

MyComponent.test.js:

import React from 'react'; import {shallow} from 'enzyme'; import MyComponent from './MyComponent'; 
it('should test handler',() => { 
    const blob = new Blob(['foo'], {type : 'text/plain'}); 
    shallow(<MyComponent/>).find('input') 
     .simulate('change', { target: { files: [ blob ] } }); 
    expect(this.state('fileContents')).toBe('foo'); 
}); 
+0

[このディスカッション](https://github.com/airbnb/enzyme/issues/426)は、 'addEventListener'を使ってReactのイベント処理戦略をバイパスし、実際に酵素などではサポートされていないことを示唆しているようです。 –

+0

最初のコメントで 'addEventListener'を述べた理由は、' addEventListener'が 'onload'よりもテスト可能であると他のサイトが示唆していたからです。 (リンク?)私が正しく理解していれば、[私の最初のコメントに記載された議論](https://github.com/airbnb/enzyme/issues/426)は、私がまだ仕事をしていないことをテストするためのいくつかの戦略を示唆しているそのような可能な解決策は、React /酵素の通常の使用を超えていると述べている。しかし、少なくとも一つの人が 'addEventListener'を使ったコンポーネントに' mousemove'イベントをテストするのに役立つように見えましたが、多くの詳細は与えられませんでした。 –

答えて

9

これは、使用して、コードの異なる部分のすべてにアクセスする方法をショーに答えます冗談。しかし、必ずしもこのようにこれらの部分すべてをテストする必要はありません。

コード被試験は、本質的に、私はonload = ...ためaddEventListener('load', ...を置換していることを除いて、問題のと同じであり、Iはconsole.log行削除しました:

MyComponent.js

import React from 'react'; 
class MyComponent extends React.Component { 
    constructor(props) { 
     super(props); 
     this.state = {fileContents: ''}; 
     this.changeHandler = this.changeHandler.bind(this); 
    } 
    changeHandler(evt) { 
     const reader = new FileReader(); 
     reader.addEventListener('load',() => { 
      this.setState({fileContents: reader.result}); 
     }); 
     reader.readAsText(evt.target.files[0]); 
    } 
    render() { 
     return <input type="file" onChange={this.changeHandler}/>; 
    } 
} 
export default MyComponent; 

私は、テスト中のコード(コメントに記されている、下記でさらに詳しく説明します)のすべてについて、次のようにすべてをテストすることができたと信じています:

MyComponent.test.js

import React from 'react'; 
import {mount} from 'enzyme'; 
import MyComponent from './temp01'; 

it('should test handler',() => { 
    const componentWrapper = mount(<MyComponent/>); 
    const component   = componentWrapper.get(0); 
    // should the line above use `componentWrapper.instance()` instead? 
    const fileContents  = 'file contents'; 
    const expectedFinalState = {fileContents: fileContents}; 
    const file    = new Blob([fileContents], {type : 'text/plain'}); 
    const readAsText   = jest.fn(); 
    const addEventListener = jest.fn((_, evtHandler) => { evtHandler(); }); 
    const dummyFileReader = {addEventListener, readAsText, result: fileContents}; 
    window.FileReader  = jest.fn(() => dummyFileReader); 

    spyOn(component, 'setState').and.callThrough(); 
    // spyOn(component, 'changeHandler').and.callThrough(); // not yet working 

    componentWrapper.find('input').simulate('change', {target: {files: [file]}}); 

    expect(FileReader  ).toHaveBeenCalled (       ); 
    expect(addEventListener ).toHaveBeenCalledWith('load', jasmine.any(Function)); 
    expect(readAsText  ).toHaveBeenCalledWith(file      ); 
    expect(component.setState).toHaveBeenCalledWith(expectedFinalState   ); 
    expect(component.state ).toEqual    (expectedFinalState   ); 
    // expect(component.changeHandler).toHaveBeenCalled(); // not yet working 
}); 

私は明示的にまだテストしていない一つのことはchangeHandlerが呼び出されたかどうかではありません。これは簡単だと思われるが、何らかの理由でそれはまだ私を逃している。明らかにと呼ばれていますが、内にはが呼び出されていますが、jest.fn()またはジャスミンのspyOnのいずれかを使用して呼び出されたかどうかはまだ確認できません。私はthis other questionにこの残りの問題に対処しようと依頼しました。

関連する問題