Intern: Testing async unit tests with ES6 promises - intern

I have some async functions that I need to test via Intern. Each uses ES6 promises.
In the Intern docs, it says that test functions that return a promise pass as soon as that promise is resolved. However, I not only care about whether the async function I am testing is resolved/rejected, I also want to check to make sure the resolved value is correct.
Example: I have my function:
function getSomething() {
return new Promise((resolve, reject) => {
// do some async stuff and resolve when done
setTimeout(function() {
resolve('the value');
}, 1000);
});
}
Then I have the test method:
tdd.test('getSomething', function() {
return new Promise((resolve, reject) => {
getSomething().then(function(value) {
// I want to resolve/reject the promise BASED ON the assertion -- if the assertion fails, I want to reject the promise; if it succeeds, I want to resolve it
assert.equal(value, 'the value', 'getSomething should return "the value".');
resolve();
});
});
}
I've noticed this doesn't work -- if the assertion fails in my test, the resolve() never gets called.
How would I be able to resolve/reject the promise conditioned upon the assertion? Should I wrap the assertion in a try/catch? I didn't see any documentation on the Intern docs about this (and most were using this.async() instead of ES6 promises).

What's happening in your code is that the assertion in the getSomething callback is throwing an exception, and that's preventing resolve from being called. The getSomething promise will be rejected, but since you're not returning it in the wrapper promise's initializer, the wrapper promise is never resolved or rejected.
There is no need to wrap the promise returned by getSomething in a new promise. Just return it directly.

Related

Bluebird promise failing to short circuit on reject

Maybe I just don't understand promises but I've used this pattern before and never had issues. Using bluebird within node.
I have this function which is getting hit:
function getStores() {
return new Bluebird((resolve, reject) => {
return Api.Util.findNearbyStores(Address,(stores) => {
if (!stores.result) {
console.log('one')
reject('no response');
console.log('two')
}
const status = stores.results.status
})
})
}
then hits both of my logs, continues past the if and throws
'one'
'two'
TypeError: Cannot read property 'Status' of undefined
Basically it keeps going right past the resolve.
My impression was the promise should immediately short circuit on reject and pass the rejection through as the resolution to the promise. Am I misunderstanding this?
Yes, you are misunderstanding this. reject(…) is not syntax (just like resolve(…) isn't either) and does not act like a return statement that exits the function. It's just a normal function call that returns undefined.
You should be using
if (!stores.result) reject(new Error('no response'));
else resolve(stores.results.status);
The "short-circuiting" behaviour of rejections is attributed to promise chains. When you have
getStores().then(…).then(…).catch(err => console.error(err));
then a rejection of the promise returned by getStores() will immediately reject all the promises in the chain and trigger the catch handler, ignoring the callbacks passed to then.

execution not waiting for promise result in AWS Lambda

I'm trying to use promises in AWS Lambda and am having some trouble. I'm using typescript/nodejs; see code below
export function handler(event: any, context: any, callback: Function){
testFunction().then(data => callback(null, "success from promise"));
callback(null, "success");
}
export function testFunction(){
return new Promise((resolve, reject) => {
setTimeout(() => resolve("data"), 5000);
});
}
When I run the code I'm getting the "success callback" instead of the "success from promise". Am I doing something wrong here?
You are actually calling the callback twice: once on the fourth line "success" and once after the promise resolves. I think that lambda will essentially ignore the second callback (which is actually first in your code).
You can merely remove the other call:
export function handler(event: any, context: any, callback: Function){
testFunction().then(data => callback(null, "success from promise"));
}
Note: the callback is only supported by Node 4.3. It is also optional. You only need to use it if you want to explicitly pass data back to the caller. Otherwise it will be called automatically once the event loop is empty which in this case will happen after the promise resolves.
You can also change the setting of context.callbackWaitsForEmptyEventLoop = false if you want the lambda function to end immediately when callback is called instead of waiting for the event loop to finish. Most likely you won't need to do this, though.

Node 7.1.0 new Promise() resolver undefined is not a function

I'm using the latest node version 7.1.0 on OSX but I still can't use Promises. I get
index.js
new Promise();
Error:
new Promise();
^
TypeError: Promise resolver undefined is not a function
Doesn't node 7.1.0 support ES6 and Promise?
The API for promises requires you to pass a function to the promise constructor. Quoting MDN:
new Promise( /* executor */ function(resolve, reject) { ... } );
executor - A function that is passed with the arguments resolve and reject. The executor function is executed immediately by the Promise implementation, passing resolve and reject functions (the executor is called before the Promise constructor even returns the created object). The resolve and reject functions, when called, resolve or reject the promise respectively. The executor normally initiates some asynchronous work and then, once that completes, calls either the resolve or reject function to resolve the promise or else reject it if an error occurred.
You can see this answer for usage examples.
Node 7.1 supports promises.
You must provide the callbacks to Promise constructor so it'll know what to do when resolving or rejecting the operation.
For example:
var p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 5000);
});
p.then(() => {
console.log("Got it");
})
After 5 seconds you'll see the message Got it in your console.
There is a very good library for Promises: Bluebird
Check the MDN documentation as well.
I like this article from Google developers.
You cannot create a new Promise this way without providing some argument. You can however create a promise that resolves to undefined simply by using Promise.resolve().

