Angular + Karma: Testing async functions
Jasmine has a way to do async testing using waits() or waitsFor() and runs(). Look here.
Code would be something like:
...
flag = false;
timer = new Timer(1000);
timer.handler = function () { flag = true };
expect(flag).toBe(false);
waitsFor( function() {
return flag;
}, "timer ran");
runs( function() {
expect(flag).toBe(true);
});
...
Note from OP
This is the right solution, so I marked it as accepted. I actually ended up implementing a sleep-like method based on this solution, and wanted to share in case it was helpful to others.
In the test file:
function loiter(ms) {
var loiter = true;
setTimeout(function () {loiter = false}, ms);
waitsFor( function () {return !loiter}, "Loitered too long", ms + 50);
}
it("should ...", function () {
flag = false;
timer = new Timer(1000);
timer.handler = function () {flag = true};
setTimeout(function () {expect(flag).toBe(true)}), 1100);
loiter(1200);
})
I hope this is useful! I'll leave it as an exercise for the reader to figure out why I did it this way =)
Related videos on Youtube
Sir Robert
Updated on September 14, 2022Comments
-
Sir Robert over 1 year
I have an angular service that does some async stuff (based on timers). One of the things you can do with a timer is define a 'handler' that fires when the timer expires (as in this pseudo-code):
flag = false; timer = new Timer(1000); // ms timer.handler = function () { flag = true };
In this trivial case, the timer would set flag to true after 1 second. How do I unit test this with Angular/Karma/Jasmine?
From reading the docs, I would have expected this to work:
... flag = false; timer = new Timer(1000); timer.handler = function () { flag = true }; expect(flag).toBe(false); sleep(2) expect(flag).toBe(true); ...
Rather than being morally upright, that test decided to fail with this:
ReferenceError: Can't find variable: sleep
After some reading, apparently I can't use angular-scenario with Jasmine. Ok, I'm cool with that.
UPDATE : Per the comments, I tested my "working" settimeout method. It doesn't ever get called.
So this works:... flag = false; timer = new Timer(1000); timer.handler = function () { flag = true }; expect(flag).toBe(false); setTimeout(function () { expect(flag).toBe(true) }, 2000); ...
But feels a little weird.Question: Is there a better way?
Fun Trivia: Yep, I know about $timeout. I have Very Good Reasons(TM) for doing the things I did deep in the code mines, away from the light of day =)
-
Sir Robert over 10 yearsThis is the right answer. Michael answered first in the comments above, but if he doesn't provide an answer soonishly, I'll accept yours as correct. Thanks =)
-
John Haugeland about 9 years"I'll leave it as an exercise for the reader to figure out why I did it this way =)" It would be nice if you'd finish explaining.
-
Thomas Kekeisen about 8 years
setTimeout(function () {expect(flag).toBe(true)}), 1100);
should besetTimeout(function () {expect(flag).toBe(true)}, 1100);
- works great! :-)