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?
AngularJS is written with testability in mind, but it still requires that you do the right thing. We tried to make the right thing easy, but if you ignore these guidelines you may end up with an untestable application.
AngularJS directives are extended HTML attributes with the prefix ng- . The ng-app directive initializes an AngularJS application. The ng-init directive initializes application data. The ng-model directive binds the value of HTML controls (input, select, textarea) to application data.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With