testing using karma failed : Module app is not available - javascript

I've included 3 files in my karma config : 1. angular.js, angular-mock.js, and login.spec.js
this is my login.spec.js:
describe("Hello World example", function() {
beforeEach(module("app"));
var loginCtrl,
scope;
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
loginCtrl = $controller('loginCtrl', {
$scope: scope
});
}));
it('says hello world!', function () {
expect(scope.hello).toEqual("Hello");
});
});
so my login.js (controller) look like this
angular.module('app')
.controller('loginCtrl', function($scope, $rootScope, $location) {
$scope.hello = 'hello';
});
but I got Module 'app' is not available!

I don't see you creating the app module anywere. You should include the app.js and all the sources your tests need to your karma.json as well.

You just need to add this line to the top of your login.js file:
This declares the module:
angular.module('app', []);
This gets an instance of the module(as you are doing):
angular.module('app')
.controller('loginCtrl', function($scope, $rootScope, $location) {
$scope.hello = 'hello';
});
Here is a working Plunkr that is very similar:
http://embed.plnkr.co/O1otV47VxsIL5krAdUW0/preview
You also mentioned that you had added 3 files to the karma config and didn't mention the login.js. That will also need to be added.

Related

Karma/Jasmine Testing Angular with Controller Module

I'm trying to test my app, which has each controller defined on it's own module i.e., not as a controller of the app module, and then loaded as a dependency of the main app module. When I try to run a test that just checks that the loginController is defined, using Karma/Jasmine, I get the following output:
'Expected undefined to be defined.'
edit
I updated login.controller.spec and switched the karma browser to chrome, which gave me more useful debug info. Now I'm getting an error related to a factory that is added to $httpProvider.interceptors in the main app file:
Unknown provider: authFactoryProvider <- authFactory <- $http <- $translateStaticFilesLoader <- $translate
I found similar issues related to this which were resolved by including angular-translate-loader-static-files.js, which is being loaded when karma runs:
DEBUG [web-server]: serving (cached): /path/to/my/app/bower_components/angular-translate-loader-static-files/angular-translate-loader-static-files.js
How do I resolve all these dependency issues with karma?
index.js
'use strict';
angular.module('app',
[
//'mockBackend', //uncomment when loading mock backend
'ngAnimate',
'ngCookies',
'ngTouch',
'ngSanitize',
'ngResource',
'ui.bootstrap',
'ui.router',
'ui.router.stateHelper',
'pascalprecht.translate',
'utilsModule',
'loginModule',
'vsmsPackageModule',
'vsmsCampaignModule',
'vdmsCampaignModule',
'vdmsDashboardModule',
'daterangepicker',
'ui.event',
'idmAdminModule',
'helpdeskModule',
'ncy-angular-breadcrumb',
'rzModule',
'vsmsDashboardModule',
'highcharts-ng',
'permission',
'dndLists'
])
.config(function ($stateProvider, $urlRouterProvider, $httpProvider, $locationProvider, $translateProvider, $breadcrumbProvider, $compileProvider) {
$urlRouterProvider.otherwise('/');
//initialize get if not there
if (!$httpProvider.defaults.headers.get) {
$httpProvider.defaults.headers.get = {};
}
//disable IE ajax request caching
$httpProvider.defaults.headers.get['If-Modified-Since'] = 'Mon, 26 Jul 1997 05:00:00 GMT';
// extra
$httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache';
$httpProvider.defaults.headers.get['Pragma'] = 'no-cache';
$locationProvider.html5Mode({
enabled: false,
requireBase: false
});
$translateProvider.useSanitizeValueStrategy('sanitize');
$translateProvider.useStaticFilesLoader({
prefix: '/locales/',
suffix: '.json'
});
$translateProvider
.preferredLanguage('en_us')
.fallbackLanguage('en_us');
$breadcrumbProvider.setOptions({
templateUrl: 'components/templates/breadcrumb.tpl.html'
});
$compileProvider.debugInfoEnabled(false);
// $compileProvider.aHrefSanitizationWhitelist(/^\s*(|blob|):/);
$httpProvider.interceptors.push('authFactory');
$httpProvider.interceptors.push('headersFactory');
})
login.module.js
angular.module('loginModule', []);
login.controller.js
angular.module('loginModule')
.controller('loginController', login);
login.$inject = [
'$log',
'$uibModal',
'$rootScope',
'storageFactory',
'loginFactory',
'$state',
'RoleStore',
'PermissionStore'
];
function login($log, $uibModal, $rootScope, storageFactory, loginFactory, $state, RoleStore, PermissionStore) {
/* jshint validthis: true */
var vm = this;
vm.loginUser = loginUser;
vm.forgotPassword = forgotPassword;
vm.errorCode = null;
PermissionStore.clearStore();
function loginUser() {
...
I'm just trying to test if the controller exists and I can't get past the error:
Expected undefined to be defined.
login.controller.spec.js
describe('loginController', function() {
beforeEach(module('app'));
var $controller,
$scope,
$log,
$uibModal,
$rootScope,
storageFactory,
loginFactory,
$state,
RoleStore,
PermissionStore,
vsmsCoreFactory;
beforeEach(inject(function(_$controller_, _$log_, _$uibModal_, _$rootScope_, _storageFactory_, _loginFactory_, _$state_, _RoleStore_, _PermissionStore_, _vsmsCoreFactory_){
$controller = _$controller_;
$scope = $rootScope.new();
$log = _$log_;
$uibModal = _$uibModal_;
$rootScope = _$rootScope_;
storageFactory = _storageFactory_;
loginFactory = _loginFactory_;
$state = _$state_;
RoleStore = _RoleStore_;
PermissionStore = _PermissionStore_;
vsmsCoreFactory = _vsmsCoreFactory_;
}));
describe('vm.loginUser', function() {
it('should be defined', function() {
var loginController = $controller('loginController', {
$log: $log,
$uibModal: $uibModal,
$rootScope: $rootScope,
storageFactory: storageFactory,
loginFactory: loginFactory,
$state: $state,
RoleStore: RoleStore,
PermissionStore: PermissionStore,
vsmsCoreFactory: vsmsCoreFactory
});
expect(loginController).toBeDefined();
// expect(testController.model.name).toEqual("controllerAs vm test");
});
});
});
unit-tests.js
'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/app/index.js',
'./src/components/scripts/ui-bootstrap-custom-tpls-2.1.3.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) });
Please refer the the below link it is already answered.
How to inject controller dependencies in Jasmine tests?
loginController dependencies are not passed in your unit test.
The second parameter of $controller is for controller dependencies.
Empty dependency is passed.
$controller('loginController', {});
Make sure all the dependent modules are loaded before testing loginColtroller.
I have modified your code. I hope it will work.
'use strict';
describe('loginController', function() {
beforeEach(module('loginModule'));
var loginController;
beforeEach(inject(function($controller, _$log_, _$uibModal_, _$rootScope_, _storageFactory_, _loginFactory_, _$state_, _RoleStore_, _PermissionStore_ ){
scope = _$rootScope_.$new();
loginController = $controller('loginController',
{ // all dependencies has to be passed in order
'$log' : _$log_,
'$uibModal' : _$uibModal_,
'$rootScope' : _$rootScope_,
'storageFactory' : _storageFactory_,
'loginFactory': _loginFactory_,
'$state': _$state_,
'RoleStore': _RoleStore_,
'PermissionStore': _PermissionStore_
},
{});
}));
it('should be defined', function() {
expect(loginController).toBeDefined();
});
});
The issue is with your login.module.js file.
You'll have to inject ui.bootstrap and ui.router as dependencies while defining the loginModule. Otherwise it will not be able to get $uibModal and $state while defining the loginController.
This should be the definition of your loginModule
angular.module('loginModule', ['ui.bootstrap', 'ui.router']);
PS: I'm assuming here that storageFactory, loginFactory, RoleStore and PermissionStore are defined on loginModule itself.
Hope this helps!

How to create module in angularjs

In all the angularjs tutorials I am gone through. Modules are created as follows
var newApp = angular.module('articles', []);
or
var routerApp = angular.module('routerApp', ['ui.router']);
I started my project with meanjs boiler plate code and controller starts as follows
angular.module('articles').controller('ArticlesController', ['$scope', '$stateParams', '$location', 'Authentication', 'Articles',
function($scope, $stateParams, $location, Authentication, Articles) {
$scope.authentication = Authentication;
.....
.....
]);
When I change it to
var newApp = angular.module('articles',[]);
newApp.controller('ArticlesController', ['$scope', '$stateParams', '$location', 'Authentication', 'Articles',
function($scope, $stateParams, $location, Authentication, Articles) {
$scope.authentication = Authentication;
.....
.....
]);
All the routes of articles stops working. If I want to include a new component into the module, how do I do it. I want to add angularFileUpload in to my module.
Sample code in angularfileupload is
angular
.module('app', ['angularFileUpload'])
.controller('AppController', function($scope, FileUploader) {
$scope.uploader = new FileUploader();
});
How do I add ['angularFileUpload'] if the module is already registered?
Edit:
articles.client.modules.js
'use strict';
// Use Applicaion configuration module to register a new module
ApplicationConfiguration.registerModule('articles');
angular.module("MyModule", []) (with []) is a setter function, that is - it registers a module.
angular.module("MyModule") without [] is a getter function, it retrieves a previously registered module.
Calling a setter twice re-defines the module.
I'm not familiar with meanjs boilerplate, but in all likelihood when you used a setter, you have redefined the module and whatever controllers, services, config, etc... that were previously registered were overwritten.
All you need to do is change what you added to:
var newApp = angular.module("articles");
Example:
angular.module("M", []).controller("A", function(){}); // module M has controller A
angular.module("M").controller("B", function(){}); // module M has controllers A, B
var app = angular.module("M", []); // module M re-registered
app.controller("C", function(){}); // module M has controller C only
// Create a new module
var myModule = angular.module('myModule', []);
// register a new service
myModule.value('appName', 'MyCoolApp');
// configure existing services inside initialization blocks.
myModule.config(['$locationProvider', function($locationProvider) {
// Configure existing providers
$locationProvider.hashPrefix('!');
}]);
Usage
angular.module(name, [requires], [configFn]);

Karma error Argument 'Controller' is not a function, got undefined

I got a problem when I tried to test my controller. When I run my test I got an error
Error: [ng:areq] Argument 'MainCtrl' is not a function, got undefined http://errors.angularjs.org/1.3.8/ng/areq?p0=MainCtrl&p1=not%20a%20function%2C%20got%20undefined
at assertArg (/Users/tetianachupryna/project/bower_components/angular/angular.js:1577)
at assertArgFn (/Users/tetianachupryna/project/bower_components/angular/angular.js:1588)
at /Users/tetianachupryna/project/bower_components/angular/angular.js:8418
at /Users/tetianachupryna/project/src/spec/controllers/main-controller.spec.js:11
at /Users/tetianachupryna/project/src/spec/controllers/main-controller.spec.js:17
at /Users/tetianachupryna/project/node_modules/karma-jasmine/lib/adapter.js:184
at http://localhost:9877/karma.js:185
at http://localhost:9877/context.html:51
I know that SO is full of similar questions. But I'm a total null in Angular and JS in general, so those answers didn't help me. From similar questions on SO I discovered that my problem is in wrong definition of the controller but I still can't figure out what I did wrong. I've stack and I'm begging for your help.
First of all here is my src/app/index.js file where my module is defined
var app = angular.module('myModule', [
'ngAnimate',
'ngSanitize',
'ngResource',
'ui.router',
'pascalprecht.translate',
'thing1',
'thing2']);
Here is src/app/controllers/main-controller.js
angular.module('myModule').controller('MainCtrl', [
'$scope',
'$state',
function ($scope, $state) {
$scope.state = $state;
//***
$scope.isBigStep = function isBigStep() {
return $state.$current.step == 3;
};
}]);
And finally this a file with the test src/spec/controllers/main-controller.spec.js
describe('MainCtrl', function() {
var scope, $state, createController;
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
createController = function() {
return $controller('MainCtrl', {
'$scope': scope
});
};
}));
it('should make 3 as current step', function() {
var controller = createController();
expect(scope.isBigStep()).toBe(true);
});
});
In karma config I have all those files
files: [
'bower_components/angular/angular.js',
'bower_components/angular-mocks/angular-mocks.js',
'src/app/index.js',
'src/app/controllers/*.js',
'src/spec/controllers/*.js'
],
For run my test I use karma-runner plugin in RubyMine.
I'd be thankful for any help!
What you are missing is to add the module in the beforeEach hook for test setup. Otherwise the controller will not be found. So add beforeEach(module('myModule')).
describe('MainCtrl', function() {
var scope, $state, createController;
beforeEach(module('myModule')); //<--- Hook module
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
createController = function() {
return $controller('MainCtrl', {
'$scope': scope
});
};
}));
it('should make 3 as current step', function() {
var controller = createController();
expect(scope.isBigStep()).toBe(true);
});
});

