Reactで画像をスムーズにロードするためのラッパーコンポーネントに取り組んでいます。私はコンポーネントを単体テストするために酵素をモカ、チャイ、シノンと共に使用しています。ここでのテストでは、私はそれをテストしようとしています:
コンポーネントの状態は、画像が読み込まれたときに更新されます
コンポーネントのonLoad
インスタンスメソッドが呼び出されました
const wrapper = shallow(); const onLoad = wrapper.find( 'img')。props()。onLoad; const onLoadSpy = sinon。 spy(onLoad); wrapper.update(); const status = wrapper.state()。status; expect(onLoadSpy).to.have.been.called; expect(status) to.equal( 'LOADED');
状態の更新が酵素によって反映されることも、onLoad
スパイの呼び出しカウントが更新されることもわかりません。これはテストに対応するコードです:
export default class Image extends Component {
constructor(props) {
super(props);
if (props.src != null && typeof props.src === 'string') {
this.state = {
status: LOADING,
};
} else {
this.state = {
status: PENDING,
};
}
this.onLoad = this.onLoad.bind(this);
}
onLoad() {
this.setState({
status: LOADED,
});
}
render() {
//lots of code above the part we care about
const defaultImageStyle = style({
opacity: 0,
transisition: 'opacity 150ms ease',
});
const loadedImageStyle = style({
opacity: 1,
});
let imageStyle = defaultImageStyle;
if (this.state.status === LOADED) {
imageStyle = merge(defaultImageStyle, loadedImageStyle);
} else {
imageStyle = defaultImageStyle;
}
let image;
if (alt != null) {
image = (<img
className={imageStyle}
src={src}
width={width}
height={height}
alt={alt}
onLoad={this.onLoad}
/>);
} else {
image = (<img
className={imageStyle}
src={src}
width={width}
height={height}
role="presentation"
onLoad={this.onLoad}
/>);
}
let statusIndicator = null;
if (this.state.status === LOADING) {
statusIndicator = (<div className={loadingStyle}></div>);
}
return (<div className={wrapperStyle}>
{statusIndicator}
{image}
</div>);
}}
より良いコンテキストの完全なコードを見てみましょう:
sinon
に依存せずにこれをテストできます。 onLoad
およびonFire
イベントリスナーが呼び出されることを想定して、テストはimg
がload
およびerror
イベントを起動するかどうかを確認します。
代わりに、simulate
img
を使用してenzyme
のイベントを実行し、適切な状態遷移が発生することを確認します。
it('has a state of LOADED if a good src prop is supplied', () => {
const wrapper = shallow(<Image
src="anyString.jpg"
width={300}
height={300}
/>);
const img = wrapper.find('img');
img.simulate('load');
const status = wrapper.state().status;
expect(status).to.equal('LOADED');
});
これにより、コンポーネントをmount
する必要もなくなります。更新されたテストは here にあります。
このアプローチで私が目にする主な問題は、状態が内部的なものであり、コンポーネントの外部で知られるべきものではないということです。これで、状態情報(この場合は「ステータス」)をテストにリークしています。
これを行うと、「ブラックボックステスト」を実行しないことになります。これは、最も価値のあるタイプのテストです。コンポーネントの実装の詳細を漏らしています。言い換えれば、「カプセル化」は非常に考慮されるべきです。
これをテストするより良い方法があるかもしれません。たとえば、プレゼンテーションコンポーネントもエクスポートできます。これは、テストする必要がある状態の部分を小道具として受け取ります。または、酵素 find メソッドでステータスが「LOADED」の場合にレンダリングされる要素を探します。