Angular mock fails to inject my module dependencies - angularjs

I want to test an Angular controller for my application fooApp, defined as follow:
var fooApp = angular.module('fooApp', [ 'ngRoute', 'ngAnimate', 'hmTouchEvents' ]);
...
The controller, MainCtrl is defined:
"use strict";
fooApp.controller('MainCtrl', function ($scope, $rootScope, fooService) {
...
}
So I've tested several ways to create a test, like this one:
'use strict';
describe('MainController test', function () {
var scope;
var controller;
beforeEach(function () {
angular.mock.module('ngRoute', []);
angular.mock.module('ngAnimate', []);
angular.mock.module('hmTouchEvents', []);
angular.module('cwfApp', [ 'ngRoute', 'ngAnimate', 'hmTouchEvents' ]);
angular.mock.inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller('MainCtrl', {
$scope: scope
});
});
});
it('should display a list', function () {
console.log('-------------- Run Test 1 | ' + scope);
expect(scope.currentStep).toBe(1);
});
});
and the result:
Error: [$injector:modulerr] http://errors.angularjs.org/1.2.16-build.64+sha.245de33/$injector/modulerr?p0=undefined&p1=Error%3A%20%5Bng%3Aareq%5D%20http%3A%2F%2Ferrors.angularjs.org%2F1.2.16-build.64%2Bsha.245de33%2Fng%2Fareq%3Fp0%3Dfn%26p1%3Dnot%2520a%2520function%252C%2520got%2520undefined%0A%20%20%20%20at%20Error%20(%3Canonymous%3E)%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fapp%2Fbower_components%2Fangular%2Fangular.min.js%3F5961971009303638e9ad386869316e8c83f67e56%3A6%3A471%0A%20%20%20%20at%20wb%20(http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fapp%2Fbower_components%2Fangular%2Fangular.min.js%3F5961971009303638e9ad386869316e8c83f67e56%3A18%3A360)%0A%20%20%20%20at%20Qa%20(http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fapp%2Fbower_components%2Fangular%2Fangular.min.js%3F5961971009303638e9ad386869316e8c83f67e56%3A18%3A447)%0A%20%20%20%20at%20nc%20(http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fapp%2Fbower_components%2Fangular%2Fangular.min.js%3F5961971009303638e9ad386869316e8c83f67e56%3A31%3A191)%0A%20%20%20%20at%20Object.d%20%5Bas%20invoke%5D%20(http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fapp%2Fbower_components%2Fangular%2Fangular.min.js%3F5961971009303638e9ad386869316e8c83f67e56%3A33%3A176)%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fapp%2Fbower_components%2Fangular%2Fangular.min.js%3F5961971009303638e9ad386869316e8c83f67e56%3A32%3A254%0A%20%20%20%20at%20Array.forEach%20(native)%0A%20%20%20%20at%20r%20(http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fapp%2Fbower_components%2Fangular%2Fangular.min.js%3F5961971009303638e9ad386869316e8c83f67e56%3A7%3A298)%0A%20%20%20%20at%20e%20(http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fapp%2Fbower_components%2Fangular%2Fangular.min.js%3F5961971009303638e9ad386869316e8c83f67e56%3A32%3A9)
at Error (<anonymous>)
at d:/dev/foo/app/bower_components/angular/angular.min.js:6:471
at d:/dev/foo/app/bower_components/angular/angular.min.js:32:400
at Array.forEach (native)
at r (d:/dev/foo/app/bower_components/angular/angular.min.js:7:298)
at e (d:/dev/foo/app/bower_components/angular/angular.min.js:32:9)
at Object.$b [as injector] (d:/dev/foo/app/bower_components/angular/angular.min.js:35:98)
at workFn (d:/dev/foo/app/bower_components/angular-mocks/angular-mocks.js:2142:52)
at Object.window.inject.angular.mock.inject [as inject] (d:/dev/foo/app/bower_components/angular-mocks/angular-mocks.js:2133:37)
at null.<anonymous> (d:/dev/foo/test/jasmine/todo.test.js:15:22)
TypeError: Cannot read property 'currentStep' of undefined
at null.<anonymous> (d:/dev/foo/test/jasmine/todo.test.js:25:21)
Chrome 31.0.1650 (Windows 7): Executed 1 of 1 (1 FAILED) ERROR (0.023 secs / 0.015 secs)
I've also tested with beforeEach(angular.mock.module('cwfApp')); (instead of the first beforeEach in the previous code), but the error is almost the same.
Regarding my karma.conf.js file, I set this list of files:
files: [
'app/bower_components/angular/angular.min.js',
'app/bower_components/angular-route/angular-route.min.js',
'app/bower_components/hammerjs/hammer.min.js',
'app/bower_components/angular-hammer/angular-hammer.js',
'app/bower_components/angular-mocks/angular-mocks.js',
'app/js/foo-application.js',
'app/js/foo-controllers.js',
'app/js/foo-services.js',
'app/js/foo-router.js',
'test/jasmine/*.js'
],
The injection seems to fail, but I don't really understand what is missing or wrong in my configuration. The stacktrace above does not give a lot of explanations...
Any idea?
I'm using Angular 1.2.8.
Regards
Edit, with the code provided by #Engineer:
beforeEach(angular.mock.module('fooApp'));
beforeEach(angular.mock.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller('MainCtrl', {
$scope: scope
});
}));
it('should display a list', function () {
console.log('-------------- Run Test 1 | ' + scope);
expect(scope.currentStep).toBe(1);
});
The error is almost the same:
Error: [$injector:modulerr] http://errors.angularjs.org/1.2.16-build.64+sha.245de33/$injector/modulerr?p0=cwfApp&p1=Error%3A%20%5B%24injector%3Amodulerr%5D%20http%3A%2F%2Ferrors.angularjs.org%2F1.2.16-build.64%2Bsha.245de33%2F%24injector%2Fmodulerr%3Fp0%3DngAnimate%26p1%3DError%253A%2520%255B%2524injector%253Anomod%255D%2520http%253A%252F%252Ferrors.angularjs.org%252F1.2.16-build.64%252Bsha.245de33%252F%2524injector%252Fnomod%253Fp0%253DngAnimate%250A%2520%2520%2520%2520at%2520Error%2520(%253Canonymous%253E)%250A%2520%2520%2520%2520at%2520http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fapp%252Fbower_components%252Fangular%252Fangular.min.js%253F5961971009303638e9ad386869316e8c83f67e56%253A6%253A471%250A%2520%2520%2520%2520at%2520http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fapp%252Fbower_components%252Fangular%252Fangular.min.js%253F5961971009303638e9ad386869316e8c83f67e56%253A20%253A260%250A%2520%2520%2520%2520at%2520http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fapp%252Fbower_components%252Fangular%252Fangular.min.js%253F5961971009303638e9ad386869316e8c83f67e56%253A21%253A262%250A%2520%2520%2520%2520at%2520http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fapp%252Fbower_components%252Fangular%252Fangular.min.js%253F5961971009303638e9ad386869316e8c83f67e56%253A32%253A69%250A%2520%2520%2520%2520at%2520Array.forEach%2520(native)%250A%2520%2520%2520%2520at%2520r%2520(http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fapp%252Fbower_components%252Fangular%252Fangular.min.js%253F5961971009303638e9ad386869316e8c83f67e56%253A7%253A298)%250A%2520%2520%2520%2520at%2520e%2520(http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fapp%252Fbower_components%252Fangular%252Fangular.min.js%253F5961971009303638e9ad386869316e8c83f67e56%253A32%253A9)%250A%2520%2520%2520%2520at%2520http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fapp%252Fbower_components%252Fangular%252Fangular.min.js%253F5961971009303638e9ad386869316e8c83f67e56%253A32%253A86%250A%2520%2520%2520%2520at%2520Array.forEach%2520(native)%0A%20%20%20%20at%20Error%20(%3Canonymous%3E)%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fapp%2Fbower_components%2Fangular%2Fangular.min.js%3F5961971009303638e9ad386869316e8c83f67e56%3A6%3A471%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fapp%2Fbower_components%2Fangular%2Fangular.min.js%3F5961971009303638e9ad386869316e8c83f67e56%3A32%3A400%0A%20%20%20%20at%20Array.forEach%20(native)%0A%20%20%20%20at%20r%20(http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fapp%2Fbower_components%2Fangular%2Fangular.min.js%3F5961971009303638e9ad386869316e8c83f67e56%3A7%3A298)%0A%20%20%20%20at%20e%20(http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fapp%2Fbower_components%2Fangular%2Fangular.min.js%3F5961971009303638e9ad386869316e8c83f67e56%3A32%3A9)%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fapp%2Fbower_components%2Fangular%2Fangular.min.js%3F5961971009303638e9ad386869316e8c83f67e56%3A32%3A86%0A%20%20%20%20at%20Array.forEach%20(native)%0A%20%20%20%20at%20r%20(http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fapp%2Fbower_components%2Fangular%2Fangular.min.js%3F5961971009303638e9ad386869316e8c83f67e56%3A7%3A298)%0A%20%20%20%20at%20e%20(http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fapp%2Fbower_components%2Fangular%2Fangular.min.js%3F5961971009303638e9ad386869316e8c83f67e56%3A32%3A9)
at Error (<anonymous>)
at d:/dev/foo/app/bower_components/angular/angular.min.js:6:471
at d:/dev/foo/app/bower_components/angular/angular.min.js:32:400
at Array.forEach (native)
at r (d:/dev/foo/app/bower_components/angular/angular.min.js:7:298)
at e (d:/dev/foo/app/bower_components/angular/angular.min.js:32:9)
at Object.$b [as injector] (d:/dev/foo/app/bower_components/angular/angular.min.js:35:98)
at workFn (d:/dev/foo/app/bower_components/angular-mocks/angular-mocks.js:2142:52)
TypeError: Cannot read property 'currentStep' of undefined
at null.<anonymous> (d:/dev/foo/test/jasmine/todo.test.js:20:21)
I will try to create a fiddle to reproduce my problem...

