Setting up Jasmine/karma for angular - javascript

I am lightly following this guide - http://paislee.io/testing-angularjs-with-grunt-karma-and-jasmine/ - and having a few issues as follows:
Error: [$injector:modulerr] Failed to instantiate module myApp due to:
Error: [$injector:modulerr] Failed to instantiate module ngRoute due to:
Error: [$injector:nomod] Module 'ngRoute' 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.
I installed everything as it told me to and found another pretty basic example of setting up a test(this is my first time implementing so I'm starting small), the test looks like so
describe('Unit: MainCtrl', function() {
// Load the module with MainCtrl
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('MainCtrl', {
$scope: scope
});
}));
it('should create $scope.greeting when calling sayHello',
function() {
expect(scope.greeting).toBeUndefined();
scope.sayHello();
expect(scope.greeting).toEqual("Hello Ari");
});
})
And in the controller it's just
$scope.name = "Ari";
$scope.sayHello = function() {
$scope.greeting = "Hello " + $scope.name;
}
(this is from http://www.ng-newsletter.com/advent2013/#!/day/19 )
I have my app set up and controllers in separate folders, using a regular ng-route structure, I'm thinking this maybe is the issue? I'm using grunt karma for this - here is the task just incase it's helpful.
karma: {
unit: {
options: {
frameworks: ['jasmine'],
singleRun: true,
browsers: ['PhantomJS'],
files: [
'app/bower_components/angular/angular.js',
'app/bower_components/angular-mocks/angular-mocks.js',
'app/scripts/**/*.js'
]
}
}
}
I could use some help, this is my first time attempting this, I would LOVE to get some automated testing in place. Thanks for reading!!

You need to include ngRoute in your files list in the karma conf. The error message says as much.
karma: {
unit: {
options: {
frameworks: ['jasmine'],
singleRun: true,
browsers: ['PhantomJS'],
files: [
'app/bower_components/angular/angular.js',
'app/bower_components/angular-mocks/angular-mocks.js',
'app/bower_components/angular-mocks/angular-route.js',
'app/scripts/**/*.js'
]
}
}
}

You have not included ngroute module, as there is some dependency on this module.
There should be a bower component
'app/bower_components/angular-route/angular-route.js',
Install this bower component and add this line to karma config.
Check for other module too.

Related

gulp-angular-templatecache Module is not available

I am using gulp-angular-templacache.
I have that task that should create a module named templates and I added it as a dependency to my app module:
Configurations:
templateCache: {
file: 'tempaltes.js',
options: {
module: 'templates',
standalone: true,
root: 'app/'
}
}
App module:
var App = angular.module('app', [
'templates']);
Gulp task:
gulp.task('templatecache', ['clean-code'], function() {
log('Creating AngularJS $templateCache');
return gulp
.src(config.htmltemplates)
.pipe($.minifyHtml({empty: true}))
.pipe($.angularTemplatecache(
config.templateCache.file,
config.templateCache.options
))
.pipe(gulp.dest(config.temp));
});
But, when I try to run this I am always getting that error message:
Uncaught Error: [$injector:nomod] Module 'templates' 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.
I tried to make the templatescache also not standalone and removing the dependency but without success...
What should I do ??
Seems you are loading template.js, after the module app definition. You can load the file before your angular app file
OR, Don't define a standalone module.
Configuration
templateCache: {
file: 'tempaltes.js',
options: {
module: 'templates',
standalone: false,
root: 'app/'
}
}
Angualr
//Define the module
angular.module('templates', []);
var App = angular.module('app', ['templates']);

AngularJS Unit Test: Module 'admin.module' is not available

I'm testing an Angular controller using Karma and Jasmine but I can't seem to load in my module from my main class.
Here's my main class: admin.controller.js
angular.module('admin.module').controller('admin.controller', ['$scope', function ($scope) {
$scope.SaveChanges = function()
{
return true;
}
}]);
Here's my test class: admin.controller.tests.js
describe('admin.controller tests', function () {
beforeEach(module('admin.module'));
var $controller = {};
beforeEach(inject(function (_$controller_) {
$controller = _$controller_;
}));
describe('$scope.SaveChanges', function () {
it('Should return true', function () {
var $scope = {};
var controller = $controller('admin.controller', { $scope: $scope });
expect($scope.SaveChanges()).toBe(true);
});
});
});
My karma.conf.js file points to the following files in my project:
// list of files / patterns to load in the browser
files: [
'../TriAngular/scripts/angular.js',
'../TriAngular/scripts/angular-mocks.js',
'../TriAngular/app/admin/*.js',
'app/admin/*.js'
],
The admin.controller.js file is inside ../TriAngular/app/admin and my admin.controller.test.js is inside 'app/admin'.
I have tried to directly reference the files in my karma config file which has not worked. The full error is:
Module 'admin.module' 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.
The issue turned out to not be obviously from the exception being shown. I was missing a angular-route.js file which needed to be included as it looked like my admin module was dependent on it.
List of includes in my karma.conf.js file:
// list of files / patterns to load in the browser
files: [
'../TriAngular/scripts/angular.js',
'../TriAngular/scripts/angular-mocks.js',
'../TriAngular/scripts/angular-route.js',
'../TriAngular/app/admin/*.js',
'app/admin/*.js'
],
Try;
beforeEach(function(){
module('admin.module');
}
});
I'm not familiar with Karma, but you also need to register your module as well, I've only ever used Jasmine with resharper so what I do to register files is;
/// <reference path="../scripts/app.js" />
At the top of the file.
Also don't forget to reference your module's dependencies as well.

