I am trying to build basic unit tests for an Angular 1.5 with the purpose of A) practicing unit testing, and B) familiarizing myself with component-based development in Angular 1.5.x. I'm trying to unit test a simple component, but I keep getting the following message:
Error: [$injector:modulerr] Failed to instantiate module app due to:
Error: [$injector:modulerr] Failed to instantiate module
ngComponentRouter due to:
Error: [$injector:nomod] Module
'ngComponentRouter' 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'd like a little guidance on how to inject this specific dependency/module into a unit test. This is the code I have:
app.js
(function(){
"use strict";
const app = angular.module("app", ["ngComponentRouter"])
app.value("$routerRootComponent", "componentApp");
})();
component-app.component.js
(function(){
"use strict";
angular.module("app").component("componentApp", {
templateUrl: "/javascripts/component-app.component.html",
controller: ["$router", function($router){
$router.config([
{ path: "/users", component: "usersComponent", name: "Users" },
{ path: "/**", redirectTo: ["Users"]}
]);
}]
});
})();
component-app.component.spec.js
describe("componentApp component", function(){
beforeEach(module("app"));
var $componentController, componentApp;
beforeEach(inject(function($injector){
$componentController = $injector.get("$componentController");
componentApp = $componentController("componentApp", { $scope: {}});
}));
it("componentApp component is defined", function(){
expect(componentApp).toBeDefined();
});
});
So two changes did the trick, first I need to change component-app.component.js:
angular.module("app").component("componentApp", {
templateUrl: "/templates/component-app.component.html",
$routeConfig: [
{ path: "/Users", name: "Users", component: "usersComponent" },
{ path: "/Home", name: "Home", component: "homeComponent"},
{ path: "/Profile/:id", name: "Profile", component: "profileComponent" },
{ path: "/**", redirectTo: ["Users"]}
]
});
And I needed to include the file in karma.conf.js:
module.exports = function(config) {
config.set({
basePath: "",
frameworks: ["jasmine"],
files: [
"bower_components/angular/angular.js",
"bower_components/angular-mocks/angular-mocks.js",
"bower_components/angular-component-router/angular_1_router.js",
"javascripts/**/*.js"
],
exclude: [
],
preprocessors: {
},
reporters: ["progress"],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ["Chrome"],
singleRun: false,
concurrency: Infinity
});
};
Related
I've some problems when testing angular directives with karma, the problem is that when comes from templateUrl never translate it.
here is my karma.conf.js
'use strict';
var wiredep = require('wiredep');
var bowerFiles = wiredep().js;
var appFiles = [
'src/modules/**/*-module.js',
'src/modules/**/**/*.js',
{ pattern: 'src/modules/**/*.mol', watched: true, served: true, included: false },
'src/modules/**/**/templates/*.html',
{
pattern: '../src/assets/images/*.*',
watched: false,
included: false,
served: true
},
'src/modules/**/**/templates/*.html'
];
module.exports = function (config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: [
'mocha',
'chai',
'sinon-chai'
],
junitReporter: {
outputFile: '../reports/test-results/test-results.xml'
},
coverageReporter: {
dir: 'reports/test-coverage/',
subdir: function (browser) {
// normalization process to keep a consistent browser name across different OS
return browser.toLowerCase().split(/[ /-]/)[0];
},
check: {
global: {
statements: 10,
branches: 1,
functions: 10,
lines: 10
},
each: {
statements: 0,
branches: 0,
functions: 0,
lines: 0
}
},
reporters: [
{ type: 'html', file: 'coverage.html' },
{ type: 'cobertura', file: 'coverage.xml' },
{ type: 'json' },
{ type: 'text-summary' }
]
},
reporters: ['junit', 'dots', 'coverage'],
// list of files / patterns to load in the browser
files: [].concat(bowerFiles, appFiles),
// list of files to exclude
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'src/modules/**/**/!(*.test).js': 'coverage',
'src/modules/**/**/templates/*.html': ['ng-html2js']
},
ngHtml2JsPreprocessor: {
stripPrefix: 'src/',
moduleName: 'templates'
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// Concurrency level
// how many browser should be started simultaneous
concurrency: Infinity
});
};
And the test ...
'use strict';
describe('dra-header-directive', function () {
var compile;
var rootScope;
var templateCache;
beforeEach(module('dd'));
beforeEach(module('templates'));
beforeEach(inject(function ($compile, $rootScope, $templateCache) {
compile = $compile;
rootScope = $rootScope;
templateCache = $templateCache;
}));
it('Replace the element with the appropiate element', function () {
var scope = rootScope.$new();
var el = angular.element('<testing></testing><dra-header></dra-header><input-bar></input-bar>');
var element = compile(el)(scope);
scope.$digest();
console.log(element);
});
});
The first tag is translated due to is not defined as templateUrl, but the others don't.
if I get the templates with $templateCache I can read the content, so I asume ng-html2js is doing it's job. any ideas?
Thanks for helping!
Its solved, I changed the before each module to avoid importing unnecesary module dependencies, looks like there was something that was modifying my rootScope, I just loaded the module that has the directive, and now works fine
'use strict';
describe('dra-header-directive', function () {
var compile;
var scope;
var templateCache;
beforeEach(module('dra.components.DRAHeaderModule'));
beforeEach(function () {
module('templates');
});
beforeEach(inject(function ($compile, $rootScope, $templateCache) {
compile = $compile;
templateCache = $templateCache;
scope = $rootScope.$new();
}));
it('Replace the element with the appropiate element', function () {
var el = angular.element('<dra-header></dra-header>');
compile(el)(scope);
scope.$digest();
expect(el.find('div')[0]).to.not.be.undefined();
});
});
karma.config.js:
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['jasmine'],
files: [
'node_modules/angular/angular.min.js',
'node_modules/angular-mocks/angular-mocks.js',
'node_modules/angular-translate/dist/angular-translate.min.js',
'browser/javascripts/*.js',
'browser/tests/*.spec.js'
],
exclude: [],
preprocessors: {},
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
concurrency: Infinity
})
};
home.spec.js:
describe('Home Controller', function() {
beforeEach(
module('pascalprecht.translate'),
module('tradeshiftApp')
);
var $controller;
beforeEach(inject(function(_$controller_){
$controller = _$controller_;
}));
it('should exist', function(){
controller = $controller('HomeController', {
$scope: {}
});
expect(controller).not.toBe(undefined);
})
});
I am using karma-jasmine and the problem is following: my app.js file has this module and it's loading correctly:
var app = angular.module('tradeshiftApp', ['pascalprecht.translate']);
But when I try to mock my controller, which is
app.controller('HomeController', function ($scope, $req, $window, $translate, $q) {
// some code
});
I get an error, which says that HomeController is not a function. As you can see, dependencies are wired up and everything should be fine, I guess. Any tips?
Note: I've tried to inject $rootScope and get $rootScope.$new() and it's successful.
Try this:
beforeEach(function() {
angular.module('pascalprecht.translate', [])
angular.mock.module('tradeshiftApp')
}
);
So, the problem was in 'pascalprecht.translate' module. In my code I have a small dependency wired to the foregoing module, which was included in my HTML file, but not in my Karma config file. Guys, be careful and vigilant about your code :)
I've a small unitTest in Jasmine run with Karma. But when i run Karma it show errors:
Uncaught Error: [$injector:nomod] Module 'material.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.
FAILED Unit: LoginController encountered a
declaration exception
ReferenceError: module is not defined
Here are my source code, config Karma file and unitTest.
karma.conf.js
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'/home/tanpham/Angular/Dev/libs/angular/angular.js',
'/home/tanpham/Angular/Dev/js/**/*.js',
'/home/tanpham/Angular/Dev/js/*.js',
'/home/tanpham/Angular/Test/*.js'
],
// list of files to exclude
exclude: [
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
},
index.html
<body ng-app="material" ng-controller="AppController">
<ui-view></ui-view>
</body>
app.js
angular.module('material.controllers', []);
angular.module('material.services', []);
angular.module('material.directives',[]);
angular.module('material.filters',[]);
var app = angular.module('material', ['ui.router','material.directives','http-auth-interceptor','material.controllers','material.services','material.filters'])
.config(function($stateProvider, $urlRouterProvider,$locationProvider) {
$stateProvider
.state('app', {
url: "/app",
abstract: true,
templateUrl: "views/app.html"
}).state('login', {
url: "/login",
templateUrl: "views/login.html",
controller: "LoginController"
});
$urlRouterProvider.otherwise('/login');
})
loginController
angular.module('material.controllers').controller('LoginController', function($scope) {
$scope.name = "Ari";
$scope.sayHello = function() {
$scope.greeting = "Hello " + $scope.name;
}
});
helloSpec.js
describe('Unit: LoginController', function() {
// Load the module with LoginController
beforeEach(module('material.controllers'));
var ctrl, scope;
// inject the $controller and $rootScope services
// in the beforeEach block
beforeEach(inject(function($controller, $rootScope) {
// Create a new scope that's a child of the $rootScope
scope = $rootScope.$new();
// Create the controller
ctrl = $controller('LoginController', {
$scope: scope
});
}));
it('should create $scope.greeting when calling sayHello',
function() {
expect(scope.greeting).toBeUndefined();
scope.sayHello();
expect(scope.greeting).toEqual("Hello Ari");
});
})
So, i can do with that and my module's name is right?
Check the order in which the angular modules are loaded. As your listing of javascript files in karma conf, see if the module defined files are loaded first before other files that use it.
Adjust the order in this listing, are explicitly load the file where 'material.controllers' module is defined.
files: [
'/home/tanpham/Angular/Dev/libs/angular/angular.js',
'/home/tanpham/Angular/Dev/js/**/*.js',
'/home/tanpham/Angular/Dev/js/*.js',
'/home/tanpham/Angular/Test/*.js'
],
i have met this issue. and solved it.
just add ",[]" behind the module name in the module declare statement。 in this case chaged code will be :
angular.module('material.controllers',[])
.controller('LoginController', function($scope) {
$scope.name = "Ari";
$scope.sayHello = function() {
$scope.greeting = "Hello " + $scope.name;
}
});
I have an application which uses requireJS, and I would like to use grunt-contrib-jasmie to test it. In order to get jasmine to work with require I am using cloudchen's grunt-template-jasmine-requirejs. The application has the following directory structure:
topLevelApplicationFolder
|_app.html
|_Gruntfile.js
|_package.json
|_js
|_app.js
|_app
|_modules
|_rgbaHelpers.js
|_main.js
|_lib
|_require.js
|_spec
|_rgba_spec.js
app.js is my requireJS config file:
requirejs.config({
baseUrl: "js/lib",
paths: {
app: "../app"
},
shim: {
spectrum: {
deps: ["jquery"],
exports: "spectrum"
}
}
});
// Load the main app module to start the app
requirejs(["app/main"]);
And my Gruntfile.js is the following:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
jasmine : {
taskName: {
src : 'js/**/*.js',
options : {
specs : 'spec/**/*.js',
template: require('grunt-template-jasmine-requirejs'),
templateOptions: {
requireConfig: {
baseUrl: 'js/lib'
}
// requireConfigFile: './js/app.js'
}
}
}
},
jshint: {
all: [
'Gruntfile.js',
'js/**/*.js',
'spec/**/*.js'
],
options: {
jshintrc: '.jshintrc'
}
}
});
grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.registerTask('test', ['jshint', 'jasmine']);
grunt.registerTask('default', ['test']);
};
The rgba_spec.js is the test I would like to run. It is very simple:
define(['js/app/modules/rgbaHelpers'], function (rgbaHelpers) {
describe('A suite', function() {
it('should pass this test', function() {
expect(rgbaHelpers).not.toBe(null);
});
});
});
But when I run grunt jasmine I get the following error:
Error: scripterror: Illegal path or script error: ['js/app/modules/rgbaHelpers']
I have been scratching my head over this all day. Does anyone know what is going on here?
So I was able to fix this issue by completely removing the requireConfig and baseURL from the template options:
jasmine : {
taskName: {
src : 'js/**/*.js',
options : {
specs : 'spec/**/*.js',
template: require('grunt-template-jasmine-requirejs'),
templateOptions: {
}
}
}
}
Then at the top of each spec I would do something like this:
define(['js/app/modules/mouseHelpers'], function (mouseHelpers) {
Having a few issues with testing a directive - our application is trying to be modular hence the need for module.exports which exports the angular module;
module.exports = angular.module('project', [])
.config(function ($stateProvider) {
$stateProvider
.state('alive', {
url: '/college',
templateUrl: 'dashboard.html',
controller: 'CollegeCtrl',
authenticate: true
});
})
.factory('College', require('./services/college.service.js'))
.controller('CollegeCtrl', require('./dashboard/college.controller.js'))
.directive('collegeTile', require('./dashboard/tile/tile.directive.js'))
.run(function ($rootScope, SideFactory) {
SideFactory.push({
'priority': 1,
'icon': 'fa-th-large'
});
});
Directive looks like this;
<div class="thumbnail" ng-click="openProject(college._id)">
<span>{{college}}</span>
</div>
</div>
The directive spec looks like this - note, the templates loads in all the html templates;
'use strict';
describe('Directive: tile', function () {
var $compile;
var $scope;
// load the directive's module and view
beforeEach(module('ui.router'));
beforeEach(module('project'));
beforeEach(module('templates'));
// Create the SideFactory
beforeEach(module(function ($provide) {
var sideFactory = {
push: function () {
}
};
$provide.value('SideFactory', sideFactory);
}));
beforeEach(inject(function (_$compile_, _$rootScope_) {
$compile = _$compile_;
$scope = _$rootScope_.$new();
}));
it("should validate to true", function () {
expect(true).toBe(true);
});
});
I get the following error when running karma;
TypeError: 'undefined' is not a function (evaluating 'expect(true).toBe(true)')
Karma config;
module.exports = function (config) {
config.set({
// base path, that will be used to resolve files and exclude
basePath: '',
// testing framework to use (jasmine/mocha/qunit/...)
frameworks: ['jasmine', 'chai'],
// list of files / patterns to load in the browser
files: [
'dev/assets/bundle.js',
'angular-mocks/angular-mocks.js',
'sample/client/*.html',
'sample/client/*.spec.js',
'client/**/*.html',
'client/**/*.spec.js'
],
preprocessors: {
'client/**/*.html': ['ng-html2js']
},
ngHtml2JsPreprocessor: {
// strip this from the file path
stripPrefix: 'client/',
prependPrefix: 'college/',
// setting this option will create only a single module that contains templates
// from all the files, so you can load them all with module('foo')
moduleName: 'templates'
},
// list of files / patterns to exclude
exclude: [],
// test results reporter to use
// possible values: 'dots', 'progress', 'junit'
reporters: ['progress', 'coverage'],
coverageReporter: {
type: 'html',
dir: 'coverage'
},
// enable / disable colors in the output (reporters and logs)
colors: true,
// web server port
port: 8080,
// level of logging: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel: 'INFO',
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// - IE (only Windows)
browsers: ['PhantomJS'],
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false
});
};