I am trying to set up unit testing with Angular and have hit a bit of a wall with injecting into the module level config and run methods.
For example, if I have a module definition as such:
angular.module('foo', ['ngRoute', 'angular-loading-bar', 'ui.bootstrap']).config(function ($routeProvider, $locationProvider, datepickerConfig, datepickerPopupConfig) {
Karma yells at me because I am not properly mocking $routeProvider, datepickerConfig, etc with the following:
Error: [$injector:modulerr] Failed to instantiate module foo due to:
Error: [$injector:unpr] Unknown provider: $routeProvider
(and then if I remove $routeProvider then it says Unknown provider: datepickerConfig and so on)
I also have the following code in a beforeEach:
angular.mock.module('foo');
angular.mock.module('ngRoute');
angular.mock.module('ui.bootstrap');
And the following in my karma.conf.js:
'components/angular/angular.js',
'components/angular/angular-mocks.js',
'components/angular/angular-route.js',
'components/angular-ui/ui-bootstrap-tpls.js',
'app/*.js', // app code
'app/**/*.js',
'app/**/**/*.js',
'test/app/*.js', // app.js
'test/specs/*.js', // angular.mock.module calls
'test/**/*.js', // tests
'test/**/**/*.js'
Thank you for any advice.
Make sure to include the angular-route module and all your dependencies into the flies array of your karma.conf.js. That should do the trick.
I also have the following code in a beforeEach:
angular.mock.module('foo');
angular.mock.module('ngRoute');
angular.mock.module('ui.bootstrap');
I don't think you need to mock ngRoute and ui.bootstrap
Generally I just set
describe('myApp', function() {
beforeEach(module('foo'));
it('should do something awesome', function() {
// arrange
// act
// assert
});
});
Related
I'm attempting to inject a factory called recipesApp.recipeData into my MainController, as soon as I added it, the app broke and I have been receiving the following error:
angular.js:68 Uncaught Error: [$injector:modulerr] Failed to instantiate module recipesApp due to:
Error: [$injector:modulerr] Failed to instantiate module recipesApp.recipeData due to:
Error: [$injector:nomod] Module 'recipesApp.recipeData' 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.
My main app module is written as follows:
var app = angular.module('recipesApp', ['ngRoute', 'recipesApp.recipeData']);
My controller:
app.controller('MainController', ['$scope', '$http', '$location', '$rootScope', 'recipeData',
function($scope,$http,$location,$rootScope,recipeData) {...}]);
My recipe factory:
angular
.module('recipesApp.recipeData', [])
.factory('recipeData', function($http) {
return {
getAllRecipes: function(){
$http.get('/allrecipes');
}
};
});
I have tried changing the file structure, the file naming convention. I have tried simply linking it onto the controller itself in the same file, I've changed the order in which it is being injected, and I've triple checked the spelling. Any suggestions would be very helpful!
You're trying to add $http as a module dependency, $http is a service, not a module. Remove it from your recipesApp.recipeData module dependencies
angular
.module('recipesApp.recipeData', [])
.factory('recipeData', function($http) {
return {
getAllRecipes: function(){
$http.get('/allrecipes');
}
};
});
Also make sure all the .js files are present in your index.html
in my ionic app I want to use cordova-plugin-video-editor plugin but I don't know how to inject it on my controller.
I added the plugin on the terminal like this:
ionic plugin add https://github.com/jbavari/cordova-plugin-video-editor.git
And it is injected with the controller like this (last one):
.controller('VideoCtrl', ['$scope', '$ionicPlatform', '$ionicModal', '$cordovaDialogs', '$cordovaCapture', '$cordovaFileTransfer', '$sce', 'VideoService', '$q', '$http', '$ionicScrollDelegate', '$timeout', '$location', 'VideoEditor', function ($scope, $ionicPlatform, $ionicModal, $cordovaDialogs, $cordovaCapture, $cordovaFileTransfer, $sce, VideoService, $q, $http, $ionicScrollDelegate, $timeout, $location, VideoEditor) {
I get this error:
Uncaught Error: [$injector:modulerr] Failed to instantiate module starter due to:
Error: [$injector:modulerr] Failed to instantiate module starter.controllers due to:
Error: [$injector:modulerr] Failed to instantiate module VideoEditor due to:
Error: [$injector:nomod] Module 'VideoEditor' 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 am confused, I am using more plugins but all are official and I didn't have problems as I only had to do:
angular.module('starter.controllers', ['ngCordova'])
And in the html
<script src="lib/ngCordova/dist/ng-cordova.js"></script>
Inside plugin folder there is a js file that has:
var exec = require('cordova/exec'),
pluginName = 'VideoEditor';
function VideoEditor() {
}
VideoEditor.prototype.transcodeVideo = function(success, error, options) {
exec(success, error, pluginName, 'transcodeVideo', [options]);
};
VideoEditor.prototype.createThumbnail = function(success, error, options) {
exec(success, error, pluginName, 'createThumbnail', [options]);
};
module.exports = new VideoEditor();
When I install the plugin should not this js content had gone somewhere in my www folder so then I can imported from html?
Remove the VideoEditor module in your controller configuration. because this VideoEditor have not any relation with angular.
Also you need refer the github document. They use it just like a jquery plugins. not a angular plugins. Does make sense? let me know, if not.
How do I implement it in Angular controller?
You can use it just like a javascript library.
I want to inject Restangular in my app to communicate with via REST.
So, here I am know with an error:
Error: [$injector:unpr] Unknown provider: RestangularProvider <- Restangular <- Api
Api is my own module here. What I'm doing:
Creating a main module called Dashboard
Creating a submodule called API
Now I want to use Restangular, but couldn't figure out how Angular is managing the dependencies...
Here is my sub-module where I inject Restangular:
angular.module( 'dashboard.api', ['restangular']).factory('Api', ['$http', 'Config', 'Restangular', function($http, Config, Restangular) {
My main module, Dashboard, doesn't need to inject Restangular, right?
angular.module( 'dashboard', [ 'dashboard.api'])
How is the injection-depency working within submodules? How can I
integrate Restangular in my app?
EDIT: Source file is included:
Okay I found the problem and the solution.
You have to differ between restangular(the module) and Restangular the service.
First, you have to include the main module of restangular into your app:
For me, it was this (polygon is a submodule of my app:
angular.module('polygons', ['restangular']);
Then, I wanted to inject restangular into a factory of that submodule:
angular.module('polygons').factory('polygonService', ['Restangular', polygonService]);
function polygonService(Restangular) {
// ...
});
This works for me. Hope this helps.
So this issue only seems to happen when I move a factory to an external file, and I'm really confused as to why. Extracting directives, controllers, and filters to external files does not break my app. I'll show what I'm doing below.
I create my app.js, name the module, inject my various dependencies, continue with my config, and create my factory.
---- app.js -----
angular
.module('myApp', [
'ngAnimate',
'ngCookies',
'ngResource',
'ngRoute',
'ngSanitize',
'ngTouch',])
.config(function ($routeProvider, $locationProvider, $httpProvider) { ... })
.factory('myFactory', function($http){ ... });
// also works with .factory('myFactory', ['$http', function($http) { ... }]);
I have no issue accessing my factory in my controller this way.
---- controller.js ------
angular.module('myApp')
.controller('myController', function(myFactory){
myFactory.method() // works just fine
});
Alternatively :
---- controller.js ------
angular.module('myApp')
.controller('myController', [ 'myFactory', function(myFactory){
myFactory.method() // also works just fine
}]);
Not sure which syntax is "right" but I try both always and they both work just fine.
...Now, if i remove .factory from app.js and move it to myFactory.js (which is linked in index.html) is where the problem happens.
----- myFactory.js -----
angular.module('myApp')
.factory('myFactory', function($http) { ... }); // also attempted with [ ] syntax
The app now fails to load after refresh, and I receive a pnpr error.
I've attempted:
Removing $http from the factory, and also leaving the factory empty to ensure I wasn't returning bad code from within the factory.
Changing myFactory.js's angular.module to read
angular.module('myFactory', []);
angular.module('myFactory').factory('api', [ '$http', function($http){ ... });
then in app.js injecting 'myFactory' as a dependency... I get some different error all together:
Uncaught Error: [$injector:modulerr] Failed to instantiate module crema.app due to: Error: [$injector:modulerr] Failed to instantiate module myFactory due to: Error: [$injector:nomod] Module 'myFactory' 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. errors.angularjs.org/1.3.15/$injector/nomod?p0=myFactory
Loading myFactory.js 1st, 2nd, 9th, last... in index.html, thinking maybe the load order might matter? It did not.
And various other minor syntactical changes. Nothing seems to really help, or change my error.
Not really sure what else to try. Like I said, the factory functions as intended when inside of app.js, and all my controllers, directives, etc. work just fine in external files... just not this factory. Any help would be appreciated.
The problem is that AngularJS does not allow you to register factories after its bootstrap. In order to make it work, you should do the following in your config function:
var app = angular.module('app', [...]);
app.config(function($provide) {
app.factory = function(name, factory) {
$provide.factory(name, factory);
};
});
I have the following:
var app = angular
.module('app', ['ui.router', 'admin', 'home', 'questions', 'ngResource', 'LocalStorageModule'])
.config(['$sceProvider', '$stateProvider', '$locationProvider', 'localStorageService',
function ($sceProvider, $stateProvider, $locationProvider, localStorageService ) {
$sceProvider.enabled(false);
$locationProvider.html5Mode(true);
localStorageService.add('adminContent', 'xx');
This is giving me an error:
Uncaught Error: [$injector:modulerr] Failed to instantiate module app due to:
Error: [$injector:unpr] Unknown provider: localStorageService
http://errors.angularjs.org/1.2.0-rc.2/$injector/unpr?p0=localStorageService
at hasOwnPropertyFn (http://127.0.0.1:81/Scripts/angular-v1.2.0-rc.2.js:78:12)
at http://127.0.0.1:81/Scripts/angular-v1.2.0-rc.2.js:2997:19
at getService (http://127.0.0.1:81/Scripts/angular-v1.2.0-rc.2.js:3119:39)
at Object.invoke (http://127.0.0.1:81/Scripts/angular-v1.2.0-rc.2.js:3140:13)
at http://127.0.0.1:81/Scripts/angular-v1.2.0-rc.2.js:3078:37
at Array.forEach (native)
at forEach (http://127.0.0.1:81/Scripts/angular-v1.2.0-rc.2.js:224:11)
at loadModules (http://127.0.0.1:81/Scripts/angular-v1.2.0-rc.2.js:3065:5)
at createInjector (http://127.0.0.1:81/Scripts/angular-v1.2.0-rc.2.js:3007:11)
at doBootstrap (http://127.0.0.1:81/Scripts/angular-v1.2.0-rc.2.js:1152:20)
http://errors.angularjs.org/1.2.0-rc.2/$injector/modulerr?p0=app&p1=Error%3…http%3A%2F%2F127.0.0.1%3A81%2FScripts%2Fangular-v1.2.0-rc.2.js%3A1152%3A20)
Is it not possible to use localStorage in config like this? I have included the code for the localstorage module and it's loaded before the app.js. It works in other parts of the application, but the same line does not work when placed in the app.config
Only providers and constants are injectable in configuration blocks. See the AngularJs documentation for more insights: http://docs.angularjs.org/guide/module (sektion "Module Loading & Dependencies").
Configuration blocks - get executed during the provider registrations
and configuration phase. Only providers and constants can be injected
into configuration blocks. This is to prevent accidental instantiation
of services before they have been fully configured.
While the accepted answer correctly answers the question, it does not offer any solution (for Angular newbies looking for the right way to do this).
You have access to services at run time, which happens after configuration. For instance:
angular.module('app').run(storeAdminContent);
storeAdminContent.$inject = ['localStorageService'];
function storeAdminContent(localStorageService) {
localStorageService.add('adminContent', 'xx');
}