2017-05-26 235 views
1

我正在嘗試使用摩卡和酶來測試React組件,該組件使用動態導入來加載模塊。使用動態導入測試React組件(酶/摩卡)

當我嘗試測試依賴動態導入的邏輯時,我得到不正確的結果。問題是異步函數在測試完成之前沒有完成,所以我永遠無法得到準確的結果。

我該如何處理這種情況?

組件

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

即使世界一對夫婦的方式來解決這個問題,簡單的廉價和骯髒的方式是推遲的預期對在合理的時間量。這將打開測試到異步測試,所以你需要使用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之類的東西手動返回已解決的承諾與動態加載組件。

必須承認,我還沒有嘗試過樁webpack方法,所以可能比平時更麻煩。試試簡單的版本,看看它是如何發展的。

+0

我不確定你的意思是「stubbing a webpack method」。你是指動態導入?如果是這樣,這是ES6,而不是特定於webpack(儘管webpack在分塊時處理它的方式不同)。此外,導入是一個特殊的關鍵字,而不是一個功能,所以我不認爲你可以將它存根。 – anthonator

+0

對於動態導入的ES6建議,僅在我知道的webpack/babel/systemJS等工具中實現,如果您使用的是在裸露的ES6中使用的東西,則表示道歉。 這正是我的意思,如果它只是從一個工具,而不是一個實際的全局函數或一個真正的polyfill,你將無法嘲笑它 – 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毫秒更不容易。

我現在要解決這個問題了,因爲社區可能提供更好的解決方案。