I\'ve created a React component that loads an image and determines if the image loaded successfully or not.
import React from \'react\';
import PropTypes fro
You could mock document.createElement
:
it('should call any passed in onError after an image load error', () => {
const img = {}
global.document.createElement = (type) => type === 'img' ? img : null
const onError = jest.fn();
mount(<Image {...props} src="crap.junk"} onError={onError} />);
img.onload()
expect(onError).toHaveBeenCalled();
});
Since behind the scenes, document.createElement('img')
is equivalent to new Image()
, we can mock part of the jsdom (used by Jest) implementation of Image
to achieve what you're going for.
(For simplicity's sake, I've renamed your component to ImageComponent
)
describe('Callbacks', () => {
const LOAD_FAILURE_SRC = 'LOAD_FAILURE_SRC';
const LOAD_SUCCESS_SRC = 'LOAD_SUCCESS_SRC';
beforeAll(() => {
// Mocking Image.prototype.src to call the onload or onerror
// callbacks depending on the src passed to it
Object.defineProperty(global.Image.prototype, 'src', {
// Define the property setter
set(src) {
if (src === LOAD_FAILURE_SRC) {
// Call with setTimeout to simulate async loading
setTimeout(() => this.onerror(new Error('mocked error')));
} else if (src === LOAD_SUCCESS_SRC) {
setTimeout(() => this.onload());
}
},
});
});
it('Calls onError when passed bad src', done => {
const onError = ev => {
expect(ev).toBeInstanceOf(Error);
// Indicate to Jest that the test has finished
done();
};
mount(<ImageComponent onError={onError} src={LOAD_FAILURE_SRC} />);
});
});
The reason onerror
/onload
is never called as it would be in a browser is explained in this jsdom issue. An alternate fix that would affect all your tests is offered up in the same issue thread.