I'm trying to test an input type=file component, using the react testing-library.
The component is a standard <input> element, with the following function to handle an image submission:
export default function ImageUpload(props) {
const { image, setImage } = props;
const handleImageChange = e => {
e.preventDefault();
let reader = new FileReader();
const imageFile = e.target.files[0];
reader.onloadend = () => {
const image = reader.result;
setImage(image);
};
reader.readAsDataURL(imageFile);
};
// etc.
}
As I wanted to simulate the uploading of an image, I went about testing it this way:
test("ImageUpload shows two buttons after an image has been uploaded", () => {
const setImageSpy = jest.fn();
const image = "data:image/jpeg;base64,/9j/4AAQSkZJ//20==";
const file = new File([image], "chucknorris.jpg", { type: "image/jpeg" });
const readAsDataURL = jest.fn();
const onloadend = jest.fn();
jest.spyOn(global, "FileReader")
.mockImplementation(function() {
this.readAsDataURL = readAsDataURL;
this.onloadend = onloadend;
});
const { getByTestId } = render(
<ImageUpload image={image} setImage={setImageSpy} />
);
fireEvent.change(getByTestId("ImageUpload"), {
target: {
files: [file]
}
});
expect(setImageSpy).toHaveBeenCalledWith(image); // this fails
expect(readAsDataURL).toHaveBeenCalledTimes(1);
expect(readAsDataURL).toHaveBeenCalledWith(file);
});
The problem is that setImageSpy never gets called.
If I understand it correctly, this is because onloadend never gets triggered.
How can I fire that event?
readAsDataURLwill be called with the actualFileand not the base64 one.. so you need to change the expect accordingly. ForsetImageSpyto be called, not sure but you probably need to mockonloadendalong withreadAsDataURL?readAsDataURL: however, the main problem is that it gets called but ... with no arguments. I've tried mocking outonloadendbut the result is the same unfortunately.createObjectURL()and I've just finished reading about the difference in another answer here on SO. I think you're right, the one you propose is the neater way to go.