Reputation: 2404
I'm quite new in the world of Javascript and asynchronous and it seems that both are giving me headaches.
So, I have a 3rd party client API that has the following async
method getItem(id)
Now I'm trying to determine the status for a parent item based on it's children:
getStatus = function(ids) {
var failedCount = 0;
var successCount = 0;
var warningCount = 0;
ids.forEach(function(id) {
//calling the async function
getItem(id).then(function(item) {
var state = item.State;
if(state == "Success") {
successCount++;
} else if(state == "Failed") {
failedCount++;
} else if(state == "Warning") {
warningCount++;
}
});
});
if(failedCounter > 0) {
return "Failed";
} else if(warningCounter > 0) {
return "Warning";
} else if(successCounter == ids.length) {
return "Success";
} else {
return "Not run yet";
}
}
Then, to make sure that I won't break anything on the way, I decided to go with some integration tests, so I settled for QUnit and qunit-parameterize:
QUnit.cases([
{
title : "Success, Failed => Failed",
ids : [1,2],
expectedItemStateAfter : "Failed"
}
]).test( "", function( params, assert ) {
var done = assert.async(2);
setTimeout(function() {
var value = getStatus(params.ids);
assert.equal(value, params.expectedItemStateAfter);
done();
}, 2000);
});
Tried to tweak the setTimeout
timeout, tried with assert.async(2)
and assert.async();
, the default value per QUnit per their documentation, but no avail, the end result is still the same everytime and even after a bunch of readings and trying to understand I have no idea what I'm doing wrong:
1. failed @ 2004 ms
Expected: "Failed"
Result: undefined
Diff: "Failed" undefined
Upvotes: 3
Views: 456
Reputation: 33496
Your getStatus
function is returning a result before any of the async calls resolve. You need to make getStatus
return a promise that resolves when all of the other promises resolve using Promise.all
:
var getStatus = function(ids) {
var failedCount = 0;
var successCount = 0;
var warningCount = 0;
return Promise.all(ids.map(function(id) {
return getItem(id).then(function(item) {
var state = item.State;
if (state === "Success") {
successCount++;
} else if (state === "Failed") {
failedCount++;
} else if (state === "Warning") {
warningCount++;
}
});
})).then(function() {
if (failedCounter > 0) {
return "Failed";
} else if (warningCounter > 0) {
return "Warning";
} else if (successCounter === ids.length) {
return "Success";
} else {
return "Not run yet";
}
});
};
Then you will need to tweak the testing code so that it uses the promise instead of a setTimeout
. Note that you can return a thenable object from the QUnit.test
callback and it will automatically handle the resolving of a Promise
.
QUnit.cases([
{ title: "Success, Failed => Failed", ids: [1, 2], expectedStatus: "Failed" }
]).test("getStatus() test", function(params, assert) {
return getStatus(params.ids).then(function(value) {
assert.equal(value, params.expectedStatus);
});
});
Upvotes: 4