Karma + Angular undefined error - javascript

I just started angular testing with karma and jasmine. I've written two basic tests. One of the two tests pass, but the other one is failing. I can't seem to debug it. I've been looking everywhere, and it should work according to various tutorials. The $scope variable should be available. I get the following error (and a lot of text, see ):
at C:/totalflatline-2.0/public/lib/angular/angular.js:4362
at forEach (C:/totalflatline-2.0/public/lib/angular/angular.js:336)
at loadModules (C:/totalflatline-2.0/public/lib/angular/angular.js:4364)
at createInjector (C:/totalflatline-2.0/public/lib/angular/angular.js:4248)
at workFn (C:/totalflatline-2.0/public/lib/angular-mocks/angular-mocks.js:2409)
at C:/totalflatline-2.0/public/lib/angular-mocks/angular-mocks.js:2392
at C:/totalflatline-2.0/public/shared/tests/unit/shared.client.controller.unit.tests.js:
5
at C:/totalflatline-2.0/node_modules/karma-jasmine/lib/boot.js:126
at C:/totalflatline-2.0/node_modules/karma-jasmine/lib/adapter.js:171
at http://localhost:9876/karma.js:210
at http://localhost:9876/context.html:83
TypeError: 'undefined' is not an object (evaluating '$scope.test')
at C:/totalflatline-2.0/public/shared/tests/unit/shared.client.controller.unit.tests.js:
9
at C:/totalflatline-2.0/node_modules/karma-jasmine/lib/boot.js:126
at C:/totalflatline-2.0/node_modules/karma-jasmine/lib/adapter.js:171
at http://localhost:9876/karma.js:210
at http://localhost:9876/context.html:83
hantomJS 1.9.8 (Windows 7): Executed 2 of 2 (1 FAILED) (0.402 secs / 0.025 secs)
The two tests are as following. The first one passes and the other one gives the above undefined error.
The one that passes:
describe('Testing MEAN Main Module', function() {
var mainModule;
beforeEach(function() {
mainModule = angular.module('mean');
});
it('Should be registered', function() {
expect(mainModule).toBeDefined();
console.log('Success!');
});
});
The one that fails:
describe('Testing the Shared Stats controller', function(){
var SharedController,$scope;
beforeEach(function(){
// load the module you're testing.
module('mean');
inject(function($rootScope,$controller){
// create a scope object for us to use.
$scope = $rootScope.$new();
SharedController = $controller('shared.StatsController',{
$scope:$scope
});
});
});
it('Should contain a user object',function(){
// User cannot be undefined
expect($scope.test).toEqual('yoo');
});
});
The angular controller is looking like this:
// Create the 'shared' controller
angular.module('shared').controller('shared.StatsController', [ '$scope',
function($scope) {
$scope.test = 'yoo';
}
]);
Angular version is 1.4 and the karma dependencies are versions:
"karma": "~0.12.23",
"karma-jasmine": "~0.2.2",
"karma-phantomjs-launcher": "~0.1.4",
I have been breaking my neck over this all day. I hope someone with more knowledge about testing angular can help me out.

Your angular controller isn't instantiated properly. To 'get' or load a module, you use angular.module('moduleName', []), with the second argument being an array with dependencies. So, it should be:
angular.module('shared', []).controller('StatsController', [ '$scope',
function($scope) {
$scope.test = 'yoo';
}
]);

Related

How to inject ngRoute into Jasmine / Karma AngularJS unit test?