Error initializing controller while testing angularjs with karma

I'm trying to test my application with Karma but I get following Errors:
minErr/<#/home/usr/webui-ng/src/client/app/bower_components/angular/angular.js:78:5
loadModules/<#/home/usr/webui-ng/src/client/app/bower_components/angular/angular.js:3859:1
forEach#/home/usr/webui-ng/src/client/app/bower_components/angular/angular.js:325:7
loadModules#/home/usr/webui-ng/src/client/app/bower_components/angular/angular.js:3824:5
createInjector#/home/usr/webui-ng/src/client/app/bower_components/angular/angular.js:3764:3
workFn#/home/usr/webui-ng/src/client/app/bower_components/angular-mocks/angular-mocks.js:2150:9
These are my files:
hello.js
angular.module('myApp', [])
.controller('MainController', function($scope) {
$scope.name = "Ari";
$scope.sayHello = function() {
$scope.greeting = "Hello " + $scope.name;
}
})
hello.js - test file :
describe('Unit: MainController', function() {
// Load the module with MainController
beforeEach(module('myApp'));
var ctrl, scope;
// inject the $controller and $rootScope services
// in the beforeEach block
beforeEach(inject(function($controller, $rootScope) {
// Create a new scope that's a child of the $rootScope
scope = $rootScope.$new();
// Create the controller
ctrl = $controller('MainController', {
$scope: scope
});
}));
it('should create $scope.greeting when calling sayHello',
function() {
expect(scope.greeting).toBeUndefined();
scope.sayHello();
expect(scope.greeting).toEqual("Hello Ari");
});
});
As you can see, I've already loaded the module, as the solution was in Controller undeclared in Jasmine test.
What else could it be? I haven't found much about these errors on the web. I would be very happy to finally find an answer for that.
As runTarm mentioned, the path in the karma.conf.js was not set to the actual path of the script file (hello.js).