AngularJS design guide

Previously when I was writing angular apps, I used to do
angular.module('ngApp', ['all', 'required', 'ng*', 'dependencies'])
in my app.js and then inside services/ and controllers, I could simply do:
angular.module('ngApp')
I have a repo to demonstrate that.
But then I saw the angular-seed/, the way implemented was,
in controllers/
angular.module('appControllers', ['dependencies'])...
in services/
angular.module('appServices', ['dependencies'])..
in app.js
angular.module('ngApp', ['ng*', 'appControllers', 'appSrvices'])..
I had no issue with design, infact I thought it was good, since evrything was dependency injected as well as modular.
I have a situation where I have a services/movie.js that has
angular.module('myAppServices', ['ngResource']).factory(..)
and services/config.js
angular.module('myAppServices').factory(..)
But while writing tests with karma and jasmine. In the karma.conf.js,
I had
files: ['usual', 'bower_components/angular-*.js', 'app/services/**/*.js', '..']
but the problem was config.js got loaded before movie.js and there were errors, myAppServices is not loaded or mis-spelt.
The way I fixed it was I did:
files: ['..', 'app/services/movie.js', 'app/services/config.js']
I have set up a github repo for this too. Here is the controller test file and here is the karma.conf.
I want to know what can be the possible approaches to take such modular approach, without having to specify the order in which the files are to be loaded for my tests.
And this is my first unit test, and its failing:
Error: Unexpected request: GET https://api.themoviedb.org/3/configuration?api_key=2e329c92227ed8be07944ae447c9426f
Expected GET https://api.themoviedb.org/3/movie/top_rated?api_key=2e329c92227ed8be07944ae447c9426f
It would be helpful if I could get some help in fixing that too.
The test
describe('Controllers', function() {
beforeEach(module('myApp'));
beforeEach(module('myAppServices'));
describe("MoviesCtrl", function() {
var scope, ctrl, httpBackend;
beforeEach(inject(function($httpBackend, $rootScope, _$controller_, Movie, Config) {
httpBackend = $httpBackend;
ctrl = _$controller_;
scope = $rootScope.$new();
}));
it("should return a list of movies", function() {
var data = {results: [{name: "Abc"}, {name: "Def"}]};
httpBackend.
expectGET("https://api.themoviedb.org/3/movie/top_rated?api_key=2e329c92227ed8be07944ae447c9426f").
respond(data);
ctrl('MoviesCtrl', { $scope: scope });
httpBackend.flush()
expect(scope.image).toEqual("https://api.themoviedb.org/3/");
});
});
});
conf. file
module.exports = function(config) {
config.set({
basePath: './',
frameworks: ['jasmine'],
files: [
'app/bower_components/angular/angular.js',
'app/bower_components/angular-mocks/angular-mocks.js',
'app/bower_components/angular-resource/angular-resource.js',
'app/bower_components/angular-route/angular-route.js',
'app/services/movie.js',
'app/services/config.js',
'app/controllers/*.js',
'app/app.js',
'unit-tests/**/*.js'
],
exclude: [
'app/**/*.min.js'
],
preprocessors: {
},
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};
UPDATE
I have figured out the error in test, I had to mock the other http request for the configuration. thanks to #Phil.
This is my test now:
describe('Controllers', function() {
beforeEach(module('myApp'));
beforeEach(module('myAppServices'));
describe("MoviesCtrl", function() {
var scope, httpBackend;
var config_data = { images: { base_url: "http://tmdb.com/t/p", backdrop_sizes: ["w300", "w500"]}},
movie_data = {results: [{name: "Abc"}, {name: "Def"}]};
beforeEach(inject(function($httpBackend, $rootScope, $controller) {
httpBackend = $httpBackend;
scope = $rootScope.$new();
httpBackend.
expectGET("https://api.themoviedb.org/3/configuration?api_key=2e329c92227ed8be07944ae447c9426f").
respond(config_data);
httpBackend.
expectGET("https://api.themoviedb.org/3/movie/top_rated?api_key=2e329c92227ed8be07944ae447c9426f").
respond(movie_data);
$controller('MoviesCtrl', { $scope: scope });
}));
it("should return a list of movies", function() {
expect(scope.image).toEqual({})
httpBackend.flush();
expect(scope.image.backdrop_size).toEqual("w300");
});
});
});
Although I am not sure if this is the right test to do :P . Something like a VCR would be helpful.
Why use two separate files for 10 lines each? The purpose of writing code in separate files is to keep it understandable and maintainable. It would make sense to keep your module 'myAppServices' in one file.
If you really need to break down your code in multiple files, you should make use of dependency injection and make them each a separate module (see my patch against your repo). Then the order of loading stops being an issue.
I still haven't found a angular-ish solution to this problem.
Still there are two ways to deal with it.
Using RequireJS as in #Lukasz 's blog post
and the second one is a dirty one, which I did,
Wrote an _config.js file inside services/, controllers/, directives/, which has, for example angular.module('myAppServices', ['ngResource']) in services/,
And in the karma.config.js I had to do files: ['app/services/_config.js', 'app/controllers/_config.js] . Although the problem still remains because I have to specify the order in which the two _config.js's are to be loaded.
Another way could be to have a single app/config.js file with,
(function() {
angular.module('myAppServices', ['ngResource']);
angular.module('myAppControllers', ['myAppServices']);
}());
and then do files: ['app/config.js', 'app/controllers/**/*.js', 'app/services/**/*.js'] in karma.conf.js

UI Router Extras breaks my unit tests with unexpected results error?

QUESTION:
- Why are my tests failing when ui-router-extras (not normal ui-router) is install?
- How can I use ui-router-extras and still have my tests pass?
If you want to install this quickly use yeoman + angular-fullstack-generator + bower install ui-router-extras
I found a similar issue with normal ui-router.
Luckially, ui-router normal works just fine with my testing.
After installing ui-router-extras I get an ERROR
If I uninstall ui-router.extras it this test passes just fine:
UPDATED for beforeEach module of $urlRouterProvider TEST
Heres my test:
'use strict';
describe('Controller: MainCtrl', function () {
// load the controller's module
beforeEach(module('morningharwoodApp'));
beforeEach(module('socketMock'));
var MainCtrl,
scope,
$httpBackend;
// Initialize the controller and a mock scope
beforeEach(
inject( function (_$httpBackend_, $controller, $rootScope) {
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('/api/things')
.respond(['HTML5 Boilerplate', 'AngularJS', 'Karma', 'Express']);
scope = $rootScope.$new();
MainCtrl = $controller('MainCtrl', {
$scope: scope
});
}),
module(function ($urlRouterProvider) {
$urlRouterProvider.otherwise( function(){ return false; });
})
);
it('should attach a list of things to the scope', function () {
$httpBackend.flush();
expect(scope.awesomeThings.length).toBe(4);
});
});
Here's my karma.conf
module.exports = function(config) {
config.set({
// base path, that will be used to resolve files and exclude
basePath: '',
// testing framework to use (jasmine/mocha/qunit/...)
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'client/bower_components/jquery/dist/jquery.js',
'client/bower_components/angular/angular.js',
'client/bower_components/angular-mocks/angular-mocks.js',
'client/bower_components/angular-resource/angular-resource.js',
'client/bower_components/angular-cookies/angular-cookies.js',
'client/bower_components/angular-sanitize/angular-sanitize.js',
'client/bower_components/lodash/dist/lodash.compat.js',
'client/bower_components/angular-socket-io/socket.js',
'client/bower_components/angular-ui-router/release/angular-ui-router.js',
'client/bower_components/famous-polyfills/classList.js',
'client/bower_components/famous-polyfills/functionPrototypeBind.js',
'client/bower_components/famous-polyfills/requestAnimationFrame.js',
'client/bower_components/famous/dist/famous-global.js',
'client/bower_components/famous-angular/dist/famous-angular.js',
'client/app/app.js',
'client/app/app.coffee',
'client/app/**/*.js',
'client/app/**/*.coffee',
'client/components/**/*.js',
'client/components/**/*.coffee',
'client/app/**/*.jade',
'client/components/**/*.jade',
'client/app/**/*.html',
'client/components/**/*.html'
],
preprocessors: {
'**/*.jade': 'ng-jade2js',
'**/*.html': 'html2js',
'**/*.coffee': 'coffee',
},
ngHtml2JsPreprocessor: {
stripPrefix: 'client/'
},
ngJade2JsPreprocessor: {
stripPrefix: 'client/'
},
// list of files / patterns to exclude
exclude: [],
// web server port
port: 8080,
// level of logging
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: ['PhantomJS'],
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false
});
};
This might be a result of some component having a dependency on $state in which case $state will be instantiated and default route will be executed. This is why a template of one of your controllers main.html is being fetched.
To bypass this, replace go() and transitionTo() of $state methods with dummies:
beforeEach( inject( function ( _$state_ ) {
state = _$state_;
spyOn( state, 'go' );
spyOn( state, 'transitionTo' );
} ) );
Here's an alternate solution that doesn't nuke ui-router's transitionTo function.
First, the failing scenario can be reproduced by following these steps:
npm install yo generator-angular-fullstack;
yo angular-fullstack
Inject $state service by adding this line to client/app/app.js:
angular.module("yoAppName").run(function($state) {});
At this point, invoking grunt karma reports the Unexpected request: GET app/main/main.html because UI-Router is bootstrapped and tries to load the default route, which requests the route's template.
To address this, tell UI-Router to delay synchronizing the URL to the state, so we don't load the default route. In the controller spec, add $urlRouterProvider.deferIntercept(); to your test init code:
beforeEach(module('uiRouterExtrasKarmaBugApp'));
// Add the following line
beforeEach(module(function($urlRouterProvider) { $urlRouterProvider.deferIntercept(); }));
1) Your test is failing because ui-router-extras is making an unexpected http GET request to app/main/main.html therefore test fails.
2) Actually there are a lot of suggestions in the issue that you linked to. I assume extra call is made to load the template for the default route, ie. otherwise. So overriding it might fix the problem:
beforeEach(module(function ($urlRouterProvider) {
$urlRouterProvider.otherwise(function(){return false;});
}));
There are two solutions actually... Right after the module declaration.
you can add:
beforeEach(module('stateMock'));
or you can manually, defer the intercept:
beforeEach(module(function($urlRouterProvider) { $urlRouterProvider.deferIntercept(); }));