My problem was in fact due to a little mistake in karma.conf.js. Indeed, my application is defined as follow:
var fooApp = angular.module('fooApp', [ 'ngRoute', 'ngAnimate', 'hmTouchEvents' ]);
and my karma.conf.js loads the following scripts:
files: [
'app/bower_components/angular/angular.min.js',
'app/bower_components/angular-route/angular-route.min.js',
'app/bower_components/hammerjs/hammer.min.js',
'app/bower_components/angular-hammer/angular-hammer.js',
'app/bower_components/angular-mocks/angular-mocks.js',
'app/js/foo-application.js',
'app/js/foo-controllers.js',
'app/js/foo-services.js',
'app/js/foo-router.js',
'test/jasmine/*.js'
], ...
but the module ngAnimate was not loaded. So I just added that line:
'app/bower_components/angular-animate/angular-animate.min.js',
and it works!

You are redefining fooApp module in the test.
You need to load it with Angular in the test code like this:
angular.mock.module('ngRoute', 'ngAnimate', 'hmTouchEvents', 'fooApp');

Try like this:
describe('MainController test', function () {
var scope;
var controller;
beforeEach(angular.mock.module('fooApp'));
beforeEach(angular.mock.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller('MainCtrl', {
$scope: scope
});
});
it('should display a list', function () {
console.log('-------------- Run Test 1 | ' + scope);
expect(scope.currentStep).toBe(1);
});
});
The thing, you need to understand, is if you declare some module with its dependencies(like angular.module('fooApp', [ 'ngRoute', 'ngAnimate', 'hmTouchEvents' ])), when you inject the module(fooApp) on your tests, you don't need to inject the dependency modules either.

