I have the following provider:
(function (angular) {
angular.module('app')
.provider('$_Config', ConfigProvider);
function ConfigProvider() {
.... //routes definition
}
ConfigProvider.prototype.$get = function () {
return this;
};
ConfigProvider.prototype.getRoutes = function() {...}
//other prototype functions
})(angular);
In app.js I am using it like this:
app.config(function ($routeProvider, $_ConfigProvider) {
var routes = $_ConfigProvider.getRoutes();
routes.forEach(function(route) {
$routeProvider
.when(route.route, {
.....
})
}
Every thing work fine till it gets to testing. Here is my test:
describe('Provider: $_ConfigProvider', function () {
// load the providers module
beforeEach(module('app'));
// instantiate provider
var $_ConfigProvider;
beforeEach(inject(function (_$_Config_) {
$_ConfigProvider = _$_Config_;
}));
it('Should verify getRoutes function', function () {
var routes = $_ConfigProvider.getRoutes();
expect(Object.prototype.toString.call(routes) === '[object Array]').toBe(true);
});
});
When running the test I am getting the following error:
Error: [$injector:modulerr] Failed to instantiate module app due to:
Error: [$injector:unpr] Unknown provider: $_ConfigProvider
Note: The $_ConfigProvider is injected correctly during run-time.
You are likely not including the file where the provider is defined in in your karma.conf.js dependencies list. See this question:
Include dependencies in Karma test file for Angular app?
I would rename the $_Config to something else, '$' is usually reserved for angular-specific components.
Related
I have few questions with to write a proper unit test for a service using jasmine as framework and karma as test runner.
here is what i implemented in example-service.js:
export default class ExampleService {
constructor($resource, $http, $urlMatcherFactory) {
'ngInject';
this.$resource = $resource;
this.$http = $http;
this.$urlMatcherFactory = $urlMatcherFactory;
}
exampleMethodOne() {
//some code lines
}
exampleMethodTwo() {
//some code lines
}
}
ExampleService.selector = 'myExampleService';
Here what i wrote in my test example-service.test.js
let myExampleService, $httpBackend, $urlMatcherFactory;
beforeEach(() => {
angular
.module('exampleApp', ['ngResource'])
.service(ExampleService.selector, ExampleService);
angular.mock.module('exampleApp');
});
beforeEach(inject((_myExampleService_, _$httpBackend_,
_$urlMatcherFactory_) => {
myExampleService = _myExampleService_;
$httpBackend = _$httpBackend_;
$urlMatcherFactory = _$urlMatcherFactory_;
}));
i have imported the angular-mocks.js, angular-resource.js and example-service.js
when i try this scenario the console will throw a Error: [$injector:unpr] Unknown provider: $urlMatcherFactoryProvider <- $urlMatcherFactory <- myExampleService error.
please help me to solve this.
I suppose $urlMatcherFactory refers to UI router service, and UI Router wasn't loaded.
It's not recommended to use real router in unit tests because it provides extra moving parts and breaks isolation between units. As a rule of thumb, every unit but a tested one should be mocked.
$urlMatcherFactory stub methods have to be configured to return expected values. Since they are used during ExampleService construction, they should be configured prior to service instantiation:
let removeAllUrlMock;
beforeEach(() => {
removeAllUrlMock = jasmine.createSpyObj('removeAllUrl', ['format']);
$urlMatcherFactory = jasmine.createSpyObj('urlMatcherFactory', ['compile']);
$urlMatcherFactory.compile.and.returnValue(removeAllUrlMock);
angular
.module('exampleApp', ['ngResource'])
.service(ExampleService.selector, ExampleService);
angular.mock.module('exampleApp');
angular.mock.module({ $urlMatcherFactory });
});
This can be tested with:
expect($urlMatcherFactory.compile).toHaveBeenCalledOnce();
expect($urlMatcherFactory.compile).toHaveBeenCalledWith('../api/v1/user/{Id}/remove/all');
expect(myExampleService.removeAllUrl).toBe(removeAllUrlMock);
Then specific removeAllUrl calls can be mocked and tested when used:
removeAllUrlMock.format.and.returnValue('../api/v1/user/foo/remove/all');
myExampleService.removeProduct('foo');
expect(removeAllUrlMock.format).toHaveBeenCalledOnce();
expect($urlMatcherFactory.compile).toHaveBeenCalledWith(
jasmine.objectContaining({ id: 'foo' })
);
Since $urlMatcherFactory is utility service that doesn't provide much moving parts and supposed to be predictable, it can alternatively be imported and used directly, without UI router module:
import { UrlMatcherFactory } from '#uirouter/angularjs';
...
beforeEach(() => {
angular
.module('exampleApp', ['ngResource'])
.service(ExampleService.selector, ExampleService);
angular.mock.module('exampleApp');
angular.mock.module(($provide) => {
$provide.service('$urlMatcherFactory', UrlMatcherFactory });
});
});
Then it's just has to be spied:
spyOn(myExampleService, 'removeAllUrl').and.callThrough();
myExampleService.removeProduct('foo');
expect(removeAllUrlMock.format).toHaveBeenCalledOnce();
expect($urlMatcherFactory.compile).toHaveBeenCalledWith(
jasmine.objectContaining({ id: 'foo' })
);
Im trying to understand hows providers works and i make a test based in angularjs documentation and i wrote a simple provider :
(function( window, angular, undefined ){"use strict";
function MyProviderExample(foo)
{
this.testdrive = function()
{
console.log(foo);
}
console.log("init");
}
angular.module('app',[])
.provider('$myProvider',function (){
var foo = "bar";
this.$get = function()
{
return new MyProviderExample(foo);
}
console.log("ey....");
}).config(function($myProvider){
console.log("wut");
$myProvider.foo = "foo";
});
})(window, window.angular);
When i run the code always returns
Uncaught Error: [$injector:modulerr] Failed to instantiate module app due to:
Error: [$injector:unpr] Unknown provider: $myProvider
I was trying to understand what fails but i cant see my mistake, if someone can helps i appreciate
I think you need to remove function($myProvider) from the .config section. Like this:
angular.module('app', [])
.provider('$myProvider', function () {
this.$get = function () {
// --
}
console.log("loaded $myProvider");
})
.config(function(){
console.log("loaded config");
})
.controller('Main',
function main() {
console.log('loaded mycontroller')
});
What are you trying to do with $myProvider.foo = "foo";?
I am trying to create a mock for testing a service that depends on another one managed by bower. The code for the Jasmine test is the following (full example at plunker):
describe('jsonrpc', function() {
'use strict';
var uuidMock, $httpBackend, jsonrpc;
beforeEach(module('jsonrpc', function ($provide) {
uuidMock = {};
uuidMock.generate = function () { return 0; };
$provide.value('uuid', uuidMock);
}));
beforeEach(inject(function(_jsonrpc_, _$httpBackend_) {
jsonrpc = _jsonrpc_;
$httpBackend = _$httpBackend_;
}));
it('should have created $httpBackend', function() {
expect($httpBackend.get).toBeDefined();
});
});
The 'jsonrpc' service provider is defined as follows:
angular.module('jsonrpc', ['uuid']).provider('jsonrpc', function() {
'use strict';
var defaults = this.defaults = {};
defaults.basePath = '/rpc';
this.$get = ['$http', 'uuid4', function($http, uuid4) {
function jsonrpc(options, config) {
... (etc) ...
When I try to mock the dependency of the 'jsonrpc' module on the 'uuid' module, I get the following error:
$injector:modulerr http://errors.angularjs.org/1.2.16/$injector/modulerr?p0=jsonrpc&p1=%5B%24injector%3Amodulerr%5D%20http%3A%2F%2Ferrors.angularjs.org%2F1.2.16%2F%24injector%2Fmodulerr%3Fp0%3Duuid%26p1%3D%255B%2524injector%253Anomod
What am I doing wrong when it comes to mock up that dependency?
What you're doing is not right because you're modifying the provider of the jsrpc module, not the uuid module, and you're only calling $provide.value to provide what should be a whole module (not a value)
If uuid4 is the only part of uuid that you need to mock, you can do
module('jsrpc', function($provide) {
$provide.service('uuid4', uuid4Mock)
});
Where uuid4Mock provides the behaviour only of that service, or whatever it is in there.
I have following app.js file for angular, and i want to add a response interceptor but when i add response interceptor it throws me an error on console
Uncaught Error: [$injector:modulerr]
Below is the file
(function () {
"use strict";
angular.module("builder").config(["$stateProvider", "$urlRouterProvider", "$locationProvider", "$provide","$httpProvider",
function ($stateProvider, $urlRouterProvider, $locationProvider, $provide, $httpProvider) {
$httpProvider.responseInterceptors.push('responseObserver');
}]).factory('responseObserver',
function responseObserver($q, $window) {
return function (promise) {
return promise.then(function (successResponse) {
return successResponse;
}, function (errorResponse) {
switch (errorResponse.status) {
case 401:
$window.location = $window.location;
break;
case 403:
$window.location = './403.html';
break;
case 500:
$window.location = './500.html';
}
return $q.reject(errorResponse);
});
};
});
}());
Can anyone guide me what is causing this issue.
You didn't define the angular module 'builder' anywhere. The following format (which your file uses):
angular.module("builder")
means, "use the angular module 'builder' which I have already defined."
The following format:
angular.module("builder",[])
means, "create the angular module 'builder' right here and now (and eliminate any previous one)".
You can create and use at the same time as:
angular.module("builder",[]).config(....
but you must define it somewhere at least once.
Your factory should be changed like below:
.factor('responseObserver', '$window', function responseObserver($window, $q){
});
notice the way I injected $window. You have to annotate the $window, so that injector can recognize the functions/directives/services to be injected.
I am getting an error when trying to attach my config class to my angular app. I get a message saying: $injector:nomod] Module 'ngLocale' is not available! I have a reference to angular.js and angular-route.js
Here is my Config Code.
module TSApplication {
export class Config {
static $inject = ["$routeProvider"];
constructor($routeProvider: ng.route.IRouteProvider) {
this.registerRoutes($routeProvider);
}
private registerRoutes(rProvider: ng.route.IRouteProvider) {
rProvider.when("/", { templateUrl: "/partials/example.html", controller: "ExampleCtrl" });
}
}
}
(function () {
var app = TSApplication.App.angularModule;
app.config(TSApplication.Config);
})();
And here is my App Module code:
module TSApplication {
"use strict";
export class App {
static angularModule = angular.module("App", ['ngRoute']);
}
}
(function () {
// Toaster Junk
})();
Am I missing something simple? If I don't include the config I do not receive an error.
It looks like you are passing TSApplication.Config to the angular config function which is treating it as a function. Therefore, in your "constructor" this isn't actually what you think it is because no instance of TSApplication.Config was created. You could remedy this by changing registerRoutes to a static method and then calling it in your constructor like this Config.registerRoutes($routeProvider);.