This is my configuration for Karma:
options: {
browsers: ['PhantomJS'],
frameworks: ['jasmine'],
plugins: [
'karma-jasmine',
'karma-phantomjs-launcher'
],
reporters: 'dots',
urlRoot: '/',
autoWatch: false,
background: false,
singleRun: true,
basePath: '.',
},
tests: {
files: {
src: [
'lib/angular/build/angular.js',
'lib/angular/build/angular-mocks.js',
'src/components/**/*.js'
]
}
}
I've the following directive:
angular.module('myContainerModule', []).directive('myContainer', function() {
return {
restrict: 'E',
scope: {
},
replace: true,
transclude: true,
template: '<section ng-transclude></section>',
compile: function() {
console.log('compile');
return {
pre: function() {
console.log('pre-link');
},
post: function() {
console.log('post-link');
}
};
},
controller: function() {
console.log('controller')
}
};
})
Also the unit test for that:
describe('myContainer', function () {
var element, scope;
beforeEach(angular.module('myContainerModule'))
beforeEach(inject(function($rootScope, $compile) {
element = angular.element(
'<my-container>' +
' {{foo}}' +
'</my-container>'
);
scope = $rootScope;
scope.foo = 'bar';
$compile(element)(scope);
scope.$digest();
}))
it('should be replaced by a `section` tag', function() {
console.log(element[0].outerHTML);
expect(element[0].tagName).toBe('SECTION');
})
})
The test runner tells me:
Running "karma:tests" (karma) task
INFO [karma]: Karma v0.12.31 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
INFO [PhantomJS 1.9.8 (Linux)]: Connected on socket 1XZDEfFUCHhoCoH7a5LR with id 14712662
LOG: '<my-container class="ng-binding ng-scope"> bar</my-container>'
..
PhantomJS 1.9.8 (Linux) Container should be replaced by a `section` tag FAILED
Expected 'MY-CONTAINER' to be 'SECTION'.
at [...]
Why is the directive myContainer ignored? When I do the same manually in the browser it works.
The problem is this line the unit test:
beforeEach(angular.module('myContainerModule'))
It has to be:
beforeEach(module('myContainerModule'))
Related
I am trying to run test cases for my application but stuck in between. Its giving the below error -
Error: [$injector:modulerr] Failed to instantiate module ng due to:
TypeError: 'undefined' is not an object (evaluating 'Function.prototype.bind.apply')
.......
......
{path}/test/unit/generate-form-directive.js:24
Test file is (generate-form-directive.js) -
describe("UNIT DIRECTIVE: generateForm", function () {
"use strict";
// Angular injectables
var $compile, $rootScope, $httpBackend;
// Module defined (non-Angular) injectables
var $scope, directiveScope, pagerVm;
// Local variables used for testing
var template;
// Initialize modules
beforeEach(function () {
module("TestDataModule");
});
beforeEach(function () {
inject(function (_$compile_, _$rootScope_, _$httpBackend_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
$httpBackend = _$httpBackend_;
}); //Line no 24
});
it("test message", function() {
console.log("Hello");
});
});
My Karma file (karma.conf.js) -
module.exports = function (config) {
config.set({
basePath: "",
frameworks: ["mocha", "chai", "sinon"],
files: [
"node_modules/angular/angular.js",
"node_modules/angular-mocks/angular-mocks.js",
// Add template files
"src/**/*.html",
"src/commons/js/*.js",
"src/commons/services/*.js",
"src/commons/directives/**/*.js",
"src/modules/**/*.js",
// Add all the test files
"test/unit/*.js",
],
exclude: [],
preprocessors: {
"src/**/*.js": "coverage"
},
reporters: ["mocha", "coverage"],
mochaReporter: {
// full, autowatch, minimal
output: "autowatch",
ignoreSkipped: false
},
browserNoActivityTimeout: 20000,
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ["PhantomJS"],
singleRun: true,
coverageReporter: {
dir: "./coverage",
reporters: [{
type: "cobertura",
subdir: ".",
file: "cobertura.xml"
}, {
type: "text"
}]
}
});
};
Thanks in advance.
I had the same problem. The minimatch pattern ('/**/*') did not worked in karma.conf.js.
You have two options:
1) Try to change your minimatch version and see if it helps.
2) Or specify each file instead of using the minimatch pattern ("/**/*.js").
Change karma configuration file for something like this:
// Add template files
"src/views/view1.html",
"src/views/view2.html",
"src/commons/js/myJs1.js",
"src/commons/services/service1.js",
"src/commons/services/service2.js",
"src/commons/directives/directive1.js",
"src/modules/moduleName/moduleNAme1.js",
// Add all the test files
"test/unit/testFile1.js",
I'm testing a really simple directive using Karma :
.directive('a', function() {
return {
restrict: 'A',
controller: function() {
}
}
})
.directive('b', function() {
return {
restrict: 'E',
require: ['^a'],
link: function() {
}
}
})
It works in an HTML page but using karma i got the following error :
Error: [$compile:ctreq] Controller 'a', required by directive 'b',
can't be found!
Using the following code in a karma/jasmine test :
var html = angular.element('<div a />\
<b>directive content</b>\
</div>')[0];
body.appendChild(html);
$compile(html)(scope);
Any ideas ?
Here are the full files :
karma.conf.js
// Karma configuration
// Generated on Fri Feb 26 2016 20:08:50 GMT+0100 (CET)
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: [
'node_modules/angular/angular.js',
'node_modules/angular-mocks/angular-mocks.js',
'directives.js',
'test.spec.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: {
'src/!(*.mock|*.spec).js': ['coverage']
},
coverageReporter: {
type : 'html',
// output coverage reports
dir : 'coverage/'
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress', 'coverage'],
// 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', 'Firefox'],
// 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
})
}
directives.js
(function(angular) {
angular.module('directives', [])
.directive('a', function() {
return {
restrict: 'A',
controller: function() {
}
}
})
.directive('b', function() {
return {
restrict: 'E',
require: ['^a'],
link: function() {
}
}
});
})(angular);
directives.spec.js
describe('Simple test', function() {
var body, $compile, $rootScope, scope;
beforeEach(module('directives'));
beforeEach(inject(['$compile', '$rootScope', function(_$compile, _$rootScope) {
$compile = _$compile;
$rootScope = _$rootScope;
scope = $rootScope.$new();
body = document.querySelector('body');
}]));
it('should work', function() {
var html = angular.element('<div a />\
<b>directive content</b>\
</div>')[0];
body.appendChild(html);
$compile(html)(scope);
});
});
question
I replace templateUrl with template in author-signature.js, then I test success.
But I use templateUrl way in author-signature.js, I test fail. I watch files loading and chrome debug, author-signature.html did translate to js, and html content did exist in $templateCache too, but I test fail. Printscreen:
author-signature.html.js
$templateCache debug content
filepath
--public
----scripts
--------**/*.js
--test
----**/*.js
--views
----templates
--------**/*.html
test-main.js
require.js main entry file
var allTestFiles = [];
var TEST_REGEXP = /(\-test)\.js$/i;
Object.keys(window.__karma__.files).forEach(function (file) {
if (window.__karma__.files.hasOwnProperty(file)) {
if (TEST_REGEXP.test(file)) {
allTestFiles.push(file);
}
}
});
require.config({
baseUrl: '/base/public/scripts',
paths: {
'jquery': '../libs/jquery/dist/jquery',
'angular': '../libs/angular/angular',
'angularMocks': '../libs/angular-mocks/angular-mocks',
'templates': '../../views/templates'
},
shim: {
'angular': {
deps: ['jquery'],
exports: 'angular'
},
'angularMocks': {
deps: ['angular'],
exports: 'angular.mock'
},
'templates/default/author-signature.html': ['angular']
},
deps: allTestFiles,
callback: window.__karma__.start
});
karma.conf.js
karma configuration file, I translate js to html by ng-html2js
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', 'requirejs'],
files: [
{pattern: 'public/libs/jquery/dist/jquery.js', included: false},
{pattern: 'public/libs/angular/angular.js', included: false},
{pattern: 'public/libs/angular-mocks/angular-mocks.js', included: false},
{pattern: 'public/scripts/**/*.js', included: false},
{pattern: 'views/templates/**/*.html', included: false},
{pattern: 'test/**/*-test.js', included: false},
'test/test-main.js'
],
exclude: [
'public/scripts/build-main.js',
'public/scripts/require-config.js',
'public/scripts/bootstrap.js'
],
browsers: ['Chrome'],
reporters: ['progress', 'html', 'coverage'],
htmlReporter: {
outputFile: 'report/units.html',
pageTitle: 'Unit Tests',
subPageTitle: 'Unit tests with karma jasmine'
},
preprocessors: {
'public/scripts/**/*.js': ['coverage'],
'views/templates/**/*.html': ['ng-html2js']
},
coverageReporter: {
type: 'html',
dir: 'report/coverage/'
},
ngHtml2JsPreprocessor: {
stripPrefix: 'views/',
stripSuffix: '.html',
moduleName: 'templates'
}
});
}
author-signature-test.js
directive test file
define(['angularMocks', 'directives/default/author-signature', 'templates/default/author-signature.html'], function () {
describe('Unit: Hello Directive', function () {
var $compile, $rootScope;
beforeEach(function () {
module('angularApp');
module('templates');
inject(function (_$compile_, _$rootScope_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
});
});
it('should display the hello text properly', function () {
var elt = $compile('<author-signature author="Plus"></author-signature>')($rootScope);
expect(elt.text()).toEqual('Plus');
});
});
});
author-signature.js
simply directive file
define('directives/default/author-signature', [
'angular-app'
], function (angularApp) {
angularApp.directive('authorSignature', function () {
return {
restrict: 'EA',
scope: {
author: '#'
},
replace: true,
templateUrl: 'templates/default/author-signature'
};
});
});
author-signature.html
<h1>{{author}}</h1>
angular-app.js
define('angular-app', [
'angular'
], function (angular) {
var angularApp = angular.module('angularApp', []);
return angularApp;
});
OMG, I forget add $rootScope.$digest(); in test directive.
That cause this directive scope's attributes doesn't change.
New to jasmine tests. So sorry if this is a dumb question. I'm trying to do a simple unit test of a controller's existence in AngularJS code, and I can't get over this error. It's something silly I'm sure. I've looked all over stackoverflow, and tried many different things based on similar error but to not avail. Keep getting the error.
Here's the app.js
angular.module('waldo', ['ui.router'])
.config(['$stateProvider','$urlRouterProvider',function($stateProvider,$urlRouterProvider){
$stateProvider
.state('home', {
url: '/home',
templateUrl: '/home.html',
controller: 'MainController'
})
.state('posts', {
url: '/posts/{id}',
templateUrl: '/posts.html',
controller: 'PostsController'
});
$urlRouterProvider.otherwise('home');
}])
.factory('posts',[function(){
var o = {
posts: []
};
return o;
}])
.controller('MainController', [
'$scope','posts',
function($scope,posts){
$scope.posts = posts.posts;
$scope.addPost = function(){
if(!$scope.title || $scope.title === '') { return; }
$scope.posts.push({
title: $scope.title,
link: $scope.link,
upvotes: 0,
comments: [
{author: 'Joe', body: 'Cool post!', upvotes: 0},
{author: 'Bob', body: 'Great idea but everything is wrong!', upvotes: 0}
]
});
$scope.title = '';
};
$scope.incrementUpvotes = function(post) {
post.upvotes += 1;
};
}])
.controller('PostsController',['$scope','$stateParams','posts',function($scope,$stateParams,posts){
$scope.post = posts.posts[$stateParams.id];
}]);
Test:
describe('test that', function() {
beforeEach(module('waldo'));
describe('MainController', function () {
var scope, createController;
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
createController = function () {
return $controller('MainController', {
'$scope': scope
});
};
}));
it('exists', function () {
var controller = createController();
expect(controller).not.toBeNull();
});
});
});
karma.conf.js
// Karma configuration
// Generated on Wed Apr 08 2015 13:46:46 GMT-0400 (EDT)
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: [
"vendor/assets/bower_components/angular/angular.js",
"vendor/assets/bower_components/angular-mocks/angular-mocks.js",
"app.js",
"test/*.js",
"test/*/*_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: {
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// 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: ['Firefox'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false
});
};
bower.json
{
"name": "waldo",
"version": "0.0.0",
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"angular": "~1.3.15",
"angular-ui-router": "~0.2.13",
"bootstrap": "~3.3.4"
},
"devDependencies": {
"angular-mocks": "~1.3.15"
}
}
Error is:
minErr/<#/home/christian/Projects/waldo/vendor/assets/bower_components/angular/angular.js:63:12
loadModules/<#/home/christian/Projects/waldo/vendor/assets/bower_components/angular/angular.js:4138:15
forEach#/home/christian/Projects/waldo/vendor/assets/bower_components/angular/angular.js:323:11
loadModules#/home/christian/Projects/waldo/vendor/assets/bower_components/angular/angular.js:4099:5
createInjector#/home/christian/Projects/waldo/vendor/assets/bower_components/angular/angular.js:4025:11
workFn#/home/christian/Projects/waldo/vendor/assets/bower_components/angular-mocks/angular-mocks.js:2425:44
TypeError: createController is not a function in /home/christian/Projects/waldo/test/integration/first_test.js (line 17)
#/home/christian/Projects/waldo/test/integration/first_test.js:17:30
Thanks.
Maybe you have to put your module dependency in your karma.conf.js that in your case is 'ui.router', for example:
...
files: [
"vendor/assets/bower_components/angular/angular.js",
"vendor/assets/bower_components/angular-mocks/angular-mocks.js",
"vendor/assets/bower_components/angular-ui-router/angular-ui-router.js",
"app.js",
"test/*.js",
"test/*/*_test.js"
],
...
Then run again the test.
Also take a look at these links, they were very useful to me
Unit testing a service in angularJS
http://jamesreubenknowles.com/angularjs-nglocale-error-1952
https://docs.angularjs.org/error/$injector/nomod?p0=ngLocale
I am getting a failed test with the error ReferenceError: dmeApp is not defined. Do I need to inject dmeApp into the test? I'm following a tutorial I found here: http://andyshora.com/unit-testing-best-practices-angularjs.html
app.js:
angular.module('dmeApp', ['ngRoute', 'dmeApp.library'])
.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider
.when('/library', {
templateUrl: 'library.html',
controller: 'LibraryController',
})
.when('/styleguide', {
templateUrl: 'styleguide.html',
})
.otherwise({
templateUrl: 'front.html',
});
$locationProvider.html5Mode(true);
}])
.controller('NavController', ['$scope', '$location', function($scope, $location) {
$scope.linkIsActive = function(viewLocation) {
return viewLocation === $location.path();
};
}]);
app.spec.js:
describe('Header Navigation', function() {
beforeEach(angular.module('dmeApp'));
it('should have a NavController defined', function() {
expect(dmeApp.NavController).toBeDefined();
});
});
And my Karma config (in Gruntfile.js):
/**
* Our Karma configuration.
*/
karma: {
options: {
files: [
'<%= vendor_files.js %>',
'<%= vendor_files.offline_js %>', // angular is added here
'<%= vendor_files.test_js %>', // angular-mock is added here
'src/**/*.js', // all app files and specs are added here
],
browsers: ['Chrome'],
frameworks: ['jasmine'],
},
dev: {
reporters: 'dots',
background: true,
},
continuous: {
singleRun: true,
},
},
in the spec.js in the beforeEach try something like:
beforeEach(inject(function($injector) {
var dmeAppNavController = $injector.get('dmeApp.NavController');
...
}
then you can use dmeAppNavController in the testcases.
imho almost always a good idea to use the $injector in the test cases