Reputation: 199
I'm trying to mock a file reader, and I have a function that accepts a callback, but during the test, the line where the callback is called is not covered. How can this be solved?
function:
const testFunction = (uint8arr, callback) => {
const bb = new Blob([uint8arr]);
const f = new FileReader();
f.onload = function (e) {
callback(e.target.result);
};
f.readAsText(bb);
};
module.exports = { testFunction };
test:
const { testFunction } = require("./index");
class FileReaderMock {
DONE = FileReader.DONE;
EMPTY = FileReader.EMPTY;
LOADING = FileReader.LOADING;
readyState = 0;
error = null;
result = null;
abort = jest.fn();
addEventListener = jest.fn();
dispatchEvent = jest.fn();
onabort = jest.fn();
onerror = jest.fn();
onload = jest.fn();
onloadend = jest.fn();
onloadprogress = jest.fn();
onloadstart = jest.fn();
onprogress = jest.fn();
readAsArrayBuffer = jest.fn();
readAsBinaryString = jest.fn();
readAsDataURL = jest.fn();
readAsText = jest.fn();
removeEventListener = jest.fn();
}
const mockCallback = jest.fn();
describe("testFunction", () => {
const fileReader = new FileReaderMock();
jest.spyOn(window, "FileReader").mockImplementation(() => fileReader);
it("should be called mockCallback and readAsText with the blob value", () => {
const uintArray = new Uint8Array();
testFunction(uintArray, mockCallback);
// expect(mockCallback).toHaveBeenCalled();
// expect(fileReader.readAsText).toHaveBeenCalledWith(new Blob([uintArray]));
});
});
codesandbox: https://codesandbox.io/s/jest-test-forked-ecejb?file=/index.test.js
Upvotes: 2
Views: 4144
Reputation: 102247
You can use the getter and setter of the Object.defineProperty()
method to intercept the assignment operation of the onload
function, so you can get the onload
function to test it as usual.
E.g.
index.js
:
const testFunction = (uint8arr, callback) => {
const bb = new Blob([uint8arr]);
const f = new FileReader();
f.onload = function (e) {
callback(e.target.result);
};
f.readAsText(bb);
};
module.exports = { testFunction };
index.test.js
:
const { testFunction } = require('./index');
describe('testFunction', () => {
it('should be called mockCallback and readAsText with the blob value', () => {
const mockCallback = jest.fn();
const fileReader = {
readAsText: jest.fn(),
};
let onloadRef;
Object.defineProperty(fileReader, 'onload', {
get() {
return this._onload;
},
set(onload) {
onloadRef = onload;
this._onload = onload;
},
});
jest.spyOn(window, 'FileReader').mockImplementation(() => fileReader);
const uintArray = new Uint8Array();
testFunction(uintArray, mockCallback);
// onload test
const event = { target: { result: 'teresa teng' } };
onloadRef(event);
expect(mockCallback).toBeCalledWith('teresa teng');
expect(fileReader.readAsText).toBeCalledWith(new Blob([uintArray]));
});
});
unit test result:
PASS examples/66964346/index.test.js (7.479 s)
testFunction
✓ should be called mockCallback and readAsText with the blob value (4 ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 8.575 s, estimated 9 s
Upvotes: 1