Related

Angular Unit Testing Factory Injection

I've seen this answered but none of the solutions are working for me. I'm getting an error Error: [ng:areq] Argument 'fn' is not a function, got undefined which is causing my test to fail. What's the correct way to inject a factory into a test spec that isn't a stubbed factory.
login module
angular.module('loginModule', ['ui.bootstrap', 'permission', 'ui.router', 'coreModule', 'utilsModule']);
login controller
(function(){
'use strict';
angular.module('loginModule')
.controller('loginController', login);
login.$inject = [
'$log',
'$uibModal',
'$rootScope',
'storageFactory',
'loginFactory',
'$state',
'RoleStore',
'PermissionStore',
'vsmsCoreFactory'
];
function login($log, $uibModal, $rootScope, storageFactory, loginFactory, $state, RoleStore, PermissionStore, vsmsCoreFactory) {
/* jshint validthis: true */
var vm = this;
vm.loginUser = loginUser;
vm.forgotPassword = forgotPassword;
vm.errorCode = null;
PermissionStore.clearStore();
vsmsCoreFactory.getHashFunction()
.then(function(response) {
if(response) {
storageFactory.setHashFunction(response); // unknown provider
}
});
function loginUser() {
...
login controller spec
describe('loginController', function() {
var $controller;
beforeEach(module('loginModule'));
beforeEach(inject(function(_$controller_){
$controller = _$controller_;
}));
describe('vm.loginUser', function() {
it('should be defined', function() {
var loginController = $controller('loginController');
expect(loginController.loginUser).toBeDefined();
});
});
});
unit test files
'use strict';
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var wiredep = require('wiredep');
var paths = gulp.paths;
function runTests (singleRun, done) {
var bowerDeps = wiredep({
directory: 'bower_components',
exclude: ['bootstrap-sass-official'],
dependencies: true,
devDependencies: true
});
var testFiles = bowerDeps.js.concat([
'./src/components/scripts/ui-bootstrap-custom-tpls-2.1.3.js',
'./src/app/index.js',
'./src/{app,components}/**/*.module.js',
'./src/{app,components}/**/*.factory.js',
'./src/{app,components}/**/*.controller.js',
'./src/{app,components}/**/*.spec.js'
]);
gulp.src(testFiles)
.pipe($.karma({
configFile: 'karma.conf.js',
action: (singleRun)? 'run': 'watch'
}))
.on('error', function (err) {
// Make sure failed tests cause gulp to exit non-zero
throw err;
});
}
gulp.task('test', function (done) { runTests(true /* singleRun */, done) });
gulp.task('test:auto', function (done) { runTests(false /* singleRun */, done) });
app
'use strict';
angular.module('fotaAdminPortal',
[
'ngAnimate',
'ngCookies',
'ngTouch',
'ngSanitize',
'ngResource',
'ui.bootstrap',
'ui.router',
'ui.router.stateHelper',
'pascalprecht.translate',
'utilsModule',
'loginModule',
...
])
log
Chrome 54.0.2840 (Mac OS X 10.11.6) loginController vm.loginUser should be defined FAILED
Error: [$injector:unpr] Unknown provider: storageFactoryProvider <- storageFactory <- loginController
The fotaAdminPortal module isn't loaded for the test so vsmsCoreFactory never gets registered.
Also there's no need to manually pass services into a controller as the injector will automatically do this when you create it. Passing services manually is useful when you need to pass something that isn't a globally registered service ie $scope or mock a service for a single controller instance.
Atm the mocks for the factories are just an undefined variable which will cause errors when the logic depending on them tries to call the methods that don't exist. You'll need to properly stub any methods on these mocks. But leaving those aside for the moment your test should be something like:
describe('loginController', function() {
var $controller;
beforeEach(module('fotaAdminPortal'));
beforeEach(inject(function(_$controller_){
$controller = _$controller_;
}));
describe('vm.loginUser', function() {
it('should be defined', function() {
var loginController = $controller('loginController');
expect(loginController.loginUser).toBeDefined();
});
});
});
If you want to load loginModule in isolation then you need to extract vsmsCoreFactory into another module and add that as a dependency:
angular.module('vsmsCore', [])
.factory('vsmsCoreFactory', function($http, env, $log, storageFactory) {
});
angular.module('loginModule', ['ui.bootstrap', 'permission', 'ui.router', 'vsmsCore']);
Then you can do beforeEach(module('loginModule')) instead

"before each" hook: workFn error

I am running my tests with karma and phantom, Also I'm using mocha and sinon and tests are getting failed with below error:
EditResourceCategoryDialogTest EditResourceCategoryDialogController "before each" hook: workFn
Error: [$injector:modulerr] http://errors.angularjs.org/1.4.9/$injector/modulerr?p0=resourceofferingsApp&p1=Error%3A%20%5B%24injector%3Amodulerr%5D%20
Sample code:
define(function (require) {
"use strict";
var assert = require('chai').assert;
var sinon = require('sinon');
var angular = require('angular');
var angularMocks = require('angular.mocks');
require('resourceofferings/app');
require('dialog path');
describe('EditResourceCategoryDialogTest', function () {
beforeEach(module('resourceofferingsApp'));
describe('EditResourceCategoryDialogController', function () {
var $scope, ctrl;
//you need to inject dependencies first
beforeEach(inject(function ($rootScope, $injector) {
$scope = $rootScope.$new();
}));
it('initialization test (create mode)', inject(function ($controller) {
ctrl = $controller("EditResourceCategoryDialogController", {
$scope: $scope,
$uibModalInstance: null,
options: {
isEditMode: false
}
});
assert.equal($scope.isEditMode, false);
}));
});
});
});
Its exactly getting failed here:
beforeEach(inject(function ($rootScope, $injector) {
$scope = $rootScope.$new();
}));
Please help me to fix this issue..
Thanks in advance.
Try this ...
describe('controllers', function(){
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new(); // this is what you missed out
controller = $controller('EditResourceCategoryDialogController', {
$scope: scope,
$uibModalInstance: null,
options: {
isEditMode: false
}
});
}));
});
Update: According to Angular ...
A common reason why the module fails to load is that you've forgotten
to include the file with the defined module or that the file couldn't
be loaded.
Are you sure all needed files are loaded?

How to access angular app module that is defined in self invoke?

I want use unit test in angular, but the webapp that I working on it is created on its owe structure. for example :
(function() {
'use strict';
angular
.module('app', [
'ngAnimate',
'ui.load',
'ui.jp',
'oc.lazyLoad'
]);})();
And one of its controllers :
(function() {
'use strict';
angular
.module('app')
.controller('EditorCtrl', EditorCtrl);
function EditorCtrl($scope) {
var vm = $scope;
vm.options = {
toolbar: [
['style', ['bold', 'italic', 'underline', 'clear']],
]
};
}})();
And I have no idea how to use unit test to this app because my test cant find controller.
This is my controller and test :
(function () {
'use strict';
angular
.module('app')
.controller('DashboardCtrl', dashboard);
describe('test dashboard', function () {
beforeEach(module('DashboardCtrl'));
var $controller;
beforeEach(inject(function (_$controller_) {
$controller = _$controller_;
}));
describe('sum', function () {
it('1 + 1 should equal 2', function () {
var $scope = {};
var controller = $controller('DashboardCtrl', {$scope: $scope});
$scope.x = 1;
$scope.y = 2;
$scope.sum();
expect($scope.z).toBe(3);
});
it('z should default to zero', function () {
var $scope = {};
var controller = $controller('DashboardCtrl', {$scope: $scope});
expect($scope.z).toBe(0);
});
});
});
function dashboard($scope) {
$scope.name = 'Dashboard';
$scope.z = 0;
$scope.sum = function () {
$scope.z = $scope.x + $scope.y;
};
}
})();
And in karma test show me this error :
Error: [$injector:modulerr] Failed to instantiate module DashboardCtrl due to:
Error: [$injector:nomod] Module 'DashboardCtrl' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
That indicate that cant find "DashboardCtrl" controller.
the problem solved by add all modules in files options of karma.conf.js
the point is event lake of one of modules that are injected is main module that here is app stop your test, so addition to include your controller you need to add all module are mentioned.
When unit testing use $controller for getting a handle on a controller instance https://docs.angularjs.org/api/ng/service/$controller like var ctrlToTest = $controller('EditorCtrl')(newTestScope); To create a new test scope you can use var newTestScope = $rootScope.$new()

Can't instantiate angular controller in karma unit tests

I'm facing some trouble with a generated project (by yoeman) and it's testing.
What I want is to build a fully automated testing environement. I use Gulp, Karma, Jasmine and angular-mocks.
TypeError: undefined is not an object (evaluating 'controller.awesomeThings')
In my console after 'gulp test' it throws this error message. but this doesn't make any sense for me.
Look at my test spec:
'use strict';
describe('Controller: AboutCtrl', function() {
// load the controller's module
beforeEach(function() {
module('evoriApp');
});
var controller;
var scope;
// Initialize the controller and a mock scope
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope.$new();
controller = $controller('AboutCtrl', {
'$scope': scope
});
}));
it('should attach a list of awesomeThings to the scope', function() {
console.log(controller);
expect(controller.awesomeThings.length).toBe(3);
});
});
And karma should have any file it needs (karma.conf.js):
files: [
// bower:js
'bower_components/angular/angular.js',
'bower_components/angular-animate/angular-animate.js',
'bower_components/angular-aria/angular-aria.js',
'bower_components/angular-cookies/angular-cookies.js',
'bower_components/angular-messages/angular-messages.js',
'bower_components/angular-resource/angular-resource.js',
'bower_components/angular-route/angular-route.js',
'bower_components/angular-sanitize/angular-sanitize.js',
'bower_components/angular-material/angular-material.js',
// endbower
'app/scripts/**/*.js',
'test/mock/**/*.js',
'test/spec/**/*.js'
],
This is how the generated gulp method looks like:
gulp.task('test', ['start:server:test'], function () {
var testToFiles = paths.testRequire.concat(paths.scripts, paths.mocks, paths.test);
return gulp.src(testToFiles)
.pipe($.karma({
configFile: paths.karma,
action: 'watch'
}));
});
I don't know where the failure is. I checked all paths and rewrote the testfiles multiple times... But the error doesn't change.
Does anybody have an idea, what the error could be caused by?
Ok guys, I got it.
I tried to run the test in the jasmine standalone environement to minimies the area where the error root is.
This is what my controller looks like:
angular.module('evoriApp')
.controller('AboutCtrl', function ($scope) {
$scope.awesomeThings = [
'HTML5 Boilerplate',
'AngularJS',
'Karma'
];
$scope.testVariable = 2;
});
I rewrote the 'this.awesomeThings' to '$scope.awesomeThings' and didn't get it, that this is something different. Whatever...
This is the now running spec:
describe('Controller: AboutCtrl', function() {
// load the controller's module
beforeEach(function() {
module('evoriApp');
console.log("1");
});
var controller;
var scope;
// Initialize the controller and a mock scope
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope.$new();
controller = $controller('AboutCtrl', {
$scope: scope
});
}));
it('sollte instanziert worden sein', function() {
expect(controller).toBeDefined();
});
it('sollte ein Object "awesomeThings" besitzen', function() {
expect(scope.awesomeThings).toBeDefined();
});
it('should attach a list of awesomeThings to the scope', function() {
expect(scope.awesomeThings.length).toBe(3);
});
});
What I learned: In a test you have to generate the scope, which you pass to the controller, by yourself and afterward you got to use the passed scope variable for $scope.variables.