Angular JS Error: [$injector:nomod] Module 'portfolioMockupApp.services' is not available

I'm attempting to write some unit tests with Karma and am receiving the following error:
PhantomJS 1.9.8 (Mac OS X) ERROR
Error: [$injector:nomod] Module 'portfolioMockupApp.services' 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.
http://errors.angularjs.org/1.3.3/$injector/nomod?p0=portfolioMockupApp.services
at /Users/danielbogart/Documents/coding/work/portfolio-mockup/bower_components/angular/angular.js:1749
Also, I have two separate files within the portfolioMockupApp.services module, both saved in the scripts/services directory.
Karma.conf files section:
files: [
'bower_components/angular/angular.js',
'bower_components/angular-mocks/angular-mocks.js',
'bower_components/angular-animate/angular-animate.js',
'bower_components/angular-cookies/angular-cookies.js',
'bower_components/angular-resource/angular-resource.js',
'bower_components/angular-sanitize/angular-sanitize.js',
'bower_components/angular-touch/angular-touch.js',
'test/mock/**/*.js',
'test/spec/**/*.js',
'app/scripts/services/*.js',
'app/scripts/directives/*.js',
'app/scripts/controllers/*.js',
'app/scripts/app.js',
'node_modules/angular/angular.js',
'node_modules/angular-mocks/angular-mocks.js',
'./src/**/*.js',
'./test/**/*.js'
],
Portfolio.js spec (first and only test currently):
'use strict';
describe('Controller: PortfolioCtrl', function () {
// load the controller's module
beforeEach(module('portfolioMockupApp', 'portfolioMockupApp.services'));
var PortfolioCtrl,
scope;
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $scope, $log, $stateParams, $state,
$rootScope,portService, portfolioCreateService) {
scope = $rootScope.$new();
PortfolioCtrl = $controller('PortfolioCtrl', {
$scope: scope
});
}));
it('should have a list of 5 tabs by default', function () {
expect(scope.tabs.length).toBe(5);
});
});
The problem stemmed from having two separate service files using the same service module. In the Karma.conf file I had to explicitly load the service file that initialized the module, and then the other service file and rest of the app afterwards.
'app/scripts/services/port-service.js',
'app/scripts/services/new-port-service.js',
'app/scripts/app.js',
'app/scripts/services/*.js',
'app/scripts/directives/*.js',
'app/scripts/controllers/*.js',
Thanks for checking back in with a solution. I had this same issue when two modules relied on each other and existed in the same folder, lets call them app/scripts/parentModule.js and app/scripts/constants.js. Both should be picked up by the wildcard entry in karma.config.js.
'app/scripts/*.js'
'app/scripts/anotherFolder/*.js'
Since constants.js relies on parentModule.js, the later must be included first and my guess is the wildcard was including the files alphabetically but I've not confirmed this yet.
'app/scripts/parentModule.js'
'app/scripts/*.js'
'app/scripts/anotherFolder/*.js'

Categories

Resources