Reputation: 4845
I have the following controller in my Angular application.
m = angular.module "myapp.dashboards"
m.directive "lkDashboardElement", (
$timeout
MyAppSettings
)->
scope:
dashboard: "="
element: "="
dashboardController: "="
elementLoaded: "&"
link: ($scope, $el)->
if MyAppSettings.shouldCalculateTableWidth
document.addEventListener "dashboard.element.rendered", =>
$timeout(->
..
..
)
I remove a lot of stuff so only the important part shows. The thing that I am having trouble with has to do with my usage of the Angular $timeout. I am currently checking for a certain condition shouldCalculateTableWidth
, and if I see an event fire, I immediately timeout.
Currently I am trying to write a unit test that checks whether $timeout
is being used.
Here is my test:
describe "in a phantomjs context", ->
beforeEach ->
# This sets our Phantom rendering context to true for testing purposes
MyAppSettings._setIsPhantomRendering(true)
afterEach ->
MyAppSettings._setIsPhantomRendering(false)
it "uses $timeout (instead of applyAsync) for adjusting table widths", ->
# Creates a dummy dashboard
dashboardController.queryMap = {1: {view: "foo", model: "bar"}}
dashboard.elements = [{id: 1}]
spyOn($timeout, "flush")
expect($timeout.flush).toHaveBeenCalled()
What I am trying to do is simply test whether $timeout
is being used in this piece of code, since it is important to how certain images are rendered when I am in Phantom (an image rendering library) context. When I run the test, I get the following error:
Expected spy flush to have been called.
The specific issue I have is the following two lines in my test:
spyOn($timeout, "flush")
expect($timeout.flush).toHaveBeenCalled()
First of all, I don't believe I am calling the right method for $timeout
. It's very clear in my controller, I am calling $timeout
, and not $timeout.flush
. Second of all, for Jasmine Spys, you can't just spyOn
the $timeout
, since it needs both a reference to a class and a method.
So I am not quite sure how to move on. I would appreciate any help - thanks!
Upvotes: 1
Views: 1121
Reputation: 1233
When you are writing the unit test, you have to call $timeout.flush()
and then call $timeout.verifyNoPendingTasks();
.
verifyNoPendingTasks()
will throw an exception if there are any pending timeouts, so basically, you can assert that the exception is never thrown like expect(function () {$timeout.verifyNoPendingTasks()}).not.toThrow()
. Also, you can write the expectation as expect(function () {$timeout.flush()}).toThrow()
If in your controller $timeout
has a fixed time like $timeout(function() {}, 1000)
, then in your unit test you can flush
as $timeout.flush(1000)
.
You can read more at here.
Also, you can take a look at the following CodePen for the working example.
Upvotes: 1
Reputation: 6961
If you want to spy on $timeout, you'll need to actually replace it in a module.decorator call with a spy. But you may want to ask yourself if it truly makes sense to micromanage the internals of your directive to that extent.
Upvotes: 0