So I'm new to the whole testing thing (I've been one of those people who has said 'I should write unit tests...' but never ended up ever doing it :-p). I'm now writing unit tests for this project. I'm using testacular + Jasmine, with browserify to compile things. I was having no problems until I started trying to do a lot angular-injection-stuff.
Right now I'm simply trying to do a test of ng-model to get my head around all of it.
I have a testacular.conf file which includes everything necessary:
files = [
'../lib/jquery.js',
'../lib/angular.js',
'./lib/jasmine.js',
'./lib/angular-mocks.js',
JASMINE_ADAPTER,
'./tests.js' //compiled by browserify
];
I have my controller defined (MainCtrl.coffee)
MainCtrl = ($scope, $rootScope) ->
$scope.hello = 'initial'
module.exports = (angularModule) ->
angularModule.controller 'MainCtrl', ['$scope', '$rootScope', MainCtrl]
return MainCtrl
And I have my test itself: (_MainCtrlTest.coffee, in same directory as MainCtrl.coffee)
testModule = angular.module 'MainCtrlTest', []
MainCtrl = require('./MainCtrl')(testModule)
describe 'MainCtrlTest', ->
scope = null
elm = null
ctrl = null
beforeEach inject ($rootScope, $compile, $controller) ->
scope = $rootScope.$new()
ctrl = $controller MainCtrl, $scope: scope
elm = $compile('<input ng-model="hello"/>')(scope)
describe 'value $scope.hello', ->
it 'should initially equal input value', ->
expect(elm.val()).toBe scope.hello
it 'should change when input value changes', ->
scope.$apply -> elm.val('changedValue')
expect(scope.hello).toBe elm.val()
The test fails immediately, with the input's elm.val() returning blank, and scope.hello returning the intended value ('initial', set in MainCtrl.coffee)
What am I doing wrong here?
To get this working, you need to do scope.$apply()
:
it 'should initially equal input value', ->
scope.$apply()
expect(elm.val()).toBe scope.hello
Don't test the framework, test your code
Your test is trying to test whether Angular's binding, and ng-model
works. You should rather trust the framework and test your code instead.
Your code is:
scope.hello
value)You can test the first one very easily, without even touching any DOM. That's the beauty of AngularJS - strong separation of view/logic.
In this controller, there is almost nothing to test, but the initial value:
it 'should init hello', ->
expect(scope.hello).toBe 'initial'
To test the second one (template + binding), you want to do an e2e test. You basically want to test, whether the template doesn't contain any typos in binding etc... So you wanna test the real template. If you inline a different html during the test, you are testing nothing but AngularJS.