使用动态导入测试React组件(酶/摩卡)
问题描述:
我正在尝试使用摩卡和酶来测试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
});
});
答
即使世界一对夫妇的方式来解决这个问题,简单的廉价和肮脏的方式是推迟的预期对在合理的时间量。这将打开测试到异步测试,所以你需要使用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方法,所以可能比平时更麻烦。试试简单的版本,看看它是如何发展的。
答
我能够完成这个 - 东西。
我将依赖动态导入的测试切换为异步。然后我创建了一个呈现组件的函数,并返回一个承诺,动态导入我试图导入组件的模块。
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毫秒更不容易。
我现在要解决这个问题了,因为社区可能提供更好的解决方案。
我不确定你的意思是“stubbing a webpack method”。你是指动态导入?如果是这样,这是ES6,而不是特定于webpack(尽管webpack在分块时处理它的方式不同)。此外,导入是一个特殊的关键字,而不是一个功能,所以我不认为你可以将它存根。 – anthonator
对于动态导入的ES6建议,仅在我知道的webpack/babel/systemJS等工具中实现,如果您使用的是在裸露的ES6中使用的东西,则表示道歉。 这正是我的意思,如果它只是从一个工具,而不是一个实际的全局函数或一个真正的polyfill,你将无法嘲笑它 – alechill