How can I count calls to a looped Promise function with Jest - jestjs

I have a function:
myFunc = async () => {
for (let item of items) {
await doSomething(items);
}
}
I use for of loop because it respects await.
My test:
it('should call doSomething twice', () => {
const doSomething = jest.fn();
const items = [{a: 'a'}, {b: 'b'}];
myFunc(items);
expect(doSomething).toBeCalledTimes(2);
})
It fails because doSomething is only called once.

You will need to wait for all the iterations to be completed.
Try something like this:
it('should call doSomething twice', async () => {
const doSomething = jest.fn();
const items = [{a: 'a'}, {b: 'b'}];
// Waiting
await myFunc(items);
expect(doSomething).toBeCalledTimes(2);
})

Related

Jest mock nested function by using spyOn, but still call the actual function

getInfo calls getColor in the same file. My intention is to mock getColor function, I import the func.js as a module and spyOn getColor. The mocked getColor is supposed to return "Red", but it still calls the actual function and returns "Black".
Function File
// func.js
function getColor() {
return "black"
}
function getInfo(){
const color = getColor()
const size = "L"
return `${color}-${size}`
}
module.exports = { getColor, getInfo }
Test File
// func.test.js
const func = require("./func")
describe("Coverage Change Test", () => {
beforeAll(() => {
const colorMock = jest.spyOn(func, "getColor"); // spy on otherFn
colorMock.mockImplementation(() => "Red");
});
afterAll(() => {
colorMock.resetAllMocks();
})
test("return Large Red", async () => {
const res = func.getInfo();
expect(res).toEqual("Red-L");
});
});
I also tried requireActual, but it also calls the actual one.
const { getInfo, getColor } = require('./func');
jest.mock('./func', () => ({
...jest.requireActual('./func.'),
getColor: jest.fn().mockImplementation(() => 'Red'),
}))
describe('test', () => {
test('returns red', () => {
const res = getInfo()
expect(res).toEqual("Red-L")
})
})
How can I properly mock up a nested function in Jest? Thanks in advance.
You're spying on func.getColor and mocking its implementation but getInfo is calling the locally scoped getColor function. You have to change the way getColor is being called to be able to mock it.
exports.getColor = function() {
return 'black'
}
exports.getInfo = function() {
const color = exports.getColor()
const size = 'L'
return `${color}-${size}`
}
Use rewire module to rewrite your exported properties.
Your test file will look like this:
const rewire = require('rewire')
describe('test', () => {
let func;
let getColorSpy;
beforeEach(() => {
getColorSpy = jest.fn()
func = rewire(__dirname + '/func.js') // import
func.__set__('getColor', getColorSpy) // rewrite content of getColor
})
test('should return Red-L when getColor returns Red', () => {
getColorSpy.mockReturnValue('Red')
const res = func.getInfo()
expect(res).toEqual("Red-L")
})
})
Try to avoid write code like your module.

Node measure execution time - return value from an async passed as parameter to another function

I want to write a function to measure the performance of parts of code (other methods) that could return a value. This is what I came out at the moment:
const fn = async (): Promise<any> => {
setTimeout(async (): Promise<any> => {
return new Promise((resolve) => resolve('Hello World!'));
}, 3000);
};
async measure(fn: () => Promise<any>): Promise<any> {
const startTime = this.performance.now();
const result = await functionToMeasure();
const endTime = this.performance.now();
const executionTime = endTime - startTime;
console.log(`Executed in ${executionTime} ms`);
return result;
}
const result = async measure(functionToMeasure); // result is undefined
The result is that functionToMeasure actually runs but it never returns something and at the moment I can use it only with void function.
I'd like to fix it if possible, or I can change completely if there's a better way to do it.
EDIT:
Actual code
const callback = async (): Promise<any> => {
return await doSomethingAndReturn();
};
const searchResults: string[] = await measure(callback);
Do I've to wrap doSomethingAndReturn in an async Promise?
You need to wrap the setTimeout call in a promise and then resolve the result, so it should look something like this:
const {performance} = require('perf_hooks');
async function executeAndMeasure(fn) {
const startTime = performance.now();
const result = await fn();
const endTime = performance.now();
const executionTime = endTime - startTime;
console.log(`Executed in ${executionTime} ms`);
return result;
}
function someFnThatReturnsAPromise() {
return new Promise(resolve => {
setTimeout(() => {
resolve("Hello World");
}, 3000);
})
}
async function someAsyncFunction() {
return 123;
}
(async () => {
let result = await executeAndMeasure(someFnThatReturnsAPromise);
console.log(`result was ${result}`);
result = await executeAndMeasure(someAsyncFunction);
console.log(`result was ${result}`);
})();

