I am working on a wrapper component for smoothly loading images in React. I use enzyme with mocha, chai and sinon to unit test my component. In the test here, I am trying to test that the:
component's state is updated when the image has loaded
the onLoad
instance method on the component was called
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');
I find that neither the update to the state is reflected by enzyme or the call count of the onLoad
spy is updated. This is the corresponding code for the test:
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>);
}}
To take a look at the full code for better context:
the source here
the test here
If you want mimic real-world user interactions, the React Testing Library is the way to go because you can do the same with fireEvent functions. Meanwhile, Enzyme is better suited to situations where you have to match the state of React or some other function with state.
The enzyme is a javascript testing utility for React that makes it easier to assert, manipulate and traverse the components.
Use the useEffect hook to listen for state changes in React. You can add the state variables you want to track to the hook's dependencies array and the logic in your useEffect hook will run every time the state variables change.
One can test this without relying on sinon
. By expecting that the onLoad
and onFire
event listeners are invoked,the tests check if the img
fires the load
and error
events.
Instead,simulate
img
's events using enzyme
and check that the appropriate state transition occurs:
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');
});
This also eliminates the need to mount
the component. The updated tests can be found here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With