Reputation: 35
In the ngOnInit
of my component I am defining the Filereader.onload
callback function. I found several solutions that say to mock the filereader and the onload but I think this defeats my purpose to test if the callback is correctly executed when onload is being called.
So I tried to mock the onload Event and then test if the functions inside the callback get called.
it("should import data on filereader onload event", () => {
const fileReader = new FileReader();
let loadEvent: ProgressEvent<FileReader>;
spyOn(fileReader, "onload").and.callThrough();
spyOn(mockServiceOne, "convertData").and.returnValue(
mockData
);
spyOn(mockServiceTwo, "importData").and.callThrough();
fileReader.onload(loadEvent);
fixture.detectChanges();
expect(fileReader.result).toBeDefined();
expect(mockServiceOne.convertData).toHaveBeenCalled();
expect(mockServiceTwo.importData).toHaveBeenCalledTimes(1);
});
});
The function I am trying to test is this:
this.fileReader.onload = (event) => {
const jsonData = JSON.parse(event.target.result.toString());
const data = this.serviceOne.convertData(
jsonData
);
this.serviceTwo.importData(data);
};
I mocked the two services and methods inside them. But in the test spec they never get called.
However the first assertion that the result of the onload event (event.target.result
) needs to be defined seems to check true.
Maybe there is a problem with the first line in the function that converts the data to json, since I am not actually giving the function a real file. However when I try to give anything other than the mocked ProgressEvent
it gives an error.
Please help me with testing the onload callback. Is it correct that I can't mock the filereader onload for this?
Upvotes: 2
Views: 2982
Reputation: 56
You don't have to mock the FileReader
. I faced this same issue a few days ago. A friend helped me create a workaround by describing the asynchronous nature of the code.
Wrap your code in a Promise
and call its resolve()
callback passing the result of the FileReader
.
// you would load your file here and return the result in a Promise
readFileMethod(file: File): Promise<string> {
return new Promise<string>((resolve) => {
const fileReader = new FileReader();
fileReader.onload = (event) => {
const jsonData = JSON.parse(event.target.result.toString());
const data = this.serviceOne.convertData(jsonData);
resolve(data);
}
fileReader.readAsText(); // I suppose this is what you called
});
}
Then, your onInit would look something like this:
ngOnInit(): void {
let file; // init your file however you do
this.readFileMethod(file).then((data) => {
this.serviceTwo.importData(data);
});
}
To test the new method, use waitForAsync
and expect()
inside the success callback:
it('should do whatever with the file', waitForAsync(() => {
component.readFileMethod(file).then((data) => {
expect(); // your test here
});
}));
To test your onInit, use fakeAsync()
and tick()
:
it('should do whatever with the file', fakeAsync(() => {
spyOn(mockServiceOne, "convertData").and.returnValue(
mockData
);
spyOn(mockServiceTwo, "importData").and.callThrough();
fixture.detectChanges();
tick();
expect(mockServiceOne.convertData).toHaveBeenCalled();
expect(mockServiceTwo.importData).toHaveBeenCalledTimes(1);
}));
Upvotes: 4