I'm having trouble getting my tests to run due to dependencies not beeing injected correctly.
The error I'm getting is defined in the title. I've included the actual test code, the app.js & index.html file from my solution.
The problem lies with the deferred bootstrap which I'm not fimiliar with as it was included by one of my colleagues. If I remove the "app.config(function (STARTUP_CONFIG..." from the app.js file then the test runs fine
How can I correctly inject the STARTUP_CONFIG in my test?
test code
..
..
describe("test description...", function () {
var app;
var mockupDataFactory;
beforeEach(module('Konstrukt'));
beforeEach(inject(function (STARTUP_CONFIG,BUDGETS,APPLICATIONS) {
//failed attempt to inject STARTUP_CONFIG
}));
beforeEach(function () {
app = angular.module("Konstrukt");
});
beforeEach(function () {
mockupDataFactory = konstruktMockupData.getInstance();
});
it('should be accessible in app module', function () {
expect(app.pivotTableService).toNotBe(null); //this test runs fine
});
it('test decr...', inject(function ( pivotTableService) {
... //Fails here
..
..
app.js
..
..
angular.module('Konstrukt', ['ngGrid', 'ngSanitize', 'ngRoute','pasvaz.bindonce', 'ngAnimate', 'nvd3ChartDirectives', 'ui.select', 'ngProgress', 'ui.grid', 'ui.grid.edit','ui.grid.selection', 'ui.grid.cellNav', 'ui.grid.pinning', 'ui.grid.resizeColumns']);
var app = angular.module('Konstrukt');
app.config(function (STARTUP_CONFIG, BUDGETS, APPLICATIONS) {
var STARTUP_CONFIG = STARTUP_CONFIG;
var BUDGETS = BUDGETS;
var APPLICATIONS = APPLICATIONS;
});
..
..
index.html
..
..
<script>
setTimeout(function(){
window.deferredBootstrapper.bootstrap({
element: window.document.body,
module: 'Konstrukt',
resolve: {
STARTUP_CONFIG: ['$http', function ($http) {
return $http.get('/scripts/_JSON/activeBudgets.JSON');
}],
BUDGETS: ['$http', function ($http) {
return $http.get('/scripts/_JSON/activeBudgets.JSON');
}],
APPLICATIONS: ['$http', function ($http) {
return $http.get('/scripts/_JSON/applications.JSON');
}]
}
})
} , 1500);
</script>
The deferredBootstrapper will not run in your unit tests, which means the constants it normally adds to your module won't be available.
You can add a global beforeEach that provides mocked versions of them:
beforeEach(function () {
module(function ($provide) {
$provide.constant('STARTUP_CONFIG', { something: 'something' });
$provide.constant('BUDGETS', { something: 'something' });
$provide.constant('APPLICATIONS', { something: 'something' });
});
});
Related
I have setted up a test environment with Angular 1.6.6, ng-mock 1.6.6, Jasmine and Karma. But even with the easiest test I'm getting a [$injector:modulerr] when trying to inject the deloreanApp module
Failed to instantiate module deloreanApp due to: Error:
[$injector:nomod]
Theoretically there aren't tipo errors and Angular and ng-mock versions matches.
My files are:
app.js
(function () {
"use strict";
// initialize Angular
angular.module('deloreanApp', ['deloreanApp.controllers', 'deloreanApp.services']);
angular.module('deloreanApp.controllers', []);
angular.module('deloreanApp.services', []);
})();
controllers.js
(function () {
"use strict";
function deloreanController($scope){
$scope.sum = function(a,b){
return a + b;
}
}
angular.module('deloreanApp.controllers', []).controller('DeloreanController', ['$scope', deloreanController] );
})();
DeloreanController.test.js
describe('calculator', function () {
beforeEach(module('deloreanApp'));
var $controller;
beforeEach(inject(function (_$controller_) {
$controller = _$controller_;
}));
describe('sum', function () {
it('1 + 2 should equal 3', function () {
var result = 3;
expect(result).toBe(3);
});
});
});
And part of my karma.conf.js file:
// list of files / patterns to load in the browser
files: [
'lib/angular.min.js',
'lib/angular-mocks.js',
'js/app.js',
'js/controllers.js',
'tests/DeloreanController.test.js'
],
Try this,
(function () {
"use strict";
angular.module('deloreanApp.controllers', []);
angular.module('deloreanApp.services', []);
// initialize Angular
angular.module('deloreanApp', ['deloreanApp.controllers', 'deloreanApp.services']);
})();
I am working on an app where I need to resolve promises in the router (ngRoute). The problem is that I am not sure how to write the unit tests for this, I am using karma with mocha and chai.
Here is the part of the code I'd like to test:
function config ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/orders.html',
controller: 'OrderController',
controllerAs: 'vmr',
resolve: OrderController.resolve,
data: {...}
});
}
function OrderController (OrderService, newOrders) {
this.newOrders = newOrders;
}
OrderController.resolve = {
newOrders: function (OrderService) {
return OrderService.getOrders();
}
};
This is how I started to write my unit tests when I didn't have the resolve part yet:
describe('OrderController', function() {
'use strict';
var controller,
service,
httpBackend;
beforeEach(module('myApp.orders'));
beforeEach(inject(function($controller, _OrderService_, $httpBackend) {
service = _OrderService_;
httpBackend = $httpBackend;
// Create the controller
controller = $controller('OrderController', {});
}));
beforeEach(function() {
httpBackend.when('GET', 'url/to/get/orders')
.respond(200, {[...]});
});
afterEach(function() {
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});
it('should get the list of new orders', function() {
httpBackend.flush();
expect(controller.neworders).not.to.undefined;
expect(controller.neworders.length).to.equal(3);
});
});
At this point is where I am getting the error:
Unknown provider: newOrdersProvider <- newOrders
I understand why I get this error, but I don't know how to solve it. Basically I don't know how to test the promise that resolves in the route.
Thanks in advance for your help!
After a lot of searching and reading the AngularJS Testing Cookbook I find out how to inject the result of the promise in the controller.
The main code doesn't change, so I will post here only the update code for the unit tests:
describe('OrderController', function() {
'use strict';
var controller,
service,
httpBackend;
// here is where I will inject a new value
beforeEach(function() {
module('myApp.orders', function($provide) {
$provide.value('resolver', {
newOrders: function(service) {
return service.getOrders();
}
});
});
});
beforeEach(inject(function($controller, _OrderService_, $httpBackend, resolver) {
service = _OrderService_;
httpBackend = $httpBackend;
// Create the controller
controller = $controller('OrderController', {
// add them to the controller
newOrders: resolver.newOrders(service)
});
}));
beforeEach(function() {
httpBackend.when('GET', 'url/to/get/orders')
.respond(200, {[...]});
});
afterEach(function() {
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});
it('should get the list of new orders', function() {
httpBackend.flush();
expect(controller.neworders).not.to.undefined;
expect(controller.neworders.length).to.equal(3);
});
});
If someone has a better/different solution I'd like to hear it as well!
I'm trying to adapt this answer to my creation and testing of a factory..
Failing unit test of factory with dependency in AngularJS using Jasmine & Karma
Anyhow, I'm getting this error..
Error: [$injector:unpr] Unknown provider: ModulizerFactoryProvider <-
ModulizerFactory
Here's my code, fairly blank, but should pass.
angular.module( 'modulizer', [
'ui.router',
'ui.bootstrap'
])
.factory('ModulizerFactory', function() {
function Modulizer(modules) {
this.modules = modules;
}
return Modulizer;
})
Here's my test:
describe( 'Modulizer', function() {
describe( 'make_apiUrlFn', function() {
var AppCtrl, $location, $scope;
beforeEach(module( 'modulizer' ) );
beforeEach( inject( function( $injector ) {
myFactory = $injector.get('ModulizerFactory');
}));
it( 'should exist', inject( function(myFactory) {
expect(myFactory).toBeDefined();
}));
});
});
So there were two things going on..
First, something was wonky with my grunt watch process, which was making none of my changes in the source file get applied.
Second, there is a bug in the test posted above...
describe( 'Modulizer', function() {
describe( 'make_apiUrlFn', function() {
var AppCtrl, $location, $scope;
beforeEach(module( 'modulizer' ) );
beforeEach( inject( function( $injector ) {
myFactory = $injector.get('ModulizerFactory');
}));
it( 'should exist', inject( function(ModulizerFactory) {
expect(myFactory).toBeDefined();
}));
});
});
The difference is in the 'should exist' line.
I am trying to test an angularjs service called MyService. If I try to inject it, seems that angular tries to use it before is loaded. On the other hand, if I mock MyService via $provide and so on, it works but I will not have the actual object to test.
(function (angular) {
'use strict';
angular.module('app', []).run(["MyService",
function (MyService) {
MyService.initListeners();
}
]);
// this is supposed to be in another file
angular.module('app')
.service("MyService", function() {
return {
initListeners: function() {
console.log("working")
}
}
})
}(angular));
The test is this:
(function () {
'use strict';
describe("MyService", function () {
var MyService = null;
beforeEach(module("app"));
beforeEach(inject(function ($injector) {
MyService = $injector.get('MyService');
}));
afterEach(function () {
MyService = null;
});
it("injection works", function () {
expect(true).toBeTruthy(); // throws exception
});
});
}());
I did the test on a jsfiddle.
I see the order of execution with some console messages. The order of execution is the correct, as expected.
My service constructor
before init
MyService.initListeners()
after init
And the two test work correctly:
it("injection works", function () {
expect(true).toBeTruthy(); // throws exception
expect(MyService).toBeDefined();
});
Here is the code: http://jsfiddle.net/jordiburgos/1efvof3k/
It could be your AngularJS version, Jasmine, etc...
I'm making a unit test for an angular controller with Jasmine but I can't get passed the error
"TypeError: Cannot read property 'running' of undefined".
The full error is posted at the bottom.
Here's the app definition...
var myApp= myApp|| angular.module('myApp', ['ngRoute', 'ngSanitize', 'ui.bootstrap']);
myApp.run(['$http', '$rootScope', 'properties', function($http, $rootScope, properties) {
//...
//Implementation of custom dependency
properties.get().then(function(response) {
$rootScope.propertiesLoaded = true;
myApp.properties = response;
});
//...
}]);
The controller..
myApp.controller('myController', function($scope, users) {
//...
});
The test.js
describe("Test Controllers", function () {
beforeEach(function () {
angular.module("myApp");
//Injection of mocked custom dependency into the myApp.run method
myApp.run(function ($provide) {
$provide.provider('properties', function () {
this.$get = function () {
return "Mock return"
};
});
});
});
describe("myController", function () {
var scope, usrs, createMainController, mockDependency;
beforeEach(function () {
mockDependency = {
current: {
get: function () {
return "Mock return";
}
}
};
angular.module(function ($provide) {
$provide.value('users', mockDependency);
},[]);
inject(function (_$injector_, _$controller_, _$rootScope_, users) {
scope = _$rootScope_.$new();
usrs = _$injector_.get("users");
_$controller_("myController", {
$scope: scope,
users: usrs
});
createMainController = function () {
return _$controller_("myController", {
$scope: scope,
users: usrs
});
};
});
});
describe("This simple test", function () {
it("should pass no matter what", function () {
expect(true).toBe(true);
});
});
});
});
Here's the whole error message...
TypeError: Cannot read property 'running' of undefined
at isSpecRunning (file:///C:/.../angular-mocks.js:1923:73)
at window.inject.angular.mock.inject (file:///C:/.../angular-mocks.js:2087:20)
Next line points to inject function
at Object.<anonymous> (file:///C:/.../mySpec.js:37:13)
at attemptSync (file:///C:/.../jasmine.js:1510:12)
at QueueRunner.run (file:///C:/.../jasmine.js:1498:9)
at QueueRunner.execute (file:///C:/.../jasmine.js:1485:10)
at Spec.Env.queueRunnerFactory (file:///C:/.../jasmine.js:518:35)
at Spec.execute (file:///C:/.../jasmine.js:306:10)
at Object.<anonymous> (file:///C:/.../jasmine.js:1708:37)
at attemptAsync (file:///C:/.../jasmine.js:1520:12)
Here is a related reference to the error that I found which suggests it is an existing problem with Jasmine. However, in this case the problem involved Mocha, which I'm not using.
https://github.com/angular/angular.js/issues/1467
I'm not sure if this will help you, but you could give this a shot, I've had that problem. I'm not very good with AngularJS so if this doesn't work I don't know what to tell you. In your angular-mocks.js find the function isSpecRunning and change it into this:
function isSpecRunning() {
//return currentSpec && (window.mocha || currentSpec.queue.running);
return !!currentSpec;
}
I read something about Jasmine 2.0 (not sure if that's what you're on) not behaving unless you have this line.
They have fixed this issue using the above logic in newer version of angular-mocks.js (v 1.3.15).