Service Injection to test controller jasmin

Newest Update
My service or factory can still not be found.
'use strict';
/* jasmine specs for controllers go here */
describe("Backpage Controller", function(){
describe('Root Ctrl', function() {
var scope, ctrl, myService;
beforeEach(module("backpageApp"));
beforeEach(inject(function(Data, $controller, $rootScope) {
myService = Data;
scope = $rootScope.$new();
ctrl = $controller("RootCtrl", {$scope:scope});
}));
it('should set the default value of orderProp model', function() {
expect(scope.orderProp).toBe('rent')
});
it('should create "listings" model with 10 listings', function() {
expect(myService.listings.length).toBe(10)
});
});
});
This is the newest error.
Chrome 32.0.1700 (Mac OS X 10.8.4) Backpage Controller Root Ctrl should create "listings" model with 10 listings FAILED
TypeError: Cannot read property 'length' of undefined
at null.<anonymous> (/Users/judyngai/Desktop/Jan2014/newback/trynewversion/minibackpage/test/unit/controllersSpec.js:24:32)
Chrome 32.0.1700 (Mac OS X 10.8.4): Executed 2 of 2 (1 FAILED) (0.284 secs / 0.058 secs)
my services.js file contain this, I am using the angular seed project.
angular.module('backpage.services', [])
.factory('Data', function($resource) {
return $resource('data/data.json');
});
my app.js file is this
var backpageApp = angular.module('backpageApp', ['ui.router', 'ngResource', 'ngRoute','backpage.services', 'backpagecontrollers']);
I am very new to angular js. I am trying to write a jasmin spec that test my RootCtrl.
I created a service to share between controllers
angular.module('backpage.services', [])
.factory('Data', function($resource) {
return $resource('data/data.json');
});
I injected the module above to my application level module.
The RootCtrl has a 'Data' parameter given to its function so the scope object can access the shared data.json fetched by $resource.
I set this to the Data in the Root Ctrl
$scope.listings = Data.query();
Now I am having trouble figuring out how to inject the service I created to my spec written in jasmin.
My Jasmin file currently looks something like this
describe("Backpage Controller", function(){
describe('Root Ctrl', function() {
var scope, ctrl;
beforeEach(module("backpageApp"));
var $injector = angular.injector(['backpageApp']);
var myService = $injector.get('backpage.services');
beforeEach(inject(function($controller, $httpBackend) {
scope = {};
ctrl = $controller("RootCtrl", {$scope:scope});
}));
it('should set the default value of orderProp model', function() {
expect(scope.orderProp).toBe('rent')
});
it('should create "listings" model with 10 listings', function() {
expect(myService.listings.length).toBe(10)
});
});
});
I am currently getting this error when I run the jasmin test
Chrome 32.0.1700 (Mac OS X 10.8.4) Backpage Controller Root Ctrl encountered a declaration exception FAILED
Error: [$injector:unpr] Unknown provider: backpage.servicesProvider <- backpage.services
I have taken a look at the testing examples on angular js official documentation, the sample uses
$httpBackend
in the jasmin code to grab the json file but the $httpBackend doc says its use with $http service but I am using resource.
Also the data.json contain 10 listings of advertisements.
any help is appreciated.
When you run beforeEach(module("backpageApp")); angular-mocks loads all the dependencies automatically and allow you to inject them as in regular applications (not tests)
You also need to create a scope with $rootScope:
var scope, ctrl, myService;
beforeEach(module("backpageApp"));
beforeEach(inject(function(Data, $controller, $httpBackend, $rootScope) {
myService = Data;
scope = $rootScope.$new();
ctrl = $controller("RootCtrl", {$scope:scope});
}));
I figured it out I should just use $httpBackend from angular js to fetch the data.json file.
I have this as a variable httpBackend
I injected this into $httpBackend
httpBackend.when('GET', 'data/data.json').respond([{id: 1 }, {id: 2}, {id:3}, {id:4}, {id:5}, {id:6}, {id:7}, {id:8}, {id:9}, {id:10}]);
and flush it back out
httpBackend.flush();
for testing purposes

Resources