AngularJS Directives - unit tests Karma coverage - angularjs

I have a problem covering directives unit tests. I used the way from :
http://blog.revolunet.com/blog/2013/12/05/unit-testing-angularjs-directive/ (by Julien Bouquillon)
to create unit tests for my directives. The idea presented on that blog looked great for my needs and well explained, but my issue is that the coverage is not reflected in Karma Coverage(Istanbul code coverage tool).
How should I create my directive unit tests in order to be reflected in coverage summary? Has someone an example that make it possible?

The reason of why you don't see the coverage on the directive code is that, the link you mentioned has used the $compile() and the $digest() called in the beforeEach() through compileDirective() function.
Have that piece of code moved ( the ones that goes into the compileDirective ) into your it() , it should have the coverage done on directive.
Instead of
describe("do some directive testing",function(){
beforeEach(function(){
compileDirective();
});
it('your test code',function(){
//some code here
});
Do the following.
describe("do some directive testing",function(){
beforeEach(function(){
// some other code which execute before each of the it()..
});
it('your test code',function(){
compileDirective();
//some code here
});
So essentially you may have to do some adjustment to your code.

I discovered some issues in my Grunt config file and that's why the coverage wasn't updated. So, the example by Julien Bouquillon is very good and I recommend it.

Related

jasmine test angular.element(document).ready

I have questions concerning how to test the code inside element(document).ready(), during the debug, it seems that the it'll first get to document.ready and then go to the tests and then go inside to the document.ready. I even tried to test in afterEach and find out that the code inside document.ready even happens after the afterEach. Is there any good way to do this kind of test?
I also added the document.ready inside the jasmine tests.
describe('test',function(){
beforeEach(....)
it('test',function(){
angular.element(document).ready(function(){
expect(test).toBe(true);
})
})
})
And in the debug mode it'll goes inside. But when the test runs, it didn't work.
First, I don't think you should use document.ready, because all angular code will execute when document ready as default.
Second, to test this kind of function, you should make the function as a service, then test that service, and in the callback, just call that service.

AngularJS Jamine testing that the broadcast message has been send Only once

I'm trying to test that boradcase message been send only once
expect(rootScope.$broadcast.calls.count()).toEqual(1);
The code itself:
$rootScope.$broadcast("page:done_loading");
So, test does not work. I'm not sure about the syntax. Could you help?
First of all you need to set up a spy (you are not showing much code so not sure if you have already done so).
For example:
Jasmine 2.0: spyOn($rootScope, '$broadcast').and.callThrough();
Jasmine 1.3: spyOn($rootScope, '$broadcast').andCallThrough();
Note that and.callThrough() not might be the correct behavior for the spy in your situation.
Then to verify it was called once:
Jasmine 2.0: expect($rootScope.$broadcast.calls.count()).toEqual(1);
Jasmine 1.3: expect($rootScope.$broadcast.callCount).toEqual(1);
Demo (Jasmine 2.0): http://plnkr.co/edit/4xeZOzxOuYNvvASY8jTM

AngularJS unit test check if function without methods have been called

I'm using Jasmine to unit test my Angular app. It's pretty easy to test if a method of a function has been called using something like:
spyOn($rootScope, "$emit");
expect($rootScope.$emit).toHaveBeenCalled();
But I can't find a way to check when a function has been called (without a method), for e.g. I'm using $anchorScroll(); in one controller and I have no idea where to apply the above code to this guy. I've seen some Jasmine examples where they were using expect(window.myFunction()).toHaveBeenCalled(), but this doesn't work with Angular's DI.
I can't try it myself at the minute but maybe you could just inject a mock $anchorScroll instead?
var $anchorScroll = jasmine.createSpy('anchorScroll');
$controller('MyCtrl', {
$anchorScroll: $anchorScroll
});
expect($anchorScroll).toHaveBeenCalled();
This should just create a blank spy, one which will take any arguments and do nothing but keep track of the calls for test usage.

AngularJS how to unit test to ensure directives like ng-click point to valid code

I'm using Jasmine to write unit tests for our controllers, but wanted to get community feedback on how to handle this situation...
I have a controller - InvoiceController, like this:
angular.module('myModule').controller('myController', ['$scope',
function($scope) {
$scope.doSomething = function() {
$scope.something = 'bar';
};
}
]});
In my unit tests I verify that my controller has the expected methods:
it('should be able to do some work', function() {
// initialize scope properties
scope.someProperty = 'foo';
// load controller using those properties
injectController();
// do I have all of the functions necessary to do this work?
expect(typeof (scope.doSomething)).toBe('function');
// now execute test
scope.doSomething();
expect(scope.something).toBe('bar');
}
And finally, in my html I have an element with an ng-click, like this:
<button ng-click="doSomehing()">Do Something</button>
Looks good, right? BUT, did anyone catch what I did wrong?
My ng-click method is misspelled, but all tests are green and life seems rosy...until I try to click on that guy and nothing happens. No render time error, no error on click. Hmm.
Several times now as I'm refactoring code this has got me. I rename doSomething to doSomethingCooler in the unit test and in the controller but miss a place in the html. After a minute of head scratching I see what was missed.
I'd love a way to ensure that the markup is valid. E2E tests seem to be the obvious solution, but those are prone to fragility so we are hoping there are some alternatives.
If this were ASP.Net I would attach the click events from code behind so that I would get compile time errors vs run time errors.
Thoughts??
Thad
One thing you could do is get the template text and run $compile on it. And then link it to your controller's scope. Then you could do something like dom.find('[ng-click]').click();, which should throw if any of them is not defined in your controller's scope. This is similar to how you generally test directives.

How to test AngularJS directives

I am working on a Rails 3.2 app that will be using AngularJS. I can get Angular to do what I need, but I am having a very difficult time figuring out how to test what I'm doing. I am using guard-jasmine to run Jasmine specs using PhantomJS.
Here is the (relevant) html:
<html id="ng-app" ng-app="app">
<div id="directive-element" class="directive-element">
</div>
</html>
The javascript (in coffeescript) looks like:
window.Project =
App: angular.module('app', [])
Directive: {}
Project.Directive.DirectiveElement =
->
restrict: 'C'
link: (scope, element, attrs) ->
element.html 'hello world'
Project.App.directive 'directiveElement', Project.Directive.DirectiveElement
The code above does exactly what it is intended to do. The tests are the problem. I can't get them to work at all. This is one thing I had tried. Posting this is mostly just to start the conversation somewhere.
describe 'App.Directive.DirectiveElement', ->
it 'updates directive-element', ->
inject ($compile, $rootScope) ->
element = $compile('<div id="app" ng-app="app"><div id="directive'element" class="directive-element"></div></div>')
expect(element.text()).toEqual('hello world')
As an aside, I am new to AngularJS, so if there are any best practices regarding namespacing, modules, etc. that I am not following, guidance would be appreciated.
How do I get a test for this to work?
Here's how alert directive is tested in angular-ui/bootstrap.
Here's another simple set of tests, for the buttons directive.
Here are a few tips:
Be sure to tell the test runner what module you are testing with beforeEach(module('myModule')).
If you have external templateUrls in your directives, you'll want to somehow pre-cache them for the test runner. The test runner can't asynchronously GET templates. In bootstrap, we inject the templates into the javascript with a build step, and make each template a module. We use grunt-html2js grunt task.
In your tests, use the inject helper in a beforeEach to inject $compile and $rootScope and any other services you'll need. Use var myScope = $rootScope.$new() to create a fresh scope for each test. You can do var myElement = $compile('<my-directive></my-directive>')(myScope); to create an instance of your directive, and have access to its element.
If a directive creates its own scope and you want to test against it, you can get access to that directive's scope by doing var directiveScope = myElement.children().scope() - It will get the element's child (the directive itself), and get the scope for that.
For testing timeouts, you can use $timeout.flush() to end all pending timeouts.
For testing promises, remember that when you resolve a promise, it will not call its then callbacks until the next digest. So in tests you have to do this a lot: deferred.resolve(); scope.$apply();.
You can find tests for directives of varying complexity in the bootstrap repo. Just look in src/{directiveName}/test/.
Angular Test Patterns may help you, there are examples in both coffeescript and javascript.
Here's a testing pattern to verify the example directive is rendering the expected output.

Resources