I'm using AngularJS and trying to test a controller that calls a factory to get some data.
This is the controller code:
'use strict'
angular.module('AngularApp')
.controller 'IndexCtrl', ($scope, session, navigation) ->
session.find().then (response) ->
$scope.session = response.data
$scope.someOtherVariable = {}
Naturally, I'd like to swap the factory with a mock to prevent calling a real API. I'm trying to use $provide.factory to inject the mock copy:
'use strict'
describe 'Controller: IndexCtrl', ->
# load the controller's module
beforeEach module 'mosaicAdminWebClientApp'
beforeEach module ($provide) ->
$provide.factory 'session', ->
true
IndexCtrl = {}
scope = {}
# Initialize the controller and a mock scope
beforeEach inject ($controller, $rootScope) ->
scope = $rootScope.$new()
IndexCtrl = $controller 'IndexCtrl', {
$scope: scope
}
it 'should attach a list of awesomeThings to the scope', ->
expect(true).toBe true
When running this test with Karma, I guess this error:
Chrome 32.0.1700 (Mac OS X 10.9.1) Controller: IndexCtrl should attach a list of awesomeThings to the scope FAILED
Error: [ng:areq] Argument 'fn' is not a function, got Object
http://errors.angularjs.org/1.2.10-build.2176+sha.e020916/ng/areq?p0=fn&p1=not%20a%20function%2C%20got%20Object
at /Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:78:12
at assertArg (/Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:1363:11)
at assertArgFn (/Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:1373:3)
at annotate (/Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:3019:5)
at Object.invoke (/Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:3685:21)
at /Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:3554:71
at Array.forEach (native)
at forEach (/Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:303:11)
at Object.createInjector [as injector] (/Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:3554:3)
at workFn (/Users/blaiz/Documents/some_angular_app/app/bower_components/angular-mocks/angular-mocks.js:2144:52)
Chrome 32.0.1700 (Mac OS X 10.9.1): Executed 10 of 10 (1 FAILED) (0.26 secs / 0.068 secs)
Warning: Task "karma:unit" failed. Use --force to continue.
Aborted due to warnings.
I've tried many different permutation, such as removing the label, passing an object or simple value instead of a function and none of them worked.
The documentation (http://docs.angularjs.org/api/AUTO.$provide) shows that I should call the factory() method with as factory(name, $getFn) where name is a string and $getFn is a function. That's what I'm doing but it's not working.
Anything I've missed? Does anyone know how to properly use $provide in Jasmine unit tests?
Thanks
Update: I found a plunkr similar that solved an issue similar to this one here: stackoverflow.com/questions/19297258/why-is-provide-only-available-in-the-angular-mock-module-function-and-q-onl
I created my own plunkr with this code, but with the test code in JS instead of Coffee and got it to work: plnkr.co/edit/gfBzMXpKdJgPKnoyJy5A?p=preview
Now I manually converted the JS code into Coffee: plnkr.co/edit/qGGMayFjJoeYZyFKPjuR?p=preview The error is back so the coffee code is wrong but the js code works.
Found the answer to my question.
Since CoffeeScript always returns the result from the last statement, in this case, CoffeeScript returns $provide inside of module(), which is wrong. An easy way to fix that is to just manually add a return statement after $provide, like this:
beforeEach module 'mosaicAdminWebClientApp', ($provide) ->
$provide.service 'session', ()->
return
Hope that will help someone else.
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