After quite a while I finally got round to creating version 0.2 of ngImprovedTesting. The
ModuleBuilder API is unchanged and still makes mock testing AngularJS code much easier (be sure to read this blog post if you are unfamiliar with ngImprovedTesting).
Version 0.2 of ngImprovedTesting brings you the following interesting improvements:
- ngModuleIntrospector no longer uses internal AngularJS API.
- mocks can now also be created manually using the (global) “mockInstance” function.
- features a more descriptive way of testing promises by adding the
tick()method to $q.
- offers an module called “ngImprovedTesting” to be able to use $q.tick() in your tests without having to use the ModuleBuilder API (which automatically includes the module).
When testing promises you have to do a
$rootScope.$digest() (digest on child scope won’t work) in order for
.then(...) callbacks (i.e. after a Deferred#resolve(…)) to be actually invoked:
Having to call
$rootScope.$digest() isn’t too descriptive and also has some possibly (unwanted) side effects since all scopes will now be $digest-ed (possibly triggering $watch callbacks). After investigating the AngularJS source-code I found out that a
$rootScope.$digest() is necessary since $q (indirectly) does a
$rootScope.$evalAsync(...) to asynchronously execute callbacks (like the promiseSuccessCallback from our sample). Internally AngularJS even uses a function called “nextTick” that takes a callback as its argument and merely delegates to
$rootScope.$evalAsync. Using (the new 0.2 version of) the ngModuleIntrospector we are now able to retrieve the $q provider declaration and alter it:
- so that a fake $rootScope is injected into the $q provider with (only) a $evalAsync method that no longer invokes
$rootScope.$digest()but instead keeps the supplied callback in an internal array.
- $q instances will get a extra “tick()” method that executes all callbacks from the internal array and then clears the internal array.
So, although a very subtle change, you can now rewrite the “when” part of our previous sample:
The altered $q provided is automatically available when:
- using the ngImprovedTesting
ModuleBuilderin your tests
- when using the ‘ngImprovedTesting’ module in your tests:
For backwards compatibility the $q.tick() feature is not enabled at default. Instead it should be enabled by setting the $qTick property to true on the (global) ngImprovedTestingConfig object:
Depending on your needs you can either choose to selectively enable $q.tick() (by selectively adding the code above inside a “describe”) or alternatively to enable it for all your tests by placing it into a seperate file.
You can easily install ngImprovedTesting through Bower using the following command:
bower install ng-improved-testing --save-dev
To be able to use $q.tick() you either must use the ModuleBuilder API or add
'ngImprovedTesting' to the requires of your module.