How to not run a Promise before I ask to

I thought I had it all figured out regarding Promise, but this one actually throws me out of bed. When creating a new Promise with a executor taking two arguments, why is this method running before I either take then() or catch() at that promise
Running node 6.2.2.
import assert = require('assert');
describe("When working with promises", () => {
let ar = [1, 2, 3, 4, 5, 6];
beforeEach(() => {
})
it("should be perfectly fine but isn't when mapping to promises", (done) => {
ar.map(num => {
return new Promise((resolve, reject) => {
done(new Error('Why on earth is ' + num + ' called'));
})
})
done();
})
it("should be perfectly fine when mapping to methods", (done) => {
ar.map(num => {
return (resolve, reject) => {
done(new Error(num + ' is not called ever'));
}
})
done();
})
});
First test fails, and second test is successful.
If you check the documentation for Promise, you will find that the function that is given to the constructor is run immediately. It is supposed to kick off the asynchronous calculation and install the two callbacks there (so that resolve and reject are not invoked just now, but whenever that calculation completes or fails).
The Promise function is not the asynchronous calculation, it just wraps that calculation and the two callbacks you need to keep track of it together into a nice package (and returns immediately after this setup is done).
Your second example creates an anonymous function for each number, but does not invoke any of them.
why is this method running before I either take then() or catch() at that promise
The Promise does not care if you install any handlers/chains. The calculation will have been started (or not) no matter if anyone is watching it or not.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise:
[...] The executor function is executed immediately by the Promise implementation, passing resolve and reject functions [...].
That's the way, the Promise implementation works. You can also create a new promise and attach chained then() or catch() handlers later when the promise already succeeded or failed.
const p = new Promise(someExecutor);
// do some other things
p.then(someHandler);
// do some other things
p.catch(someOtherHandler);
If you do not want the executor to execute, yet, then don't pass it to the Promise constructur, yet.
To achieve the same behavior you have to wrap promises in a factory. You can use a lambda functions for that.
it("should be perfectly fine but isn't when mapping to promises", (done) => {
ar.map(num => {
return () => new Promise((resolve, reject) => {
done(new Error('Why on earth is ' + num + ' called'));
})
})
done();
})
So you have stateless factories to call later without creating promises (that run immediately) during map.
It permits you to compose and join Promises for later batch execution using Promise.all, Promise.race, or custom chaining.
If you want something to run only (i.e. not before) a "then()" handler is attached, then you can use plain then-ables ( https://promisesaplus.com/ )
var runLater = {
then: function(resolve, reject) {
var p = new Promise (...); // Creating a promise is optional
resolve(p); // you can return a plain value
}
}
Note this is not a Promise, so it does not have a "catch" method.
But it can be given to any function expecting a promise:
`Promise.all([runLater])
return as result from a then handled .then(function() { return runLater; })
Promise.resolve(runLater) => Now it is a promise with then/catch
Any of those will call the runLater.then method.

Wrapping promise in async/await

I'm struggling a bit with async/await and returning a value from a Promise.
function test () {
return new Promise((resolve, reject) => {
resolve('Hello')
})
}
async function c() {
await test()
}
As I understood things I should be able to get a value by doing:
console.log(c())
But clearly I am missing a point here as this returns a promise. Shouldn't it print "hello"? On a similar note I am unclear as to whether a callback needs to be converted to a promise before wrapping it in async/await?
I am missing a point here as this returns a promise. Shouldn't console.log(c()) print "hello"?
No, async functions always return promises. They're not magically running asynchronous code synchronously - rather the reverse, they turn synchronous-looking code (albeit speckled with await keywords) into asynchronously running one.
You can get the result value inside the asynchronous function:
async function c() {
const result = await test()
console.log(result);
return 'World';
}
c().then(console.log);
I am unclear as to whether a callback needs to be converted to a promise before wrapping it in async/await?
Yes, you can await only promises. See How do I convert an existing callback API to promises? for how to do the conversion.
Async functions return a Promise. If the function throws an error, the
Promise will be rejected. If the function returns a value, the Promise
will be resolved.

Resources