I'm trying to get a basic unit test example working. It all works fine with this app.js
var whapp = angular.module('whapp', [])
.filter('reverse',[function(){
return function(string){
return string.split('').reverse().join('');
}
}]);
and this spec.js
describe('Filters', function(){ //describe your object type
beforeEach(module('whapp')); //load module
describe('reverse',function(){ //describe your app name
var reverse, rootScope;
beforeEach(inject(function($filter){ //initialize your filter
reverse = $filter('reverse',{});
}));
it('Should reverse a string', function(){ //write tests
expect(reverse('rahil')).toBe('lihar'); //pass
});
});
});
with this karma files config
files: [
'node_modules/angular/angular.js',
'node_modules/angular-mocks/angular-mocks.js',
'node_modules/angular-mocks/angular-route/angular-route.js',
'node_modules/angular-mocks/angular-ui-router/release/angular-ui-router.js',
'app/js/*.js',
'tests/*.js'
]
The problem occurs when I try to inject ngRoute into my module in app.js like so
var whapp = angular.module('whapp', ['ngRoute'])
.filter('reverse',[function(){
return function(string){
return string.split('').reverse().join('');
}
}]);
In which case I get the following error in karma [UPDATE: this error occurs even if I don't load the angular-mock.js library into karma as shown above]
TypeError: undefined is not a constructor (evaluating 'reverse('rahil')') in tests/spec.js (line 9)
So... how do I inject ngRoute into spec.js correctly? I've tried a variety of things, none of which worked.
Apparently, you get this error because PhantomJS fails to instantiate your main Angular module whapp. One possible reason is, that the file node_modules/angular-mocks/angular-route/angular-route.js is missing.
Obviously, you are using npm to manage your dependencies. So try to replace your current file with:
node_modules/angular-route/angular-route.js
The same for the ui-route module:
node_modules/angular-ui-router/release/angular-ui-router.js
I hope this will help you.

AngularJS Test a Factory with Mocha

I am new to Mocha and AngularJS Unit Testing but want to test my application using Mocha. I have basic language tests working, but I cannot run tests against my applications Factory or Controller.
I have the following basic files.
apps.js
aangular.module('MyApp', []);
file1.js
angular.module('MyApp').factory('Factory1' ...);
file2.js
angular.module('MyApp').factory('Factory2' ...);
angular.module('MyApp').factory('Controller' ...);
describe('Main Test', function() {
var FactoryToTest;
beforeEach(module('MyApp'));
beforeEach(inject(function (_Factory_) {
FactoryToTest = _Factory_;
}));
describe('Factory2', function () {
it('should return "unknown"', function () {
Game = {};
expect(new Factory2(Game)).to.equal('unknown');
});
});
});
When I run the test, it generates an error, and I am not sure what to fix to get this to work.
Error:
Message:
object is not a function
Stack:
TypeError: object is not a function
at Suite.<anonymous> (b:\app\test.js:5:16)
You're getting an error because the beforeEach function should take a callback function instead of an object. According to the Angular guide on module unit testing (scroll to bottom of the page) :
Each module can only be loaded once per injector. Usually an Angular app has only one injector and modules are only loaded once. Each test has its own injector and modules are loaded multiple times.

AngularJS testing $httpBackend.flush() causes error

I'm trying to do some testing with jasmine for an AngularJS service that I have been creating for Spotify. But I keep getting an error with my tests when testing promises.
My test is currently like this:
describe('Spotify.search', function () {
var $httpBackend;
var $rootScope;
var Spotify;
var api = 'https://api.spotify.com/v1';
beforeEach(inject(function(_Spotify_, _$httpBackend_, _$rootScope_) {
Spotify = _Spotify_;
$httpBackend = _$httpBackend_;
$rootScope = _$rootScope_;
jasmine.getJSONFixtures().fixturesPath='base/test/mock';
}));
it('should return an array of artists', function () {
$httpBackend.when('GET', api + '/search?q=Nirvana&type=artist').respond(
getJSONFixture('search.artist.json')
);
Spotify.search('Nirvana', 'artist').then(function (data) {
expect(data).toBeDefined();
expect(data.artists.items.length).toBeGreaterThan(0);
});
$httpBackend.flush(); //This line causes the error
});
});
and the error that comes out is:
✗ should return an array of artists
TypeError: 'undefined' is not a function (evaluating '$browser.$$checkUrlChange()')
at /Users/XXXX/Work/angular-spotify/bower_components/angular/angular.js:12502
at /Users/XXXX/Work/angular-spotify/bower_components/angular-mocks/angular-mocks.js:1438
at /Users/XXXX/Work/angular-spotify/test/spec/angular-spotify.spec.js:249
Line 249 is $httpBackend.flush()
I'm using karma-jasmine and running tests through PhantomJS.
AngularJS: 1.2.24
angular-mocks: 1.2.16
angular-scenario: 1.2.16
karma-jasmine: 0.2.0
Why would $httpBackend be trying to change the url in the browser?
Any help on this would be great.
The problem is your version mismatch between Angular and Angular-Mocks. This line was added recently in Angular-Mocks:
https://github.com/angular/angular.js/blob/v1.2.24/src/ngMock/angular-mocks.js#L59
I could fix this by pushing both Angular and Angular-Mocks to 1.2.22 where this change is not present yet in both projects. But I guess 1.2.24 for both would also work.
The flush method is part of the mocked httpBackend implementation.
See :
https://github.com/angular/angular.js/blob/master/src/ngMock/angular-mocks.js#L1823
To use this implementation of HttpBackend you need to inject 'ngMockE2E' in your dependencies.

Loading AngularJS module in Jasmine test via Grunt

I am trying to write some unit tests for an AngularJS service. I want to run the unit tests from the command-line via Grunt. In an attempt to do that, I've written the following:
gruntfile.js
'use strict';
module.exports = function (grunt) {
grunt.initConfig({
jasmine: {
service: {
src: 'dist/myService.js',
options: {
specs: 'test/*.js',
vendor: [
'bower_components/angularjs/angular.min.js',
'bower_components/angular-mocks/angular-mocks.js'
]
}
}
}
});
// load all grunt task details
require('load-grunt-tasks')(grunt);
grunt.registerTask('default', ['jasmine:service']);
};
dist/myService.js
'use strict';
angular.module('myModule')
.factory('$myService', function () {
return {
getResult: function () {
return 3;
}
};
})
;
test/serviceTests.spec.js
describe('myModule', function() {
beforeEach(function() {
console.log('loading module...');
module('myModule');
});
describe('$myService', function () {
it('should work', function () {
console.log('testing');
expect(1 + 2).toEqual(3);
});
});
})
When I try to run this, I get the following error:
Running "jasmine:service" (jasmine) task
Testing jasmine specs via PhantomJS
>> Error: [$injector:nomod] http://errors.angularjs.org/1.2.22/$injector/nomod?p0=myModule at
>> ..\..\..\C:\source\myModule\bower_components\angularjs\angular.min.js:20
>> ..\..\..\C:\source\myModule\bower_components\angularjs\angular.min.js:21
>> ..\..\..\C:\source\myModule\dist\myService.js
myModule
$myService
- should work...
log: loading module...
log: testing
√ should work
I know that in order to test my service, I need to inject it. However, at this time, I'm getting an error loading the module itself. For that reason, I know that I cannot inject my service. However, I do not know why the module won't load. I've confirmed that I have the correct src value.
Can anybody tell me what I'm doing wrong? Or, perhaps point me to the smallest possible example of testing a service in AngularJS (complete with Grunt, etc.)?
I just don't understand what is wrong with my approach. Thank you for your help.
When you call angular.module('myModule') (without second parameter) Angular tries to reference already existing module and cannot find it.
To declare a new module you should call angular.module('myModule', []) (with two parameters)

AngularJS Jasmine Test Fails: Failed to instantiate module

My angular app worked great and so did my tests, using karma and jasmine, until I added a dependency in ui.bootstrap. Now the app still works as expected, but I can't get my tests to run. This is what I have:
app.js - added dependency in ui.bootstrap
angular.module('myApp', ['ngResource', 'ngRoute', 'ui.bootstrap']).config(function(...) {...});
service.js
angular.module('myApp').service('myService', function () {})
controller.js
angular.module('myApp').controller('MyController', function ($scope, $http, myService) {})
tests/main.js
describe('Controller: MyController', function () {
var MyController, scope;
// load the controller's module
beforeEach(function(){
module('myApp');
inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
MyController = $controller('MyController', {
$scope:scope
});
});
});
it('should do something', function () {
expect(scope.myOptions.length).toBe(5);
});
});
And my test, which I run using grunt and krama, fails due to:
Error: [$injector:modulerr] Failed to instantiate module myApp due to:
Error: [$injector:modulerr] Failed to instantiate module ui.bootstrap due to:
Error: [$injector:nomod] Module 'ui.bootstrap' is not available! You either misspelled the module name or forgot
What have I missed? The app runs with no problem, only the test fails.
In karma.conf.js there is a list of files that karma loads before test execution:
// list of files / patterns to load in the browser
files: [
'bower_components/angular/angular.js',
'bower_components/angular-mocks/angular-mocks.js',
...
]
Add bootstrap-ui.js there.
Inject your dependencies
beforeEach(function(){
angular.module('ui.bootstrap',[]);
});
I had the same problem. Just solved it. Somehow putting the module(myApp); function call inside a the function you provide to beforeEach() doesn't work just try this:
Extract the module call into its own beforeEach():
beforeEach(module('myApp'));
And use another beforeEach() for the function you use.

Categories