How solve this answer [AsyncFunction: response]?

I execute this function for a test in nodejs
const response = async () => {return await MyService.Adding({name})}
console.log(response)
but i get this: [AsyncFunction: response]
i want to use:
const res = await (async () => {
const response = await MyService.Adding({name})
return response
})()
console.log('RESPONDE ', res, expected)
If you are in the async function, just use await to run the other async functions.
Example
const res = await MyService.Adding({
name
})
Try:
// Just for example
const MyService = {
Adding: async (params) => params
}
async function main() {
const res = await MyService.Adding({
name: 'Your Name'
})
console.log(res)
}
main()
You are assigning a function to response
You want to eval the function in order to get the expected response.
Something like this:
let response2 = (async () => {return await MyService.Adding({name})})()
But if you are writing a small script, and you want to use await, you can't do it without an async function. So your script should be refactor to something like this:
(async () => {
const response = await MyService.Adding({name})
console.log(response);
})()
Your whole script can be written in the implicit evaluation of an async function and await will work.
It is not very preatty, but is better that managing callbacks

Error: await is only valid in async function when function is already within an async function

Goal: Get a list of files from my directory; get the SHA256 for each of those files
Error: await is only valid in async function
I'm not sure why that is the case since my function is already wrapped inside an async function.. any help is appreciated!
const hasha = require('hasha');
const getFiles = () => {
fs.readdir('PATH_TO_FILE', (err, files) => {
files.forEach(i => {
return i;
});
});
}
(async () => {
const getAllFiles = getFiles()
getAllFiles.forEach( i => {
const hash = await hasha.fromFile(i, {algorithm: 'sha256'});
return console.log(hash);
})
});
Your await isn't inside an async function because it's inside the .forEach() callback which is not declared async.
You really need to rethink how you approach this because getFiles() isn't even returning anything. Keep in mind that returning from a callback just returns from that callback, not from the parent function.
Here's what I would suggest:
const fsp = require('fs').promises;
const hasha = require('hasha');
async function getAllFiles() {
let files = await fsp.readdir('PATH_TO_FILE');
for (let file of files) {
const hash = await hasha.fromFile(i, {algorithm: 'sha256'});
console.log(hash);
}
}
getAllFiles().then(() => {
console.log("all done");
}).catch(err => {
console.log(err);
});
In this new implementation:
Use const fsp = require('fs').promises to get the promises interface for the fs module.
Use await fsp.readdir() to read the files using promises
Use a for/of loop so we can properly sequence our asynchronous operations with await.
Call the function and monitor both completion and error.

Async await not working in forEach

I have the following code:
async function goodUsers(users) {
const filteredUsers = [];
users.forEach(async (userInstance) => {
console.log('TEST1');
const fromUserContacts = await db.userContactInvite.findAll({
where: {
fromUserId: userInstance.id,
},
});
console.log('TEST2');
await fromUserContacts.forEach((fromUserContact) => {
console.log('TEST3');
const userJson = fromUserContact.toJSON();
userJson.contactState = 'INVITATION_SENT';
filteredUsers.push(userJson);
});
console.log('TEST4');
});
console.log('FILTERED', filteredUsers);
return filteredUsers;
}
When I call goodUsers I get the following output:
TEST1
FILTERED
TEST2
TEST3
TEST4
FILTERED should be last (obviously).
I tried various options but I seem to be not understanding something here. Do you guys notice what's going on?
This's a correct behavior, async/await only affect the function where they are used. So you need to replace forEach which calls callback for each element, to for operator:
async function goodUsers(users) {
const filteredUsers = [];
for(user in users) {
console.log('TEST1');
const fromUserContacts = await new Promise(resolve => setTimeout(() => resolve(['c1', 'c2']), 500));
console.log('TEST2');
fromUserContacts.forEach(fromUserContact => {
console.log('TEST3');
filteredUsers.push('json');
});
console.log('TEST4');
}
console.log('FILTERED', filteredUsers);
return filteredUsers;
}
goodUsers(['u1', 'u2']);

Resources