[angular.js] Jasmine tests with $q

3,397 views
Skip to first unread message

Pawel Kozlowski

unread,
Aug 3, 2012, 5:35:45 PM8/3/12
to ang...@googlegroups.com
Hi!

I'm having trouble making a basic test working with $q promisses:
http://jsfiddle.net/pkozlowski_opensource/Ls8eW/2/
Does anyone have an idea about what is going on here?

The funny thing is that (almost) the same use case works OK when
executed in angular, without Jasmine:
http://jsfiddle.net/pkozlowski_opensource/kjtbb/

I guess I'm missing sth that is obvious but somehow just can't
understand what is going on here....

Cheers,
Pawel

Witold Szczerba

unread,
Aug 3, 2012, 6:21:49 PM8/3/12
to ang...@googlegroups.com
Hi,
take a look at the source code:
https://github.com/angular/angular.js/blob/master/src/ng/q.js

The 'resolve' function does not execute immediately, it schedules
execution using $rootScope.$evalAsync, so you are asserting on a
result too early.

Take a look at the example you have provided:
http://jsfiddle.net/pkozlowski_opensource/kjtbb/
You said it is the funny thing that the example works OK without
Jasmine, but it actually works exactly the same. Look at this:
http://jsfiddle.net/witoldsz/kjtbb/1/

The only thing is: how to defer the assertion in Jasmine...

Regards,
Witold Szczerba
> --
> You received this message because you are subscribed to the Google Groups "AngularJS" group.
> To post to this group, send email to ang...@googlegroups.com.
> To unsubscribe from this group, send email to angular+u...@googlegroups.com.
> Visit this group at http://groups.google.com/group/angular?hl=en.
>
>

Witold Szczerba

unread,
Aug 3, 2012, 7:13:58 PM8/3/12
to ang...@googlegroups.com
Hi again,
here is working code:
http://jsfiddle.net/witoldsz/Ls8eW/4/

As I wrote above, $q uses root scope's $evalAsync to schedule
execution. The only thing I do not get is why does it work only when I
explicitly call $digest on root scope... (last line before final
assert).
Can someone explain, please? The source code of $digest is a little
bit complicated and right now I have nothing but a web browser to read
and analyze it...

The final thought is: should developers be aware that $q delegates to
rootScope.$evalAsync? Isn't that an implementation detail? Maybe it
would be a good idea to add a 'flush' method to $q or deffered objects
in testing environment?

Regards,
Witold Szczerba

Pawel Kozlowski

unread,
Aug 4, 2012, 3:03:55 AM8/4/12
to ang...@googlegroups.com
Hi Witold!

Thnx so much for taking time looking into this. I didn't realize that
'resolve' is called via root scope's $evalAsync, so I've learned
something here!
As often with async stuff it wasn't so obvious for me and I was even
persuaded that my example without Jasmine works in the synchronous
way... So in the end this is just timing issue with Jasmine. I wonder
if we need mock version of $q (with flush()) since calling $digest
will do the trick.

With this new insight I need to go back to the Bogdan's question that
trigger this $q + Jasmine questions for me:
https://groups.google.com/forum/?fromgroups#!topic/angular/N5yBJvl7Pbg

Once again, thnx for your help!

Cheers,
Pawe;

Peter Bacon Darwin

unread,
Oct 22, 2012, 5:32:02 AM10/22/12
to ang...@googlegroups.com
Hi Witold
I was just playing with this situation and your fiddle helps tremendously.
Regarding your question about explicitly calling $digest on root scope:
  • According to this in the docs - http://docs.angularjs.org/guide/concepts - under the heading Runtime, you can see that evaluating the $evalAsync queue is part of the $digest loop.
  • From looking at the src, there is a $evalAsync queue for each scope.
  • Since $q pushes defers to the $rootScope's $evalAsync queue, that is where you have to run the $digest.
Equally, one could have simply called $apply on any scopeto get the same effect.
Pete

ThomasBurleson

unread,
Aug 25, 2013, 11:13:17 AM8/25/13
to ang...@googlegroups.com
@Pete, @Witold,

Last night I ran into this same issue build Jasmine/Karma tests on promised-based services (using Karma and RequireJS).  
Attached is a self-contained, documentd Gist sample: PeopleListControllerSpec.js

While I understand the issue, I think it reveals a bigger concern to me:

What if I had used Q.js or When.js as my Promise-library (instead of AngularJS built-in $q). 
Then I would not have encountered this issue. So the fact that $q works fundamentally different is very worrisome.

- Thomas

ThomasBurleson

unread,
Aug 25, 2013, 11:27:17 AM8/25/13
to ang...@googlegroups.com
I just saw that Igor Minar has a fix in his fork regarding this exact issue.
Should be in the AngularJS v1.2.x master soon....

Jamie @GotNoSugarBaby

unread,
Apr 24, 2014, 7:43:20 AM4/24/14
to ang...@googlegroups.com
Hi all,
I came across this quirk today and documented it on Stack Overflow at Testing immediately resolved $.defer() with Jasmine.

Thanks,

Jamie Mason / @fold_left
Reply all
Reply to author
Forward
0 new messages