angularjs injector with location service

I am testing some Angular.js code with Jasmine. To do this I need an Angular injector:
var injector = angular.injector(['ng', 'ngRoute', 'mainModule']);
This works fine, but when I get to testing a controller that uses $location, I have to add that to the injector:
var injector = angular.injector(['ng', 'ngRoute', 'location', 'mainModule']);
Now this throws an error:
Error: Error: [$injector:modulerr] Failed to instantiate module location due to:
Error: [$injector:nomod] Module 'location' 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.
How can I include $location service there? Thanks.
-------------- EDIT -----------------
due to not many answers I thought I will add some details.
Here is a controller I am trying to test (or the definition of it, I won't be pasting all code):
var app = angular.module('mainModule');
app.controller('appController', ['$window', '$scope', '$location', '$wsService', '$userService', '$labelService', function ($window, $scope, $location, $wsService, $userService, $labelService) {
//body of the controller
}]);
You have already seen how I create the injector in my unit test in the original post, here is how I use the injector to create the controller:
var scope;
var controller;
var getController = function() {
injector.invoke( ['$rootScope', '$controller', function ($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller('appController', {$scope: scope});
}]);
};
Hope this will help with producing some potential answers. Thanks
To answer my own question. Here is how to test the following controller:
var app = angular.module('mainModule');
app.controller('appController', ['$window', '$scope', '$location', '$userService', function ($window, $scope, $location, $userService) {
//body of the controller
}]);
1 In unit test create injector:
var injector = angular.injector(['ng', 'ngRoute', 'mainModule']);
2 Invoke services required:
injector.invoke( ['$userService', function ($userService) {
service = $userService;
}]);
3 Mock location service:
var mockLocation = {
path : ""
};
I just needed path for the controller I am testing, thus I did not mock anything else, but mock whatever else you need.
4 Invoke the controller:
var scope;
var controller;
var getController = function() {
injector.invoke( ['$rootScope', '$controller', function ($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller('appController', {$scope: scope, $location: mockLocation});
}]);
};
Now the controller can be used in unit tests.
This did get rid of 'unknown provider' and other errors related to location service.
This blog post helped me with an answer, thanks to the author.

Categories

Resources