I am trying to unit test a service without depending on my application module. How is this supposed to work?
Code:
#karma.conf.coffee
files: [
'bower_components/angular/angular.js' # angular core
'bower_components/**/angular-*.js' # all angular plugins
'utils/typometer.js'
'utils/typometer.spec.js'
]
# utils/typometer.coffee
angular.module('myApp').factory 'typometer', ->
#sizes =
'A':8
'B':9
# # return `this`
# utils/typometer.spec.coffee
describe 'typometer', ->
typometer = undefined # scope control
# Create a mock module so that the typometer factory has something to attach to
beforeEach angular.mock.module 'myApp' #TODO: why doesn't mock.module work?
# Inject the typometer service
beforeEach angular.mock.inject (_typometer_) ->
typometer = _typometer_ # http://docs.angularjs.org/api/angular.mock.inject
it 'exists', ->
expect(typometer).toBeDefined() # fail. 'Uncaught Error: [$injector:nomod] Module 'coatue' is not available!'
expect(typometer.sizes.A).toEqual 8
The ultimate goal is to be able to instantiate a typometer service and test it in isolation without standing up a real instance of the myApp module.
I think this is some kind of order of operations issue. When the typometer factory is declared, the module doesn't exist--I want to test my production files though. Do I have to create a shell application or load the real one before loading any of the files under test? This is a dependency that I would like to remove from the test considerations.
I think I understand now. For a working setup, one needs to perform all of the following:
Load angular + angular plugins
Load dependent module definitions (eg: myApp). This is what I missed.
Load files to test
Load specs
Have test specs instantiate dependent modules and injectables under test
This is a working setup:
#karma.conf.coffee
files: [
'bower_components/angular/angular.js' # angular core
'bower_components/**/angular-*.js' # all angular plugins
'main.js' # still need to load the app definition
'utils/typometer.js'
'utils/typometer.spec.js'
]
# utils/typometer.coffee
angular.module('myApp').factory 'typometer', ->
#sizes =
'A':8
'B':9
# # return `this`
# utils/typometer.spec.coffee
describe 'typometer', ->
typometer = undefined # scope control
beforeEach ->
angular.mock.module 'myApp' # instantiate the mock app
angular.mock.inject (_typometer_) -> # instantiate the mock service
typometer = _typometer_ # http://docs.angularjs.org/api/angular.mock.inject
it 'exists', ->
expect(typometer).toBeDefined()
expect(typometer.sizes.A).toEqual 8
Related
I'm trying to setup unit tests with an Angular application that utilizes the breezejs library for odata queries. When running my tests with Karma the breeze library appears to attempt a configuration setup which I don't want to happen. I'm using angular mocks to mock the module but it appears the entityManagerFactory runs and tries to configure breeze. Here is the karma.conf setup
files: [
// 'www/Scripts/**/*.js',
// 'www/**/*.js',
'www/Scripts/angular.js',
'www/Scripts/angular-animate.min.js',
'www/Scripts/angular-translate.min.js',
'www/Scripts/angular-route.js',
'www/Scripts/angular-messages.js',
'www/Scripts/angular-sanitize.min.js',
'www/Scripts/angular-resource.js',
'www/Scripts/naturalSort.js',
'node_modules/angular-mocks/angular-mocks.js',
'www/Scripts/jquery-1.10.2.js',
'www/Scripts/breeze.min.js',
'www/Scripts/breeze.debug.js',
'www/Scripts/breeze.directives.js',
'www/Scripts/breeze.bridge*.js',
'www/app.module.js',
'www/data/**/*.js',
'www/core/**/*.js',
'www/blocks/**/*.js',
'www/common/**/*.js',
'www/features/**/*.js',
'test/unit/**/*Spec.js',
],
I get the following error when I run "karam start"
Error: Unable to initialize OData. Needed to support remote OData services
at Object.__requireLib [as requireLib] (www/Scripts/breeze.debug.js:410:11)
at webApiODataCtor.proto.initialize (www/Scripts/breeze.debug.js:16284:18)
at initializeAdapterInstanceCore (www/Scripts/breeze.debug.js:1874:14)
at Object.__config.initializeAdapterInstance (www/Scripts/breeze.debug.js:1795:12)
at configureBreeze (www/data/entityManagerFactory.js:46:41)
at Object.emFactory (www/data/entityManagerFactory.js:16:9)
at Object.invoke (www/Scripts/angular.js:4182:17)
at Object.enforcedReturnValue [as $get] (www/Scripts/angular.js:4035:37)
The entityManagerFactory calls a function (configureBreeze();) when its loaded to configure breeze, which must be the problem
function emFactory(breeze) {
configureBreeze();
var oldClient = null;
var factory = {
newManager: newManager,
serviceName: eCAT_ServiceName,
setAuthToken: setAuthToken
};
return factory;
Running into a weird issue with loading an Angular module.
I have a file structure like so
-ng-app
-app
-account
accountCtrl.js.coffee
-auth
authCtrl.js.coffee
-other_folders
app.js.coffee
and I'm loading accountCtrl and other controllers like so
#app/app.js.coffee
angular.module("app", [
'ngResource'
'smart-table'
'checklist-model'
'ui.router'
...
])
#app/account/accountCtrl.js.coffee
#app = angular.module('app')
app.controller 'accountCtrl', ($scope, $state) ->
....
#app/auth/authCtrl.js.coffee
#app = angular.module('app')
app.controller 'authCtrl', ($scope, $state) ->
....
But then accountCtrl throws an error
Module 'app' 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 know the syntax is correct, because I'm loading a a few dozen other controllers with the same syntax. So I started playing around with different scenarios.
I deleted the 'account' folder
No error thrown, other controllers load normally
I renamed account folder to z-account
No error thrown, all controllers including accountCtrl load normally
So the error only occurs when the folder is named 'account' and is the first file in the 'app' folder. Any ideas what's going on?
Rails asset pipeline includes javascript files aphabetically, and app/account.js.coffee was being included before app/app.js.coffee, hence the missing module error.
Two solutions possible:
prefix files with an underscore to ensure it loads first like so:
_app.js.coffee
Or
Remove
//= require_tree .
in application.js and include files manually.
Had a bit of trouble with Angular earlier, but I was able to resolve that problem. Of course, being a newbie, we've hit more problems!
Did some searching around for this error, but applying the fixes that other people have tried has not proven effective for me.
I am currently trying to load a partial onto a show page in Rails using AngularJS.
EDIT: I apologize- I forgot to mention that I intend to load a partial from a file in the same directory as all these files. Current directory tree is as follows:
Directory containing relevant js files and the timer partial
I have the following code built out:
Show.html.erb
<timer-info ng-controller = "CountdownController">
</timer-info>
app.js
'use strict';
var myApp = angular.module("summoners-universe", ['ngRoute'])
directives.js
'use strict';
myApp.directive("timerInfo", function(){
return {
restrict: "E",
templateUrl: 'app/assets/javascripts/timer.html'
};
});
controllers.js
'use strict';
myApp.controller('CountdownController',
["$scope", "$http", "$routeParams",
function($scope, $http, $routeParams){
console.log($routeParams);
}]);
Eventually this controller will display a countdown timer, but for now, I just wanted to make sure I could get my routeParams and all that.
Sadly, I'm hit with the following error upon page load:
angular.self-208d6d1….js?body=1:11757 GET http://localhost:3000/games/app/assets/javascripts/timer.html 404 (Not Found)(anonymous function) # angular.self-208d6d1….js?body=1:11757sendReq # angular.self-208d6d1….js?body=1:11518serverRequest # angular.self-208d6d1….js?body=1:11228processQueue # angular.self-208d6d1….js?body=1:15962(anonymous function) # angular.self-208d6d1….js?body=1:15978Scope.$eval # angular.self-208d6d1….js?body=1:17230Scope.$digest # angular.self-208d6d1….js?body=1:17046Scope.$apply # angular.self-208d6d1….js?body=1:17338bootstrapApply # angular.self-208d6d1….js?body=1:1750invoke # angular.self-208d6d1….js?body=1:4666doBootstrap # angular.self-208d6d1….js?body=1:1748bootstrap # angular.self-208d6d1….js?body=1:1768angularInit # angular.self-208d6d1….js?body=1:1653(anonymous function) # angular.self-208d6d1….js?body=1:30864fire # jquery.self-4e23968….js?body=1:3188self.fireWith # jquery.self-4e23968….js?body=1:3318jQuery.extend.ready # jquery.self-4e23968….js?body=1:3537completed # jquery.self-4e23968….js?body=1:3553
angular.self-208d6d1….js?body=1:13551 Error: [$compile:tpload] Failed to load template: app/assets/javascripts/timer.html (HTTP status: 404 Not Found)
http://errors.angularjs.org/1.5.5/$compile/tpload?p0=app%2Fassets%2Fjavascripts%2Ftimer.html&p1=404&p2=Not%20Found
at angular.self-208d6d1….js?body=1:69
at handleError (angular.self-208d6d1….js?body=1:18979)
at processQueue (angular.self-208d6d1….js?body=1:15962)
at angular.self-208d6d1….js?body=1:15978
at Scope.$eval (angular.self-208d6d1….js?body=1:17230)
at Scope.$digest (angular.self-208d6d1….js?body=1:17046)
at Scope.$apply (angular.self-208d6d1….js?body=1:17338)
at done (angular.self-208d6d1….js?body=1:11573)
at completeRequest (angular.self-208d6d1….js?body=1:11779)
at XMLHttpRequest.requestLoaded (angular.self-208d6d1….js?body=1:11712)(anonymous function) # angular.self-208d6d1….js?body=1:13551(anonymous function) # angular.self-208d6d1….js?body=1:10226processQueue # angular.self-208d6d1….js?body=1:15970(anonymous function) # angular.self-208d6d1….js?body=1:15978Scope.$eval # angular.self-208d6d1….js?body=1:17230Scope.$digest # angular.self-208d6d1….js?body=1:17046Scope.$apply # angular.self-208d6d1….js?body=1:17338done # angular.self-208d6d1….js?body=1:11573completeRequest # angular.self-208d6d1….js?body=1:11779requestLoaded # angular.self-208d6d1….js?body=1:11712XMLHttpRequest.send (async)(anonymous function) # angular.self-208d6d1….js?body=1:11757sendReq # angular.self-208d6d1….js?body=1:11518serverRequest # angular.self-208d6d1….js?body=1:11228processQueue # angular.self-208d6d1….js?body=1:15962(anonymous function) # angular.self-208d6d1….js?body=1:15978Scope.$eval # angular.self-208d6d1….js?body=1:17230Scope.$digest # angular.self-208d6d1….js?body=1:17046Scope.$apply # angular.self-208d6d1….js?body=1:17338bootstrapApply # angular.self-208d6d1….js?body=1:1750invoke # angular.self-208d6d1….js?body=1:4666doBootstrap # angular.self-208d6d1….js?body=1:1748bootstrap # angular.self-208d6d1….js?body=1:1768angularInit # angular.self-208d6d1….js?body=1:1653(anonymous function) # angular.self-208d6d1….js?body=1:30864fire # jquery.self-4e23968….js?body=1:3188self.fireWith # jquery.self-4e23968….js?body=1:3318jQuery.extend.ready # jquery.self-4e23968….js?body=1:3537completed # jquery.self-4e23968….js?body=1:3553
I don't know why a get request is being made to that URL. Any thoughts? Thank you!
The templateUrl of the timerInfo should be absolute, like this:
templateUrl: '/app/assets/javascripts/timer.html'
This way you're referencing from the root directory down to the desired file.
Ah, I was able to figure it out. Apparently, the Angular-Rails gem looks for templates to load in an app/templates directory. I just had to make that directory and put the template there.
I'm testing an Angular app with Karma. I've got everything working, but it seems like I'm doing something wrong.
https://gist.github.com/guyjacks/7bca850844deb612e681
Karma will throw the following error if I comment out 'app/notes/notes.main.js' :
Uncaught Error: [$injector:nomod] Module 'notes.main' 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.4.3/$injector/nomod?p0=notes.main
at /Users/guyjacks/projects/adr-demo/node_modules/angular/angular.js:1958
I don't want to have to manually list each application file to control the order in which each file loads. Am I don't something wrong or do I just have to list each file in the order I want?
---- Solution based on the accepted answer ----
My app is organized into modules as recommended by the Angular Style Guide: https://github.com/johnpapa/angular-styleguide.
'app/app.module.js',
'app/**/*.module.js',
'app/**/*.service.js',
'app/**/*.controller.js',
'app/**/*.directive.js',
'app/**/*.js'
I don't think the following lines are necessary above
'app/**/*.service.js',
'app/**/*.controller.js',
'app/**/*.directive.js'
when each module has an angular module declared in the *.module.js file like my app does.
That said, if you did need to explicitly load services before controllers & controllers before directives then this would be the way to do it.
Update : I could not see your karma file, now Gist link is fixed.
The point in notes[.]main.js is causing the problem,
So, 'app/**/*.js' is not matching notes.main.js.
Try now like this : app/**/*. *.js
=============================================================
Before update :
You have to load the modules that you app depends on, in karma config. file :
module.exports = function(config) {
config.set({
.......
// list of files / patterns to load in the browser
files: [
'./client/app/vendors/angular/angular.js',
// =====> load Your modules here ...
'./client/app/app.js',
'./client/app/controllers/*.js',
'./client/app/directives/*.js',
'./client/app/services/*.js',
'./test/client/unit/**/*.js'
],
.....
}) }
I complete the tutorial from this codelab, and as suggested tried to fix the errors on the unit tests.
But i don't know how to fix this error. I already took a look at this question:running-tests-with-localstorage but it does not address my problem.
Here's my test file:
'use strict';
describe('Controller: MainCtrl', function () {
// load the controller's module
beforeEach(function(){
module('mytodoApp'),
module('LocalStorageModule')
});
var MainCtrl,
scope;
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
MainCtrl = $controller('MainCtrl', {
$scope: scope
});
}));
it('should have no items to start', function () {
expect(scope.todos.length).toBe(0);
});
});
And here is the console output:
PhantomJS 1.9.7 (Linux) Controller: MainCtrl should have no items to start FAILED
Error: [$injector:modulerr] Failed to instantiate module mytodoApp due to:
Error: [$injector:modulerr] Failed to instantiate module LocalStorageModule due to:
Error: [$injector:nomod] Module 'LocalStorageModule' 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.2.16/$injector/nomod?p0=LocalStorageModule
at /home/ubuntu/mytodo/bower_components/angular/angular.js:1613
at ensure (/home/ubuntu/mytodo/bower_components/angular/angular.js:1535)
at module (/home/ubuntu/mytodo/bower_components/angular/angular.js:1823)
at /home/ubuntu/mytodo/bower_components/angular/angular.js:3781
http://errors.angularjs.org/1.2.16/$injector/modulerr?p0=LocalStorageModule&p1=Error%3A%20%5B%24injector%3Anomod%5D%20Module%20'LocalStorageModule'%20is%20not%20available!%20You%20either%20misspelled%20the%20module%20name%20or%20forgot%20to%20load%20it.%20If%20registering%20a%20module%20ensure%20that%20you%20specify%20the%20dependencies%20as%20the%20second%20argument.%0Ahttp%3A%2F%2Ferrors.angularjs.org%2F1.2.16%2F%24injector%2Fnomod%3Fp0%3DLocalStorageModule%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A8080%2Fbase%2Fbower_components%2Fangular%2Fangular.js%3F7dcf1b25480258d399759429338cedc57239f2d1%3A1613%0A%20%20%20%20at%20ensure%20(http%3A%2F%2Flocalhost%3A8080%2Fbase%2Fbower_components%2Fangular%2Fangular.js%3F7dcf1b25480258d399759429338cedc57239f2d1%3A1535)%0A%20%20%20%20at%20module%20(http%3A%2F%2Flocalhost%3A8080%2Fbase%2Fbower_components%2Fangular%2Fangular.js%3F7dcf1b25480258d399759429338cedc57239f2d1%3A1823)%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A8080%2Fbase%2Fbower_components%2Fangular%2Fangular.js%3F7dcf1b25480258d399759429338cedc57239f2d1%3A3781
at /home/ubuntu/mytodo/bower_components/angular/angular.js:3810
http://errors.angularjs.org/1.2.16/$injector/modulerr?p0=mytodoApp&p1=Error%3A%20%5B%24injector%3Amodulerr%5D%20Failed%20to%20instantiate%20module%20LocalStorageModule%20due%20to%3A%0AError%3A%20%5B%24injector%3Anomod%5D%20Module%20'LocalStorageModule'%20is%20not%20available!%20You%20either%20misspelled%20the%20module%20name%20or%20forgot%20to%20load%20it.%20If%20registering%20a%20module%20ensure%20that%20you%20specify%20the%20dependencies%20as%20the%20second%20argument.%0Ahttp%3A%2F%2Ferrors.angularjs.org%2F1.2.16%2F%24injector%2Fnomod%3Fp0%3DLocalStorageModule%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A8080%2Fbase%2Fbower_components%2Fangular%2Fangular.js%3F7dcf1b25480258d399759429338cedc57239f2d1%3A1613%0A%20%20%20%20at%20ensure%20(http%3A%2F%2Flocalhost%3A8080%2Fbase%2Fbower_components%2Fangular%2Fangular.js%3F7dcf1b25480258d399759429338cedc57239f2d1%3A1535)%0A%20%20%20%20at%20module%20(http%3A%2F%2Flocalhost%3A8080%2Fbase%2Fbower_components%2Fangular%2Fangular.js%3F7dcf1b25480258d399759429338cedc57239f2d1%3A1823)%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A8080%2Fbase%2Fbower_components%2Fangular%2Fangular.js%3F7dcf1b25480258d399759429338cedc57239f2d1%3A3781%0Ahttp%3A%2F%2Ferrors.angularjs.org%2F1.2.16%2F%24injector%2Fmodulerr%3Fp0%3DLocalStorageModule%26p1%3DError%253A%2520%255B%2524injector%253Anomod%255D%2520Module%2520'LocalStorageModule'%2520is%2520not%2520available!%2520You%2520either%2520misspelled%2520the%2520module%2520name%2520or%2520forgot%2520to%2520load%2520it.%2520If%2520registering%2520a%2520module%2520ensure%2520that%2520you%2520specify%2520the%2520dependencies%2520as%2520the%2520second%2520argument.%250Ahttp%253A%252F%252Ferrors.angularjs.org%252F1.2.16%252F%2524injector%252Fnomod%253Fp0%253DLocalStorageModule%250A%2520%2520%2520%2520at%2520http%253A%252F%252Flocalhost%253A8080%252Fbase%252Fbower_components%252Fangular%252Fangular.js%253F7dcf1b25480258d399759429338cedc57239f2d1%253A1613%250A%2520%2520%2520%2520at%2520ensure%2520(http%253A%252F%252Flocalhost%253A8080%252Fbase%252Fbower_components%252Fangular%252Fangular.js%253F7dcf1b25480258d399759429338cedc57239f2d1%253A1535)%250A%2520%2520%2520%2520at%2520module%2520(http%253A%252F%252Flocalhost%253A8080%252Fbase%252Fbower_components%252Fangular%252Fangular.js%253F7dcf1b25480258d399759429338cedc57239f2d1%253A1823)%250A%2520%2520%2520%2520at%2520http%253A%252F%252Flocalhost%253A8080%252Fbase%252Fbower_components%252Fangular%252Fangular.js%253F7dcf1b25480258d399759429338cedc57239f2d1%253A3781%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A8080%2Fbase%2Fbower_components%2Fangular%2Fangular.js%3F7dcf1b25480258d399759429338cedc57239f2d1%3A3810
at /home/ubuntu/mytodo/bower_components/angular/angular.js:3810
PhantomJS 1.9.7 (Linux): Executed 1 of 1 (1 FAILED) ERROR (0.04 secs / 0.006 secs)
Warning: Task "karma:unit" failed. Use --force to continue.
Aborted due to warnings.
UPDATE: Added the answer.
Here's my karma.conf.js file, fixed. Had to add the module angular-local-storage.js to the list of files.
// list of files / patterns to load in the browser
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-route/angular-route.js',
'bower_components/angular-sanitize/angular-sanitize.js',
'bower_components/angular-touch/angular-touch.js',
'bower_components/jquery/dist/jquery.js',
'bower_components/jquery-ui/jquery-ui.js',
'bower_components/angular-ui-sortable/sortable.js',
'bower_components/angular-local-storage/angular-local-storage.js',
'app/scripts/**/*.js',
'test/mock/**/*.js',
'test/spec/**/*.js'
],
The karama.conf.js file contains a files array. When testing, make sure the files containing all of your dependent modules are inserted in to the array:
files: [
/* file paths */
]
One other cool thing is that the file section supports patterns. One way to avoid this problem in the future is to put all your modules or required scripts in to one place or under one common folder and use a pattern to load them all:
files: [
/* or whatever other pattern you want to use */
'/myProject/scripts/vendor/*.min.js',
'/myProject/scripts/modules/*.min.js',
/* the use of ** will search any child folder for the file pattern */
'/myProject/scripts/tests/**/*.js'
]