I have function want to do unit testing, for example, it contains:
function foo (file, option) {
return new Promise((resolve, reject) => fs.readFile(file, option, (err, content) => {
if (err) return reject(new Error(`Failed to read the file: (${file})`));
else {
(...some operations, and that is the point for me to test it...)
return resolve(...some result...);
}
}));
}
Just right at the beginning of the testing file, I have:
jest.mock('fs', () => ({
readFile : jest.fn(),
}));
const fs = require('fs');
The testing logic is something like:
test('Should get context as string from the template file', async () => {
const mockContent = '<a>Hello World</a>';
fs.readFile.mockReturnValue(mockContent);
const result = (await foo('test', 'utf8')).then(() => 123);
//
expect(result).toEqual(123);
});
However, when I try to run the test, it shows:
- Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.`
I know it is an issue due to unresolved promise from Jest website; but their suggestion is not what I have actually... I recognize my problem is due to fs.readFile(...)
is replaced by the mocking function which returns undefined
so that the new Promise
is never being rejected/resolved (am I correct?!).
My question is how can I do a unit test like this case? I really don't want to fire a I/O event like using a empty file in oder to make it work... Any thoughts?! Thanks!
/// UPDATE: I think a much clear question is how are we mock the data that received by a callback function. In my example it looks like I test against it, but in my real code, what I really want to test is the logic of the callback function.
I have function want to do unit testing, for example, it contains:
function foo (file, option) {
return new Promise((resolve, reject) => fs.readFile(file, option, (err, content) => {
if (err) return reject(new Error(`Failed to read the file: (${file})`));
else {
(...some operations, and that is the point for me to test it...)
return resolve(...some result...);
}
}));
}
Just right at the beginning of the testing file, I have:
jest.mock('fs', () => ({
readFile : jest.fn(),
}));
const fs = require('fs');
The testing logic is something like:
test('Should get context as string from the template file', async () => {
const mockContent = '<a>Hello World</a>';
fs.readFile.mockReturnValue(mockContent);
const result = (await foo('test', 'utf8')).then(() => 123);
//
expect(result).toEqual(123);
});
However, when I try to run the test, it shows:
- Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.`
I know it is an issue due to unresolved promise from Jest website; but their suggestion is not what I have actually... I recognize my problem is due to fs.readFile(...)
is replaced by the mocking function which returns undefined
so that the new Promise
is never being rejected/resolved (am I correct?!).
My question is how can I do a unit test like this case? I really don't want to fire a I/O event like using a empty file in oder to make it work... Any thoughts?! Thanks!
/// UPDATE: I think a much clear question is how are we mock the data that received by a callback function. In my example it looks like I test against it, but in my real code, what I really want to test is the logic of the callback function.
Share Improve this question edited Jan 29, 2018 at 23:13 Leo Li asked Jan 29, 2018 at 0:57 Leo LiLeo Li 2574 silver badges20 bronze badges 3- The thing is that if you re testing against fs.readFileAsync you should not mock itself. Instead test it with fixture files directly for unit test. – Allen Commented Jan 29, 2018 at 1:47
- And working with async functions you need to return a promise or invoke a callback passed from test(xxx, (done)). Btw your mocked jest.fn was not async at all – Allen Commented Jan 29, 2018 at 1:52
- Thank you for pointing me out my mocked async function is not async at all! – Leo Li Commented Jan 29, 2018 at 2:20
1 Answer
Reset to default 8The problem, is the way you mock js.readFile
. mockReturnValue
just creates a function that returns something, but you want it to call on of its parameter so you need to use mockImplementation
to define the mock function by yourself
jest.fn().mockImplementation((file, option, cb) => cb(null, mockContent))
or
jest.fn().mockImplementation((file, option, cb) => cb('Some Error', null))