Reputation: 4976
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 =)
Upvotes: 8
Views: 12178
Reputation: 498
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 =)
Upvotes: 12