2017-05-26 9 views
1

ダイナミックインポートを使用してモジュールをロードするMochaとEnzymeを使用してReactコンポーネントをテストしようとしています。ダイナミックインポート(React component with dynamic import)(Enzyme/Mocha)

動的インポートに依存するロジックをテストしようとすると、不正な結果が得られます。問題は、テストが終了する前に非同期関数が終了しないため、正確な結果を得ることができないということです。

このシナリオをどのように処理できますか?

コンポーネント

import classNames from 'classnames'; 
import PropTypes from 'prop-types'; 
import React from 'react'; 

// styles 

import styles from './PasswordStrengthIndicator.scss'; 

class PasswordStrengthIndicator extends React.Component { 
    static defaultProps = { 
    password: undefined, 
    onPasswordChange: undefined, 
    } 

    static propTypes = { 
    password: PropTypes.string, 
    onPasswordChange: PropTypes.func, 
    } 

    constructor() { 
    super(); 

    this.state = {}; 
    } 

    componentWillMount() { 
    this.handlePasswordChange(); 
    } 

    componentWillReceiveProps(nextProps) { 
    const password  = this.props.password; 
    const nextPassword = nextProps.password; 

    if (password !== nextPassword) { 
     this.handlePasswordChange(); 
    } 
    } 

    render() { 
    const strength = this.state.strength || {}; 
    const score = strength.score; 

    return (
     <div className={ styles.passwordStrength }> 
     <div className={ classNames(styles.score, styles[`score-${score}`]) } /> 
     <div className={ styles.separator25 } /> 
     <div className={ styles.separator50 } /> 
     <div className={ styles.separator75 } /> 
     </div> 
    ); 
    } 

    // private 

    async determineStrength() { 
    const { password } = this.props; 
    const zxcvbn = await import('zxcvbn'); 

    let strength = {}; 

    if (password) strength = zxcvbn(password); 

    return strength; 
    } 

    async handlePasswordChange() { 
    const { onPasswordChange } = this.props; 
    const strength = await this.determineStrength(); 

    this.setState({ strength }); 

    if (onPasswordChange) onPasswordChange(strength); 
    } 
} 

export default PasswordStrengthIndicator; 

テスト

describe('when `password` is bad',() => { 
    beforeEach(() => { 
    props.password = 'badpassword'; 
    }); 

    it.only('should display a score of 1',() => { 
    const score = indicator().find(`.${styles.score}`); 

    expect(score.props().className).to.include(styles.score1); // should pass 
    }); 
}); 

答えて

0

はシンプル安くて汚い方法は妥当な時間の期待を遅らせることで、これを解決するにはいくつかの方法をTheresの。あなたは、テストが完了したモカを伝えるために、あなたのアサーション後doneメソッドを使用する必要がありますので、これは、非同期テストにテストを回す...

it('should display a score of 1', (done) => { 
    setTimeout(() => { 
    const score = indicator().find(`.${styles.score}`); 

    expect(score.props().className).to.include(styles.score1); 
    done() // informs Mocha that the async test should be complete, otherwise will timeout waiting 
    }, 1000) // mocha default timeout is 2000ms, so can increase this if necessary 
}); 

他のより複雑な方法は、呼び出しをスタブすることですimportをSinonのようなものに置き換え、動的にロードされたコンポーネントで解決された約束を手動で返します。

私はウェブパックの方法をスタブしようとしていないことを認めなければなりません。シンプルなバージョンを試して、それがどうなるかを見てみましょう。

+0

「ウェブパックの方法をスタブする」とはどういう意味ですか。あなたは動的なインポートを指していますか?もしそうなら、それはES6でwebpackに特有ではありません(ただし、chunkでwebpackはそれを別々に扱います)。また、インポートは特殊なキーワードであり、関数ではないので、私はあなたがそれをスタブできるとは思わない。 – anthonator

+0

動的なインポートのためのES6の提案は、私がwebpack/babel/systemJSのようなツールで知っている限り実装されています。あなたが裸のES6で本当に何かを使っているなら、謝罪します。 実際のグローバル関数または実際のポリフィルではなく、単にツールからのものであれば、それを擬似することはできません – alechill

0

これは、の何かでこれを達成できました。

ダイナミックインポートに依存するテストを非同期に切り替えました。次に、コンポーネントをレンダリングする関数を作成し、コンポーネントでインポートしようとしているモジュールを動的にインポートするという約束を返します。

const render =() => { 
    indicator = shallow(
    <PasswordStrengthIndicator { ...props } />, 
); 

    return (
    Promise.resolve() 
     .then(() => import('zxcvbn')) 
); 
}; 

私は、これはimport('zxcvbn')は、両方の場所にインポートする時の同様の十分な量がかかりますので、ただ待っているのと同じ概念に頼っていると信じています。それがスタブにしたから私を防止し、私はより良いサポートのスタブに私のコンポーネントの実装を変更する必要はありませんでしたので、これが出て働くことになった

describe('when `password` is defined',() => { 
    describe('and password is bad',() => { 
    beforeEach(() => { 
     props.password = 'badpassword'; 
    }); 

    it('should display a score of 1', (done) => { 
     render() 
     .then(() => { 
      const score = indicator.find(`.${styles.score}`); 

      expect(score.props().className).to.include(styles.score1); 

      done(); 
     }); 
    }); 
    }); 
}); 

は、ここに私のテストコードです。それはまた、x msを待つことよりも恣意的ではない。

ここでは、コミュニティが提供できるソリューションがおそらく存在するため、この質問を開いたままにしておきます。