I am currently working on writing a simple test case for the driver script using IIFE(Immediately invoked function expression). Here is my driver script.
driver.js
(function() {
"use strict";
var app = angular
.module("myApp", [
"ui.bootstrap",
"ui.sortable"
]);
}());
Here is my spec driver.spec.js
describe("application configuration tool driver", function() {
it("should create an angular module named myTest", function() {
expect(app).toEqual(angular.module("myApp"));
});
});
When I run my spec using IIFE. I am getting a ReferenceError: app is not defined.
If I run the driver script without IIFE:
var app = angular
.module("myApp", [
"ui.bootstrap",
"ui.sortable"
]);
My spec passes. Any thoughts on passing the spec using IIFE?
You can move app back to the outer scope (if that's an option you can take, of course):
var app;
(function(app) {
"use strict";
app = angular
.module("myApp", [
"ui.bootstrap",
"ui.sortable"
]);
}(app));
Related
I'm in the process of upgrading a legacy app that uses angularjs to the latest LTS release. I seem to have the application working, but i'm struggling with
Error: [$controller:ctrlreg] The controller with the name 'LogoutController' is not registered.
errors in the test environment.
I have an angular module:
angular
.module('LoginModule', ['ui.bootstrap']);
a controller
(function () {
'use strict';
angular
.module("LoginModule")
.controller('LogoutController', LogoutController);
LogoutController.$inject = ['LogoutService'];
function LogoutController(LogoutService) {
this.logout = function () {
LogoutService.logout();
};
}
})();
and a spec
describe('MyApplication', function () {
'use strict';
var ctrl, mockLogoutService;
beforeEach(module('LoginModule'));
beforeEach(function () {
module(function ($provide) {
$provide.factory('LogoutService', function () {
return ({
logout: jasmine.createSpy('LogoutService.logout')
});
});
});
});
describe('LogoutController', function () {
beforeEach(inject(function ($controller, LogoutService) {
mockLogoutService = LogoutService;
ctrl = $controller('LogoutController', {
LogoutService: mockLogoutService
});
}));
it('instantiates', function () {
expect(ctrl).not.toBe(undefined);
});
});
});
When the spec runs, i get
Error: [$controller:ctrlreg] The controller with the name 'LogoutController' is not registered.
The files are in a directory structure like:
- root
-angular
-module
-login
-dialog
-theme
-test
-jasmine
-login
-dialog
-theme
and i configure karma to load files using:
files: [
'./node_modules/angular/angular.js',
'./node_modules/angular-mocks/angular-mocks.js',
'./node_modules/angular-sanitize/angular-sanitize.min.js',
'./node_modules/angular-resource/angular-resource.min.js',
'./node_modules/angular-ui-bootstrap/dist/ui-bootstrap.js',
'./angular/application.js',
'./angular/module/**/*.js',
'./test/jasmine/**/*.js'
],
I ran across Angular controller is not registered error suggesting that the IIFE was problematic, so i tried implementing the accepted answer without joy -- which make sense, as the project has a couple dozen other controllers wrapped in IIFE that all test without needing changes.
So i'm stumped, and am left wondering if i've been starting at the code too long to see something right in front of my face. Looking for any insight into why this code produces the "controller not registered" error.
I've tried several tutorials and looked at many of the solutions provided here. I am new to Angular and currently trying to set up testing for a rather big SPA.
Following this tutorial I have completed:
Angularjs application setup
Karma setup
Our first test
The karma config file is basically the default content, with some references in files and exclude:
// list of files/patterns to load in the browser
files: [
'bower_components/angular/angular.js',
'bower_components/angular-mocks/angular-mocks.js',
'app/app.js',
'JavaScript.spec.js'
],
I reinstalled the entire test implementation and now the simple test works again. But trying to write a test for a controller does not work:
here is the error message
I changed the path referencing the bower_components and app files in the karma config file. Now the shell running karma returns an error message from the app.js file, saying:
Uncaught ReferenceError: Logging is not defined
Writing a test identical to the one from doucmentation, gives the following error:
Here is the test code:
describe('nyKladdController', function () {
beforeEach(module('app'));
var $controller;
beforeEach(inject(function (_$controller_) {
$controller = _$controller_;
}));
describe('$scope.mixTable', function () {
it('is false', function () {
var $scope = {};
var controller = $controller('nyKladdController', { $scope: $scope });
expect($scope.mixTable).toBeFalsy();
});
});
});
As you can see from the error message: after the app module, the test file start loading the app dependencies. Here is the app.js file:
(function () {
'use strict';
angular.module('app', [
'ngAnimate', 'ngRoute', 'ngSanitize', 'ngResource', 'ngMessages',
'AdalAngular', 'config', 'angular.filter',
'ui.bootstrap', 'ui.mask', 'ui.select', 'ui.validate',
'angular-loading-bar', 'ui.tree', 'ui.tree-filter', 'checklist-model'
]);
})();
In other words: how can i get my tests to load the app dependecies as well.
I had to load in all the app dependencies from app.js in to karma.config file. Now the files array in karma config looks like this:
// list of files / patterns to load in the browser
files: [
//bower modules
'./bower_components/angular/angular.js',
'./bower_components/angular-mocks/angular-mocks.js',
'./bower_components/angular-ui-mask/src/mask.js',
'./bower_components/angular-ui-select/dist/select.js',
'./bower_components/angular-ui-tree-filter/dist/angular-ui-tree-filter.js',
'./bower_components/angular-ui-tree/dist/angular-ui-tree.js',
'./bower_components/angular-ui-validate/dist/validate.js',
'./bower_components/angular-loading-bar/build/loading-bar.js',
// node modules
'./node_modules/angular-animate/angular-animate.js',
'./node_modules/angular-route/angular-route.js',
'./node_modules/angular-sanitize/angular-sanitize.js',
'./node_modules/angular-resource/angular-resource.js',
'./node_modules/angular-messages/angular-messages.js',
'./node_modules/adal-angular/dist/adal-angular.min.js',
'./node_modules/angular-filter/dist/angular-filter.js',
'./node_modules/angular-ui-bootstrap/dist/ui-bootstrap.js',
'./node_modules/bower-config/lib/Config.js',
'./node_modules/checklist-model/checklist-model.js',
//app file
'./app/app.js',
'./app/common/config/config.js',
//test files etc..
'JavaScript.spec.js',
'./app/produkt/ny/controllers/*.js' // tester å hente inn controller som refereres i test filen
],
This may be because Karma is loading the source files in the wrong order. For Angular to work properly, each module must be loaded before any component, services, etc. associated with that module.
To fix this, you can change your Karma configuration to ensure your module files are loaded first.
// list of files / patterns to load in the browser
files: [
'../../bower_components/angular/angular.js',
'../../bower_components/angular-mocks/angular-mocks.js',
'app/**/*.module.js',
'app/**/*.js'
],
This is assuming you're using some kind of naming convention for angular modules (like *.module.js as in the above example). Otherwise you'll have to list the paths to the modules individually.
add beforeEach(module("your-module-name")); => your angular application name from app.js"
describe('check a controller', function () {
beforeEach(module("your module name")); // I think you missed this.
var scope, checkController;
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.new();
checkController = function () {
return $controller('nyKladdController', {
'$scope': scope
});
};
}));
it('has a dummy spec to test 2 + 2', function () {
// An intentionally failing test. No code within expect() will never equal 4.
expect(2 + 2).toEqual(4);
});
});
karma.conf
files: [ // sample order. Include your files accordingly
'src/bower_components/angular/angular.min.js',
'src/bower_components/angular-mocks/angular-mocks.js',
// some sample libraries
'src/bower_components/angular-cookies/angular-cookies.min.js',
'src/bower_components/angular-ui-router/release/angular-ui-router.min.js',
'src/bower_components/angular-resource/angular-resource.min.js',
'src/bower_components/angular-sanitize/angular-sanitize.min.js',
'src/bower_components/angular-loading-bar/build/loading-bar.min.js',
'src/app/app.js',
'src/app/**/*.js',
'tests/unit/**/*.spec.js'
],
exclude: []
I create a very small project to test the unit test in AngularJS. The test work until I try to include the dependence restangular. Why it generates conflicts?. Files:
karma.conf.js
files: [
'lib/angular.js',
'lib/angular-route.js',
'lib/angular-mocks.js',
'lib/angular-cookies.js',
'lib/angular-md5.js',
'lib/restangular.js',
'app.js',
'tests/app.spec.js'
]
app.js
var phonecatApp = angular.module('phonecatApp', [
'ngRoute',
'ngCookies',
'angular-md5',
'restangular' //This generate ERROR!
]);
app.spec.js
describe('PhoneListController', function() {
beforeEach(module('phonecatApp'));
beforeEach(module('ngRoute'));
beforeEach(module('angular-md5'));
beforeEach(module('restangular')); //This generate ERROR!
it('should...', inject(function($controller) {
var scope = {};
var ctrl = $controller('PhoneListController', {$scope: scope});
expect(scope.phones.length).toBe(3);
}));
When you trying to load restangular. Then you might be getting error like
Faild to instantiate module restangular due to (_'underscore.js') is undefined. The '_'(undescore) javascript utility library that Restangular uses and depending on it. Include (_'underscore.js') library before the angular js in your template.
Here is your working jsfiddle code please take a look http://jsfiddle.net/chhitij92/x67u4Ldu/ In external resource I Included '_'(undescore) cdn after this its working.
I am using ngMock for unit testing in Angular. I now have a browserify \w Angular setup. I have some strange behaviour. When I just load angular-mocks with require('angular-mocks'); my tests and app work. But if I then load it into my Angular app module as an dependency it does not load my Angular app anymore, but my karma test still works:
(function () {
'use strict';
require('angular');
require('angular-route');
require('angular-mocks');
require('./home');
angular.module('greenboxUi', [
'ngRoute',
//'ngMock',
'greenboxUi.home'
]);
}());
If I uncomment ngMock, my app does not load anymore
My browserify-shim:
'angular-mocks': {
path: './app/bower_components/angular-mocks/angular-mocks.js',
exports: 'angular.mock',
depends: {
angular: 'angular'
}
}
My test:
beforeEach(function(){
module('greenboxUi.home');
inject(function($controller){
controller = $controller('HomeCtrl');
});
});
it('test test', function() {
expect(controller.hello).toBe('Hello world');
});
My app does work when just commenting 'ngMock' out, but I just find it a bit strange because the Angular docs do load it with angular.module('app', ['ngMock']).. Is it because browserify wraps the module somehow?
Kind regards, Niels
In fact, ngMock should not be added to the dependencies of "production" project.
See this github issue for more information : https://github.com/angular/angular.js/issues/12137
I'm trying for the first time to use AngularJS in conjunction with RequireJS using this guide as a basis. As far I can tell after a lot of debugging I'm loading all my modules in the correct order, but when the application runs Angular throws an Error / Exception with the following message:
Argument 'fn' is not a function, got string from myApp
I've seen this message before due to syntax errors, so even though I've looked trough the code multiple times I won't rule out the possibility of a simple syntax error. Not making a Fiddle just yet in case it is something as simple as a syntax error, but I'll of course do so if requested.
Update: I just noticed when setting ng-app="myApp" in the <html> tag I also get an additional error,
No module: myApp
Update II: Okay, it turns out it indeed was an syntax error in the only file not included below. I am though still left with the problem from update I.
RequireJS bootstrap
'use strict';
define([
'require',
'angular',
'app/myApp/app',
'app/myApp/routes'
], function(require, ng) {
require(['domReady'], function(domReady) {
ng.bootstrap(domReady, ['myApp']);
});
});
app.js
'use strict';
define([
'angular',
'./controllers/index'
], function(ng) {
return ng.module('myApp', [
'myApp.controllers'
]);
}
);
controllers/index
'use strict';
define([
'./front-page-ctrl'
], function() {
});
controllers/module
'use strict';
define(['angular'], function (ng) {
return ng.module('myApp.controllers', []);
});
controllers/front-page-ctrl
'use strict';
define(['./module'], function(controllers) {
controllers.
controller('FrontPageCtrl', ['$scope',
function($scope) {
console.log('I\'m alive!');
}
]);
});
Delete ng-app="myApp" from your html.
Because it has bootstrapped manually
ng.bootstrap(domReady, ['myApp']);
RequireJS docs on Dom ready state:
Since DOM ready is a common application need, ideally the nested
functions in the API above could be avoided. The domReady module also
implements the Loader Plugin API, so you can use the loader plugin
syntax (notice the ! in the domReady dependency) to force the
require() callback function to wait for the DOM to be ready before
executing. domReady will return the current document when used as a
loader plugin:
So, when you require 'domReady' the result is a function:
function domReady(callback) {
if (isPageLoaded) {
callback(doc);
} else {
readyCalls.push(callback);
}
return domReady;
}
But when you append the domReady string with ! sign the result will be the actual document element:
'use strict';
define([
'require',
'angular',
'app/myApp/app',
'app/myApp/routes'
], function(require, ng) {
require(['domReady!'], function(domReady) {
// domReady is now a document element
ng.bootstrap(domReady, ['myApp']);
});
});