This question already has an answer here:
Argument 'fn' is not a function, when trying to do unit test with Jasmine and AngularJS
(1 answer)
Closed 4 years ago.
Trying to load controller module in unit testing karma + jasmine + ionic Angular 1.5.3.
Module/Controller file
angular.module('App.View.Controllers', []).controller('ListController',
function($scope){
$scope._userName = UserService.getUserObject().maxperson;
});
describe("ListController", function(){
var $scope, $controller, ListController;
beforeEach(function () {
module('App.View.Controllers');
});
beforeEach(inject(function(_$rootScope_, _$controller_) {
$scope = $rootScope.$new();
$controller = _$controller_;
ListController = $controller('ListController', {$scope: $scope});
}));
it("has a dummy controller", function(){
expect(2+2).toEqual(4);
});
it('should be defined', function() {
expect(ListController).toBeDefined();
});
});
Gives me error:
Error: [$injector:modulerr] Failed to instantiate module App.View.Controllers due to:
Error: [$injector:nomod] Module 'App.View.Controllers' 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.5.3/$injector/nomod?p0=App.View.Controllers
at node_modules/angular/angular.js:68:12
It is ionic app. Actually controller loads dependency also but for time sake I have commented it out to make a simple controller loads.
package.json file
{
"name": "karma-2174",
"version": "1.0.0",
"description": "",
"devDependencies": {
"#uirouter/angularjs": "^1.0.3",
"angular": "^1.5.3",
"angular-mocks": "^1.5.3",
"jasmine-core": "^2.0.4",
"karma": "^1.5.0",
"karma-chrome-launcher": "^2.0.0",
"karma-jasmine": "^1.1.0"
},
"scripts": {
"test": "karma start"
},
"author": "",
"license": "ISC"
}
Please check that you have added all the files in karma.conf.js and also take the example of this link:
In the case of ionic, you have added the main ionic file in karma.conf file
https://scotch.io/tutorials/testing-angularjs-with-jasmine-and-karma-part-1
Related
I am trying to unit test an html template that has variables in paragraph, anchor tags, and {{header.title || translate}} however no matter what posts I have tried it does not seem to work. I get the retrieved HTML template and when it is compiled it is still the same. In the template I still see {{user}} for example. It seems none of them are actually being compiled.
Current Template Output:
<h1>{{header.title | translate}}</h1>
<h2>{{homeCtrl.name}}</h2>
Expected Output:
<h1>Cake Blogger</h1>
<h2>Alexandria</h2>
Test Suite:
(function() {
'use strict';
describe('home.tpl.html', function() {
var scope, controller, createController, template, element, rootScope;
beforeEach(module('Templates'));
beforeEach(module('mainApp'));
/**
#name: home.tpl.html
#description: Inject and set test related objects
#param {Service} rootScope - Used to get the language
#param {Compiler} $templateCache - Holding the compiled template
#param {Injector} $compile - Compiles an HTML string or DOM
*/
beforeEach(inject(
function(_$controller_, _$rootScope_, $templateCache, $compile) {
scope = _$rootScope_.$new();
createController = function() {
return _$controller_('homeCtrl', {
'$scope': scope
});
};
controller = createController();
rootScope = _$rootScope_;
template = $templateCache.get('home.tpl.html');
element = $compile(template)(rootScope);
// var ctrl = element.controller('homeCtrl');
rootScope.$digest();
console.log("home page", element);
}));
/**
#name: Describe Block - home.tpl.html
#description: Test cases related to home.tpl.html
*/
describe('home.tpl.html tests', function() {
fit('should have "Alexandria"', function() {
expect(element.html()).toContain("Alexandria");
});
});
});
})();
Karma File:
files: ['list of files'],
port: 8080,
browsers: [
'PhantomJS'
],
plugins: [
'karma-phantomjs-launcher',
'karma-jasmine',
'karma-ng-html2js-preprocessor',
],
preprocessors: {
'app/**/*.tpl.html': 'html2js'
},
ngHtml2JsPreprocessor: {
'moduleName': 'Templates',
'stripPrefix': 'app/'
}
package.json
{
"name": "",
"private": true,
"devDependencies": {
"autoprefixer-core": "^5.2.1",
"grunt": "^0.4.5",
"grunt-angular-templates": "^0.5.7",
"grunt-concurrent": "^1.0.0",
"grunt-contrib-clean": "^0.6.0",
"grunt-contrib-compass": "^1.0.0",
"grunt-contrib-concat": "^0.5.0",
"grunt-contrib-connect": "^0.9.0",
"grunt-contrib-copy": "^0.7.0",
"grunt-contrib-cssmin": "^0.12.0",
"grunt-contrib-htmlmin": "^0.4.0",
"grunt-contrib-imagemin": "^1.0.0",
"grunt-contrib-jshint": "^0.11.0",
"grunt-contrib-uglify": "^0.7.0",
"grunt-contrib-watch": "^0.6.1",
"grunt-filerev": "^2.1.2",
"grunt-google-cdn": "^0.4.3",
"grunt-jscs": "^1.8.0",
"grunt-karma": "*",
"grunt-modernizr": "^1.0.2",
"grunt-newer": "^1.1.0",
"grunt-ng-annotate": "^0.9.2",
"grunt-ng-constant": "^2.0.1",
"grunt-postcss": "^0.5.5",
"grunt-svgmin": "^2.0.0",
"grunt-usemin": "^3.0.0",
"grunt-wiredep": "^2.0.0",
"jasmine-core": "^2.4.1",
"jit-grunt": "^0.9.1",
"jshint-stylish": "^1.0.0",
"karma": "^0.13.22",
"karma-coverage": "^0.5.5",
"karma-fixture": "^0.2.6",
"karma-jasmine": "*",
"karma-json-fixtures-preprocessor": "0.0.6",
"karma-json-preprocessor": "^0.3.3",
"karma-junit-reporter": "^1.2.0",
"karma-ng-html2js-preprocessor": "~0.1.0",
"karma-phantomjs-launcher": "*",
"phantomjs": "^2.1.7",
"time-grunt": "^1.0.0"
},
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"test": "grunt test"
},
"dependencies": {}
}
According to posts I have read such as this plunker from a post plunker example, this should be working correctly. I am thinking perhaps the controller is not binding to the scope so that when $digest runs the template cannot find the controller maybe.
Helpful Information:
Where it says rootscope.$digest() I also tried it as scope.$digest(), I also tried using $apply().
I am using ngHtml2JsPreprocessor
I am using TemplateCache
I am using $compile
Links viewed:
how to access controller in directive [jasmine]
$compile not compiling templates in Karma/Jasmine
Don't work $compile in Jasmine Karma Angular
Unit Testing AngularJS directive with templateUrl
The template returns but the angular in the template is never compiled. Always seeing {{homeCtrl.name}} instead of Alexandria.
Update 1.1
I am thinking perhaps since the translate {{header.title | translate}} is not working that maybe angular-translate (module: pascalprecht.translate) is not actually working correctly and is then causing the controller to also fail binding. Will continue investigation.
After injecting angular-translate the | translate filter just works and yields expected translated value after $compile. See this plunker as an example:
http://plnkr.co/edit/j8rbnMI067YntllwTcGi?p=preview
One possible reason that leads to your issue is timing - suppose you have big translate array / json and it takes a while to load, but Jasmine testing already starts and finishes before they are fully loaded and ready. Then Jasmine will see un-translated string during tests.
Updated 2017-06-30
After a few experiments, I can confirm that any async json loader, whether it's .useStaticFilesLoader or $.getJSON(), will not be executed before jasmine. See http://plnkr.co/edit/nreUd52iqOVvwLPMNtJA?p=preview as an example, the static loader works fine for page view but fails unit test.
One possible way to go is to ditch .useStaticFilesLoader completely. Instead, we can use grunt-replace to inject the translations during the build process. Example grunt task:
// replace string with json
replace: {
dist: {
options: {
patterns: [
{
match: /\"JSONEN\"/,
replacement: '<%= grunt.file.read("app/resources/en.json") %>'
}
]
},
files: [
{expand: true, flatten: true, src: ['app/scripts/app.js'], dest: 'public/'}
]
}
}
Using the angular.mock.inject(...) function when trying to unit test an Angular (Ionic) 1 application throws the following error. The strange thing is that there is no specific error message, making particularly hard to debug. No matter what I try, it always seems to throw this same non-descript error without any message.
PhantomJS 2.1.1 (Linux 0.0.0) LoginController should pass FAILED
bower_components/angular/angular.js:4527:53
forEach#bower_components/angular/angular.js:321:24
loadModules#bower_components/angular/angular.js:4487:12
createInjector#bower_components/angular/angular.js:4409:30
WorkFn#bower_components/angular-mocks/angular-mocks.js:3160:60
loaded#http://localhost:9876/context.js:151:17
Removing the call to angular.mock.inject() allows the test to pass.
Here's the test in question:
describe('LoginController', function() {
var scope;
var controller;
beforeEach(angular.mock.module('mCommonJobs'));
beforeEach(angular.mock.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller('LoginController', {
$scope: scope
});
}));
it('should pass', function() {
expect(true).toEqual(true);
});
});
My bower dependencies:
"dependencies": {
"angular-resource": "#1.5.0",
"ionic": "driftyco/ionic-bower#1.3.2",
"ngCordova": "^0.1.27-alpha",
"ng-cordova-oauth": "^0.3.0",
"ngstorage": "^0.3.11",
"angular-mocks": "^1.5.2"
},
"resolutions": {
"angular": "~1.5.x"
}
And the files set in the Karma test config:
files: [
//Angular source
'bower_components/angular/angular.js',
'bower_components/angular-animate/angular-animate.js',
'bower_components/angular-mocks/angular-mocks.js',
'bower_components/angular-resource/angular-resource.js',
'bower_components/angular-sanitize/angular-sanitize.js',
'bower_components/angular-ui-router/release/angular-ui-router.js',
'bower_components/ionic/js/ionic.bundle.js',
'bower_components/ng-cordova-oauth/dist/ng-cordova-oauth.js',
'bower_components/ngCordova/dist/ng-cordova.js',
'bower_components/ngCordova/dist/ng-cordova-mocks.js',
'bower_components/ngstorage/ngStorage.js',
//App code
'app/**/*.module.js',
'app/**/*.js',
'app/*.js',
//Test files
'test/**/*.test.js'
],
This issue was resolved by not including all of ionic.bundle.js in the files config of karma, but by specifically including its parts.
I also explicitly forced all versions of angular-related dependencies to be the same version (special thanks to Phil in the comments.).
In the end, my bower.json had:
"dependencies": {
"angular-resource": "1.5.2",
"ionic": "driftyco/ionic-bower#1.3.2",
"ngCordova": "^0.1.27-alpha",
"ng-cordova-oauth": "^0.3.0",
"ngstorage": "^0.3.11",
"angular-mocks": "1.5.2"
},
and my karma config looked like:
files: [
//Angular source
'bower_components/angular/angular.js',
'bower_components/angular-animate/angular-animate.js',
'bower_components/angular-mocks/angular-mocks.js',
'bower_components/angular-resource/angular-resource.js',
'bower_components/angular-sanitize/angular-sanitize.js',
'bower_components/angular-ui-router/release/angular-ui-router.js',
'bower_components/ionic/js/ionic.js',
'bower_components/ionic/js/ionic-angular.js',
'bower_components/ng-cordova-oauth/dist/ng-cordova-oauth.js',
'bower_components/ngCordova/dist/ng-cordova.js',
'bower_components/ngCordova/dist/ng-cordova-mocks.js',
'bower_components/ngstorage/ngStorage.js',
//App code
'app/**/*.module.js',
'app/**/*.js',
'app/*.js',
//Test files
'test/**/*.test.js'
],
My pipeline looks like this:
// Client-side javascript files to inject in order
// (uses Grunt-style wildcard/glob/splat expressions)
var jsFilesToInject = [
// Dependencies like sails.io.js, jQuery, or Angular
'js/dependencies/sails.io.js',
'js/bower_components/angular/*.js',
'js/bower_components/**/*.js',
// All of the rest of your client-side js files
// will be injected here in no particular order.
'js/modules/app.js',
'js/modules/auth/services/accessLevels.js',
'js/**/*.js'
];
and my bower.json:
{
"name": "myapp",
"version": "0.0.1",
"dependencies": {
"angular": "1.3.7",
"angular-cookies": "1.3.7",
"angular-ui-router": "0.2.15"
},
"resolutions": {
"angular": "1.3.7"
}
}
I think this issue is because it's injecting angular.js and angular.min.js, any way to solve this with grunt?
I have a stable product which uses angular 1.2.23. Of late, I decided to move to angular 1.4.3. After few compatibility issues with all the dependencies, my application is working fine, but all the unit testcases have started failing..After investing I realized that if I upgrade versions of all dependencies but keep angular at the previous version i.e 1.2.23, the testcases work fine..With angular 1.4.3, for some reason the injections of the dependencies in unit tests are failing.
Following is the list of the updated dependencies in bower.json.
"dependencies": {
"angular-cookies": "1.4.3",
"bootstrap": "3.0.3",
"angular-ui-router": "0.2.15",
"angular-gettext": "2.1.0",
"angular": "1.4.3",
"angular-ui-utils": "3.0.0",
"restangular": "1.4.0",
"angular-route": "1.4.3",
"momentjs": "2.10.6",
"angular-i18n": "1.4.3"
}
Following is the test file -
describe("Module: x.xyz", function () {
describe("Factory: xyz", function () {
var service;
beforeEach(function () {
module('x.xyz');
inject(function ($injector) {
service = $injector.get("xyz");
});
});
describe("Testing service(): ", function () {
describe('Testing getXYZDescription(): ', function () {
it('should return the description for the xyz event name passed if it is available', function () {
expect(service.getXYZDescription('abc')).toBe('abc');
});
});
});
});
});
When I run the above test case, I get service is undefined. Can anyone help?
I ran into a similar issue when upgrading from angular 1.3 to 1.4. In my case, I forgot to upgrade angular-mocks from 1.3 to 1.4. I suspect that mocking functionality was broken out into a separate module in the transition from 1.2 to 1.3, although I can't seem to find documentation to confirm that. In that case, you wouldn't have needed an angular-mocks dependency for your original app, but you would need to add the dependency when upgrading.
You should be able to fix this by adding "angular-mocks": "1.4.x" to your list of dependencies and a link to installed file in your karma config. For completeness, here's a minimal example:
karma.conf.js:
/*global module*/
module.exports = function (config) {
'use strict';
config.set({
basePath: '.',
frameworks: ['jasmine'],
files: [
'node_modules/angular/angular.js',
'node_modules/angular-mocks/angular-mocks.js',
'*.js'
],
autoWatch: true,
singleRun: false,
browsers: ['Chrome']
});
};
package.json:
{
"name": "angular-inject-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "karma start karma.conf.js"
},
"author": "",
"dependencies": {
"angular": "1.4.x",
"angular-mocks": "1.4.x",
"karma": "^0.13.x",
"karma-cli": "^0.1.x",
"karma-jasmine": "^0.3.x",
"karma-chrome-launcher": "^0.2.x"
}
}
test.js:
/*global angular, beforeEach, describe, expect, inject, it, module*/
angular.module('x', [])
.factory('xyz', function () {
"use strict";
return {
getXYZDescription: function (value) {
return value;
}
};
});
describe("Module: x.xyz", function () {
"use strict";
describe("Factory: xyz", function () {
var service;
beforeEach(function () {
module('x');
inject(function ($injector) {
service = $injector.get("xyz");
});
});
it('Should echo input', function () {
expect(service.getXYZDescription('abc')).toBe('abc');
});
});
});
I'm trying to use Browserify + Debowerify to load Angular.js but I get a Uncaught TypeError: undefined is not a function in browser console after I run gulp serve at run the app. When I use npm to install Angular everything works.
In my package.json I have:
{
"browserify": {
"transform": [
"debowerify"
]
},
"devDependencies": {,
"browserify": "^5.10.0",
"browserify-ngannotate": "^0.1.0",
"debowerify": "^0.8.1",
"vinyl-source-stream": "^0.1.1"
...
}
}
I installed Angular with with
bower install angular
And inside my main.js I add:
require("angular");
In my gulpfile.js I have:
...
gulp.task('browserify', ['clean'], function() {
browserify('./app/scripts/main.js')
.transform(debowerify)
.transform(ngAnnotate)
.transform(uglifyify)
.bundle()
.pipe(source('main.js'))
.pipe($.streamify($.rename({suffix: '.min'})))
.pipe(gulp.dest('.tmp/scripts'));
});
...
Here's a pastebin of my bundled js file http://pastebin.com/Uar8VkVMI'm
What is it that I'm doing wrong? Any clues? Thanks!