I'm trying to make a test with jest and promises.
When I try to write in console the result get it from the promise I've got an undefined value
This is my testing code:
describe("Search concurrent with promises", () => {
describe("Test 10: Several searches in DDBB", () => {
function connection(){
let ddbb = new PGMappingDDBB();
return new Promise((resolve, reject) => {
let db = ddbb.connect();
//resolve("Hello World");
resolve(db);
});
}
test("Test 12: Several searches concurrently", () => {
connection().then(ddbb => {
console.log(ddbb);
});
});
});
});
ddbb.connect() is an asynchronous function. The code of connect() is:
async connect(){
this.client = await poolMapping.connect();
}
When I try to write the state of the variable ddbb I've got that is undefined.
However, If I comment resolve(db) and remove the comment of resolve("Hello World"), when I write the value of ddbb I've got "Hello World".
What am I doing wrong?
Edit I:
ddbb.connect() returns a Promise. If I write what returns console.log(ddbb.connect()). I've got:
Promise { <pending> }
To explain:
async connect(){
this.client = await poolMapping.connect();
// NOTE: There is no return value
}
describe("Search concurrent with promises", () => {
describe("Test 10: Several searches in DDBB", () => {
function connection(){
let ddbb = new PGMappingDDBB();
return new Promise((resolve, reject) => {
let db = ddbb.connect();
// ^^ this will be undefined, as connect has no return value
resolve(db);
// ^^^^^^^^^^^^ Resolving the promise with undefined
});
}
test("Test 12: Several searches concurrently", () => {
connection().then(ddbb => {
console.log(ddbb);
/// ^^^^ will be undefined
});
});
});
});
Additionally, jest is not waiting for the outcome of the promise, and you are not asserting anything in the test, so it will always succeed.
When dealing with promises, if you return the promise from the test, Jest will wait for it. But you still need to assert on the value.
Related
I'm using the async.eachLimit function to control the maximum number of operations at a time.
const { eachLimit } = require("async");
function myFunction() {
return new Promise(async (resolve, reject) => {
eachLimit((await getAsyncArray), 500, (item, callback) => {
// do other things that use native promises.
}, (error) => {
if (error) return reject(error);
// resolve here passing the next value.
});
});
}
As you can see, I can't declare the myFunction function as async because I don't have access to the value inside the second callback of the eachLimit function.
You're effectively using promises inside the promise constructor executor function, so this the Promise constructor anti-pattern.
Your code is a good example of the main risk: not propagating all errors safely. Read why there.
In addition, the use of async/await can make the same traps even more surprising. Compare:
let p = new Promise(resolve => {
""(); // TypeError
resolve();
});
(async () => {
await p;
})().catch(e => console.log("Caught: " + e)); // Catches it.
with a naive (wrong) async equivalent:
let p = new Promise(async resolve => {
""(); // TypeError
resolve();
});
(async () => {
await p;
})().catch(e => console.log("Caught: " + e)); // Doesn't catch it!
Look in your browser's web console for the last one.
The first one works because any immediate exception in a Promise constructor executor function conveniently rejects the newly constructed promise (but inside any .then you're on your own).
The second one doesn't work because any immediate exception in an async function rejects the implicit promise returned by the async function itself.
Since the return value of a promise constructor executor function is unused, that's bad news!
Your code
There's no reason you can't define myFunction as async:
async function myFunction() {
let array = await getAsyncArray();
return new Promise((resolve, reject) => {
eachLimit(array, 500, (item, callback) => {
// do other things that use native promises.
}, error => {
if (error) return reject(error);
// resolve here passing the next value.
});
});
}
Though why use outdated concurrency control libraries when you have await?
I agree with the answers given above and still, sometimes it's neater to have async inside your promise, especially if you want to chain several operations returning promises and avoid the then().then() hell. I would consider using something like this in that situation:
const operation1 = Promise.resolve(5)
const operation2 = Promise.resolve(15)
const publishResult = () => Promise.reject(`Can't publish`)
let p = new Promise((resolve, reject) => {
(async () => {
try {
const op1 = await operation1;
const op2 = await operation2;
if (op2 == null) {
throw new Error('Validation error');
}
const res = op1 + op2;
const result = await publishResult(res);
resolve(result)
} catch (err) {
reject(err)
}
})()
});
(async () => {
await p;
})().catch(e => console.log("Caught: " + e));
The function passed to Promise constructor is not async, so linters don't show errors.
All of the async functions can be called in sequential order using await.
Custom errors can be added to validate the results of async operations
The error is caught nicely eventually.
A drawback though is that you have to remember putting try/catch and attaching it to reject.
BELIEVING IN ANTI-PATTERNS IS AN ANTI-PATTERN
Throws within an async promise callback can easily be caught.
(async () => {
try {
await new Promise (async (FULFILL, BREAK) => {
try {
throw null;
}
catch (BALL) {
BREAK (BALL);
}
});
}
catch (BALL) {
console.log ("(A) BALL CAUGHT", BALL);
throw BALL;
}
}) ().
catch (BALL => {
console.log ("(B) BALL CAUGHT", BALL);
});
or even more simply,
(async () => {
await new Promise (async (FULFILL, BREAK) => {
try {
throw null;
}
catch (BALL) {
BREAK (BALL);
}
});
}) ().
catch (BALL => {
console.log ("(B) BALL CAUGHT", BALL);
});
I didn't realized it directly by reading the other answers, but what is important is to evaluate your async function to turn it into a Promise.
So if you define your async function using something like:
let f = async () => {
// ... You can use await, try/catch, throw syntax here (see answer of Vladyslav Zavalykhatko) ..
};
your turn it into a promise using:
let myPromise = f()
You can then manipulate is as a Promise, using for instance Promise.all([myPromise])...
Of course, you can turn it into a one liner using:
(async () => { code with await })()
static getPosts(){
return new Promise( (resolve, reject) =>{
try {
const res = axios.get(url);
const data = res.data;
resolve(
data.map(post => ({
...post,
createdAt: new Date(post.createdAt)
}))
)
} catch (err) {
reject(err);
}
})
}
remove await and async will solve this issue. because you have applied Promise object, that's enough.
I'm using the async.eachLimit function to control the maximum number of operations at a time.
const { eachLimit } = require("async");
function myFunction() {
return new Promise(async (resolve, reject) => {
eachLimit((await getAsyncArray), 500, (item, callback) => {
// do other things that use native promises.
}, (error) => {
if (error) return reject(error);
// resolve here passing the next value.
});
});
}
As you can see, I can't declare the myFunction function as async because I don't have access to the value inside the second callback of the eachLimit function.
You're effectively using promises inside the promise constructor executor function, so this the Promise constructor anti-pattern.
Your code is a good example of the main risk: not propagating all errors safely. Read why there.
In addition, the use of async/await can make the same traps even more surprising. Compare:
let p = new Promise(resolve => {
""(); // TypeError
resolve();
});
(async () => {
await p;
})().catch(e => console.log("Caught: " + e)); // Catches it.
with a naive (wrong) async equivalent:
let p = new Promise(async resolve => {
""(); // TypeError
resolve();
});
(async () => {
await p;
})().catch(e => console.log("Caught: " + e)); // Doesn't catch it!
Look in your browser's web console for the last one.
The first one works because any immediate exception in a Promise constructor executor function conveniently rejects the newly constructed promise (but inside any .then you're on your own).
The second one doesn't work because any immediate exception in an async function rejects the implicit promise returned by the async function itself.
Since the return value of a promise constructor executor function is unused, that's bad news!
Your code
There's no reason you can't define myFunction as async:
async function myFunction() {
let array = await getAsyncArray();
return new Promise((resolve, reject) => {
eachLimit(array, 500, (item, callback) => {
// do other things that use native promises.
}, error => {
if (error) return reject(error);
// resolve here passing the next value.
});
});
}
Though why use outdated concurrency control libraries when you have await?
I agree with the answers given above and still, sometimes it's neater to have async inside your promise, especially if you want to chain several operations returning promises and avoid the then().then() hell. I would consider using something like this in that situation:
const operation1 = Promise.resolve(5)
const operation2 = Promise.resolve(15)
const publishResult = () => Promise.reject(`Can't publish`)
let p = new Promise((resolve, reject) => {
(async () => {
try {
const op1 = await operation1;
const op2 = await operation2;
if (op2 == null) {
throw new Error('Validation error');
}
const res = op1 + op2;
const result = await publishResult(res);
resolve(result)
} catch (err) {
reject(err)
}
})()
});
(async () => {
await p;
})().catch(e => console.log("Caught: " + e));
The function passed to Promise constructor is not async, so linters don't show errors.
All of the async functions can be called in sequential order using await.
Custom errors can be added to validate the results of async operations
The error is caught nicely eventually.
A drawback though is that you have to remember putting try/catch and attaching it to reject.
BELIEVING IN ANTI-PATTERNS IS AN ANTI-PATTERN
Throws within an async promise callback can easily be caught.
(async () => {
try {
await new Promise (async (FULFILL, BREAK) => {
try {
throw null;
}
catch (BALL) {
BREAK (BALL);
}
});
}
catch (BALL) {
console.log ("(A) BALL CAUGHT", BALL);
throw BALL;
}
}) ().
catch (BALL => {
console.log ("(B) BALL CAUGHT", BALL);
});
or even more simply,
(async () => {
await new Promise (async (FULFILL, BREAK) => {
try {
throw null;
}
catch (BALL) {
BREAK (BALL);
}
});
}) ().
catch (BALL => {
console.log ("(B) BALL CAUGHT", BALL);
});
I didn't realized it directly by reading the other answers, but what is important is to evaluate your async function to turn it into a Promise.
So if you define your async function using something like:
let f = async () => {
// ... You can use await, try/catch, throw syntax here (see answer of Vladyslav Zavalykhatko) ..
};
your turn it into a promise using:
let myPromise = f()
You can then manipulate is as a Promise, using for instance Promise.all([myPromise])...
Of course, you can turn it into a one liner using:
(async () => { code with await })()
static getPosts(){
return new Promise( (resolve, reject) =>{
try {
const res = axios.get(url);
const data = res.data;
resolve(
data.map(post => ({
...post,
createdAt: new Date(post.createdAt)
}))
)
} catch (err) {
reject(err);
}
})
}
remove await and async will solve this issue. because you have applied Promise object, that's enough.
I wrote a function I try to test with jest:
asyncUpperCase(value: string): Promise<string> {
return new Promise(function(resolve, reject) {
setTimeout(() => {
return resolve(value.toUpperCase())
}, 1000);
})
}
It recives a string and turns it into a upperCase string (asynchronally).
I have to tests:
it('upperCase with promise and then', () => {
return myAsync.asyncUpperCase('hello world').then(value => {
expect(value).toBe('HELLO WORLD');
})
})
it('upperCase with promise and resolve', () => {
const promise = myAsync.asyncUpperCase('hello world');
expect(promise).resolves.toBe('HELLO WORLD');
})
First test works correctly. But the second test does never fail. So if I change the expected string to ABC it still exits with success. Why and how do i use resolves correctly?
A promise is asynchronous and needs time to be resolved, there's no way how resolves can fail synchronous test. Without being chained inside a test, it will result in unhandled rejection if test run is long enough.
It should be:
await expect(promise).resolves.toBe('HELLO WORLD');
Jest provides 3 options to properly handle asynchronous tests documentation
Returning a promise
it('upperCase with promise and resolve', () => {
const promise = myAsync.asyncUpperCase('hello world');
return expect(promise).resolves.toBe('HELLO WORLD');
})
Using async/await
Which is quite the same as an async function will return Promise<void>
it('upperCase with promise and resolve', async () => {
const promise = myAsync.asyncUpperCase('hello world');
expect(await promise).toBe('HELLO WORLD');
})
Using a callback
it('upperCase with promise and resolve', (done) => {
const promise = myAsync.asyncUpperCase('hello world');
promise
.then(result => expect(promise).toBe('HELLO WORLD'))
.then(done);
})
also you may take a look at Advance Timers by Time
(Forgive me if the title is inaccurate to the problem this one is boggling the mind)
My application requires that I check a value from the request against the database. For this I created an asynchronous function to query the database:
async function checktoken(){
return prisma.$exists.invalidtoken({token: "testtoken"}).then(result => {
return(result)
})
}
I know that the database call on its own works:
prisma.$exists.invalidtoken({token: "testtoken"}).then(result => {
console.log(result) // returns true
})
In the function that fires at every request I try and call checktoken():
async function getUser(token){
var promise = await checktoken()
var result = promise
console.log(result) //undefined
};
Amending the function to include an explicit call to the database works but only when var promise = await checktoken() is defined before it:
async function getUser(token){
var promise = await checktoken() //When this is removed result1 is undefinded
await prisma.$exists.invalidtoken({token: "testtoken"}).then(result1 => {
console.log("inside db call: "+result1) // true
})
};
I think I have a fundamental misunderstanding of async/await but I am not sure exactly what I am missing.
EDIT:
I have updated my approach taking the advice I received and it still does not work. I am beginning to think my ORM is doing something weird:
async function test(token) {
const status = await prisma.$exists.invalidtoken({ token: token });
console.log(status);
return status;
}
test("123") //logs false (as it should)
async function getUser(token){
var status = await test(token) //logs undefined
console.log(status) //logs undefined
};
An async function requires an await. If you are using the promise.then() technique, then what you would want to do is return a new Promise(), and within the .then call back function resolve the promise
function checktoken() {
return new Promise((resolve,reject) => {
prisma.$exists.invalidtoken({token: "testtoken"}).then(result => {
doSomeOtherStuff();
resolve(result);
});
});
}
Is functionally the same as
async checktoken() {
await prisma.$exists.invalidtoken({token: "testtoken"});
}
I've been trying to test the following code using Mocha, but I always get the error.
Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test
The code I want to test is as follows.
'use strict'
const Promise = require('bluebird');
const successResponse = {status: 'OK'};
const failResponse = {status: 'FAIL'};
function dbStatusSuccess () {
return new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(successResponse);
}, 2010);
});
}
function dbStatusFail () {
return new Promise(function(resolve, reject) {
setTimeout(() => {
reject(failResponse);
}, 2000);
});
}
module.exports = {
dbStatusSuccess,
dbStatusFail
}
and here are my tests.
'use strict'
const Promise = require('bluebird');
const chai = require('chai')
chai.use(require('chai-string'))
chai.use(require('chai-as-promised'));
const expect = chai.expect;
chai.should();
const healthyCheck = require('./healthyCheck');
const resp = {status:'OK'};
const resp2 ={status: 'FAIL'};
describe('healthy-check end point', () => {
it('should return successful response when connected to database', () => {
return healthyCheck.dbStatusSuccess()
.then((res) => {
console.log(JSON.stringify(res, undefined, 2));
return expect(res).to.equal(resp);
}).catch( (err) => {
console.log(err);
return expect(err).to.deep.equal(resp2);
});
});
});
I also get an error { AssertionError: expected { status: 'OK' } to equal { status: 'OK' } in the console. Which I believe is from loggin the err from the .catch function.
EDIT 1.
Removed the reject function from dbStatusSuccess function.
The issue is with the promises taking 2 seconds to complete/fail. If the time set in setTimeout is less than 2 seconds, the tests will pass.
The default timeout in your test seems to be 2000ms. Your code obviously takes longer to complete. Therefore, you have to up the timeout limit. As noted here you shouldn't use arrow functions so you can safely access this.
Then you can increase your timeout like so:
'use strict'
const Promise = require('bluebird');
const chai = require('chai')
chai.use(require('chai-string'))
chai.use(require('chai-as-promised'));
const expect = chai.expect;
chai.should();
const healthyCheck = require('./healthyCheck');
const resp = {status:'OK'};
const resp2 ={status: 'FAIL'};
describe('healthy-check end point', () => {
it('should return successful response when connected to database', function() {
this.timeout(3000);
return healthyCheck.dbStatusSuccess()
.then((res) => {
console.log(JSON.stringify(res, undefined, 2));
return expect(res).to.equal(resp);
}).catch( (err) => {
console.log(err);
return expect(err).to.deep.equal(resp2);
});
});
});
Then your test should run as expected.
'use strict'
const Promise = require('bluebird');
const chai = require('chai');
chai.use(require('chai-string'));
chai.use(require('chai-as-promised'));
const expect = chai.expect;
chai.should();
const healthyCheck = require('./healthyCheck');
describe('healthy-check end point', function() {
it('should return successful response when connected to database', function(done) {
const resp = {status: 'OK'};
healthyCheck.dbStatusSuccess()
.then((res) => {
console.log(JSON.stringify(res, undefined, 2));
expect(res).to.equal(resp);
done();
}).catch(done);
});
});
In code example I don't return promise, so I need use callback. Usage callback in your async tests helps avoid Error: timeout of 2000ms exceeded
Don't use arrow function in descibe and it. More info
You should use the done callback, for example:
it('reads some file', function(done) {
fs.readFile('someFile.json', function(err, data) {
if (err) return done(err);
assert(data != null, "File should exist.");
done();
});
});
What's happening is the test ('it' function) returns before your promise resolves; using done means the test won't finish until you call done() when the promises resolves.
See
http://tobyho.com/2015/12/16/mocha-with-promises/
and
https://mochajs.org/#working-with-promises
Well, I just found the problem, your test is tricky.
You set the timeout timer to 2010ms but Mocha default execution time is 2000ms, so you will always get the error from Mocha.
I still think you shouldn't create .catch block in the returned promise chain, it will stop the promise chain to propagate.
describe('healthy-check end point', () => {
it('should return successful response when connected to database', () => {
return healthyCheck.dbStatusSuccess()
.then((res) => {
console.log(JSON.stringify(res, undefined, 2));
return expect(res).to.equal(resp);
});
}).timeout(2500); //tell Mocha to wait for 2500ms
});