Unit Testing AngularJS directive with templateUrl - angularjs

Using AngularJS.
Have a directive.
Directive defines templateUrl.
Directive needs unit testing.
Currently unit testing with Jasmine.
This recommends code like:
describe('module: my.module', function () {
beforeEach(module('my.module'));
describe('my-directive directive', function () {
var scope, $compile;
beforeEach(inject(function (_$rootScope_, _$compile_, $injector) {
scope = _$rootScope_;
$compile = _$compile_;
$httpBackend = $injector.get('$httpBackend');
$httpBackend.whenGET('path/to/template.html').passThrough();
}));
describe('test', function () {
var element;
beforeEach(function () {
element = $compile(
'<my-directive></my-directive>')(scope);
angular.element(document.body).append(element);
});
afterEach(function () {
element.remove();
});
it('test', function () {
expect(element.html()).toBe('asdf');
});
});
});
});
Running code in Jasmine.
Getting error:
TypeError: Object #<Object> has no method 'passThrough'
templateUrl needs loading as-is
Cannot use respond
May be related to ngMock use rather than ngMockE2E use.

You're correct that it's related to ngMock. The ngMock module is automatically loaded for every Angular test, and it initializes the mock $httpBackend to handle any use of the $http service, which includes template fetching. The template system tries to load the template through $http and it becomes an "unexpected request" to the mock.
What you need a way to pre-load the templates into the $templateCache so that they're already available when Angular asks for them, without using $http.
The Preferred Solution: Karma
If you're using Karma to run your tests (and you should be), you can configure it to load the templates for you with the ng-html2js preprocessor. Ng-html2js reads the HTML files you specify and converts them into an Angular module that pre-loads the $templateCache.
Step 1: Enable and configure the preprocessor in your karma.conf.js
// karma.conf.js
preprocessors: {
"path/to/templates/**/*.html": ["ng-html2js"]
},
ngHtml2JsPreprocessor: {
// If your build process changes the path to your templates,
// use stripPrefix and prependPrefix to adjust it.
stripPrefix: "source/path/to/templates/.*/",
prependPrefix: "web/path/to/templates/",
// the name of the Angular module to create
moduleName: "my.templates"
},
If you are using Yeoman to scaffold your app this config will work
plugins: [
'karma-phantomjs-launcher',
'karma-jasmine',
'karma-ng-html2js-preprocessor'
],
preprocessors: {
'app/views/*.html': ['ng-html2js']
},
ngHtml2JsPreprocessor: {
stripPrefix: 'app/',
moduleName: 'my.templates'
},
Step 2: Use the module in your tests
// my-test.js
beforeEach(module("my.templates")); // load new module containing templates
For a complete example, look at this canonical example from Angular test guru Vojta Jina. It includes an entire setup: karma config, templates, and tests.
A Non-Karma Solution
If you do not use Karma for whatever reason (I had an inflexible build process in legacy app) and are just testing in a browser, I have found that you can get around ngMock's takeover of $httpBackend by using a raw XHR to fetch the template for real and insert it into the $templateCache. This solution is much less flexible, but it gets the job done for now.
// my-test.js
// Make template available to unit tests without Karma
//
// Disclaimer: Not using Karma may result in bad karma.
beforeEach(inject(function($templateCache) {
var directiveTemplate = null;
var req = new XMLHttpRequest();
req.onload = function() {
directiveTemplate = this.responseText;
};
// Note that the relative path may be different from your unit test HTML file.
// Using `false` as the third parameter to open() makes the operation synchronous.
// Gentle reminder that boolean parameters are not the best API choice.
req.open("get", "../../partials/directiveTemplate.html", false);
req.send();
$templateCache.put("partials/directiveTemplate.html", directiveTemplate);
}));
Seriously, though. Use Karma. It takes a little work to set up, but it lets you run all your tests, in multiple browsers at once, from the command line. So you can have it as part of your continuous integration system, and/or you can make it a shortcut key from your editor. Much better than alt-tab-refresh-ad-infinitum.

What I ended up doing was getting the template cache and putting the view in there. I don't have control over not using ngMock, it turns out:
beforeEach(inject(function(_$rootScope_, _$compile_, $templateCache) {
$scope = _$rootScope_;
$compile = _$compile_;
$templateCache.put('path/to/template.html', '<div>Here goes the template</div>');
}));

This initial problem can be solved by adding this:
beforeEach(angular.mock.module('ngMockE2E'));
That's because it tries to find $httpBackend in ngMock module by default and it's not full.

The solution I reached needs jasmine-jquery.js and a proxy server.
I followed these steps:
In karma.conf:
add jasmine-jquery.js to your files
files = [
JASMINE,
JASMINE_ADAPTER,
...,
jasmine-jquery-1.3.1,
...
]
add a proxy server that will server your fixtures
proxies = {
'/' : 'http://localhost:3502/'
};
In your spec
describe('MySpec', function() {
var $scope, template;
jasmine.getFixtures().fixturesPath = 'public/partials/'; //custom path so you can serve the real template you use on the app
beforeEach(function() {
template = angular.element('');
module('project');
inject(function($injector, $controller, $rootScope, $compile, $templateCache) {
$templateCache.put('partials/resources-list.html', jasmine.getFixtures().getFixtureHtml_('resources-list.html')); //loadFixture function doesn't return a string
$scope = $rootScope.$new();
$compile(template)($scope);
$scope.$apply();
})
});
});
Run a server on your app's root directory
python -m SimpleHTTPServer 3502
Run karma.
It took my a while to figure this out, having to search many posts, I think the documentation about this should be clearer, as it is such an important issue.

My solution:
test/karma-utils.js:
function httpGetSync(filePath) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/base/app/" + filePath, false);
xhr.send();
return xhr.responseText;
}
function preloadTemplate(path) {
return inject(function ($templateCache) {
var response = httpGetSync(path);
$templateCache.put(path, response);
});
}
karma.config.js:
files: [
//(...)
'test/karma-utils.js',
'test/mock/**/*.js',
'test/spec/**/*.js'
],
the test:
'use strict';
describe('Directive: gowiliEvent', function () {
// load the directive's module
beforeEach(module('frontendSrcApp'));
var element,
scope;
beforeEach(preloadTemplate('views/directives/event.html'));
beforeEach(inject(function ($rootScope) {
scope = $rootScope.$new();
}));
it('should exist', inject(function ($compile) {
element = angular.element('<event></-event>');
element = $compile(element)(scope);
scope.$digest();
expect(element.html()).toContain('div');
}));
});

If you are using Grunt, you can use grunt-angular-templates. It loads your templates in the templateCache and it's tranparent to your specs configuration.
My sample config:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
ngtemplates: {
myapp: {
options: {
base: 'public/partials',
prepend: 'partials/',
module: 'project'
},
src: 'public/partials/*.html',
dest: 'spec/javascripts/angular/helpers/templates.js'
}
},
watch: {
templates: {
files: ['public/partials/*.html'],
tasks: ['ngtemplates']
}
}
});
grunt.loadNpmTasks('grunt-angular-templates');
grunt.loadNpmTasks('grunt-contrib-watch');
};

I solved the same problem in a slightly different way than the chosen solution.
First, I installed and configured the ng-html2js plugin for
karma. In the karma.conf.js file :
preprocessors: {
'path/to/templates/**/*.html': 'ng-html2js'
},
ngHtml2JsPreprocessor: {
// you might need to strip the main directory prefix in the URL request
stripPrefix: 'path/'
}
Then I loaded the module created in the beforeEach.
In your Spec.js file :
beforeEach(module('myApp', 'to/templates/myTemplate.html'));
Then I used $templateCache.get to store it into a variable.
In your Spec.js file :
var element,
$scope,
template;
beforeEach(inject(function($rootScope, $compile, $templateCache) {
$scope = $rootScope.$new();
element = $compile('<div my-directive></div>')($scope);
template = $templateCache.get('to/templates/myTemplate.html');
$scope.$digest();
}));
Finally, I tested it this way.
In your Spec.js file:
describe('element', function() {
it('should contain the template', function() {
expect(element.html()).toMatch(template);
});
});

To load the template html dynamically into $templateCache you could just use html2js karma pre-processor, as explained here
this boils down to adding templates '.html' to your files in the conf.js file
as well
preprocessors = {
'.html': 'html2js'
};
and use
beforeEach(module('..'));
beforeEach(module('...html', '...html'));
into your js testing file

if you're using Karma, consider using karma-ng-html2js-preprocessor to pre-compile your external HTML templates and avoid having Angular try to HTTP GET them during test execution. I struggled with this for a couple of ours - in my case templateUrl's partial paths resolved during normal app execution but not during tests - due to differences in app vs. test dir structures.

If you are using the jasmine-maven-plugin together with RequireJS you can use the text plugin to load the template content into a variable and then put it in the template cache.
define(['angular', 'text!path/to/template.html', 'angular-route', 'angular-mocks'], function(ng, directiveTemplate) {
"use strict";
describe('Directive TestSuite', function () {
beforeEach(inject(function( $templateCache) {
$templateCache.put("path/to/template.html", directiveTemplate);
}));
});
});

If you use requirejs in your tests then you can use the 'text' plugin to pull in the html template and put it in the $templateCache.
require(["text!template.html", "module-file"], function (templateHtml){
describe("Thing", function () {
var element, scope;
beforeEach(module('module'));
beforeEach(inject(function($templateCache, $rootScope, $compile){
// VOILA!
$templateCache.put('/path/to/the/template.html', templateHtml);
element = angular.element('<my-thing></my-thing>');
scope = $rootScope;
$compile(element)(scope);
scope.$digest();
}));
});
});

I resolve this issue with compiling all templates to templatecache.
I'm using gulp, you can find similar solution for grunt too.
My templateUrls in directives, modals looks like
`templateUrl: '/templates/directives/sidebar/tree.html'`
Add a new npm package in my package.json
"gulp-angular-templatecache": "1.*"
In gulp file add templatecache and a new task:
var templateCache = require('gulp-angular-templatecache');
...
...
gulp.task('compileTemplates', function () {
gulp.src([
'./app/templates/**/*.html'
]).pipe(templateCache('templates.js', {
transformUrl: function (url) {
return '/templates/' + url;
}
}))
.pipe(gulp.dest('wwwroot/assets/js'));
});
Add all js files in index.html
<script src="/assets/js/lib.js"></script>
<script src="/assets/js/app.js"></script>
<script src="/assets/js/templates.js"></script>
Enjoy!

Related

Can't setup Karma and Jasmine for Angularjs

I've tried several tutorials and looked at many of the solutions provided here. I am new to Angular and currently trying to set up testing for a rather big SPA.
Following this tutorial I have completed:
Angularjs application setup
Karma setup
Our first test
The karma config file is basically the default content, with some references in files and exclude:
// list of files/patterns to load in the browser
files: [
'bower_components/angular/angular.js',
'bower_components/angular-mocks/angular-mocks.js',
'app/app.js',
'JavaScript.spec.js'
],
I reinstalled the entire test implementation and now the simple test works again. But trying to write a test for a controller does not work:
here is the error message
I changed the path referencing the bower_components and app files in the karma config file. Now the shell running karma returns an error message from the app.js file, saying:
Uncaught ReferenceError: Logging is not defined
Writing a test identical to the one from doucmentation, gives the following error:
Here is the test code:
describe('nyKladdController', function () {
beforeEach(module('app'));
var $controller;
beforeEach(inject(function (_$controller_) {
$controller = _$controller_;
}));
describe('$scope.mixTable', function () {
it('is false', function () {
var $scope = {};
var controller = $controller('nyKladdController', { $scope: $scope });
expect($scope.mixTable).toBeFalsy();
});
});
});
As you can see from the error message: after the app module, the test file start loading the app dependencies. Here is the app.js file:
(function () {
'use strict';
angular.module('app', [
'ngAnimate', 'ngRoute', 'ngSanitize', 'ngResource', 'ngMessages',
'AdalAngular', 'config', 'angular.filter',
'ui.bootstrap', 'ui.mask', 'ui.select', 'ui.validate',
'angular-loading-bar', 'ui.tree', 'ui.tree-filter', 'checklist-model'
]);
})();
In other words: how can i get my tests to load the app dependecies as well.
I had to load in all the app dependencies from app.js in to karma.config file. Now the files array in karma config looks like this:
// list of files / patterns to load in the browser
files: [
//bower modules
'./bower_components/angular/angular.js',
'./bower_components/angular-mocks/angular-mocks.js',
'./bower_components/angular-ui-mask/src/mask.js',
'./bower_components/angular-ui-select/dist/select.js',
'./bower_components/angular-ui-tree-filter/dist/angular-ui-tree-filter.js',
'./bower_components/angular-ui-tree/dist/angular-ui-tree.js',
'./bower_components/angular-ui-validate/dist/validate.js',
'./bower_components/angular-loading-bar/build/loading-bar.js',
// node modules
'./node_modules/angular-animate/angular-animate.js',
'./node_modules/angular-route/angular-route.js',
'./node_modules/angular-sanitize/angular-sanitize.js',
'./node_modules/angular-resource/angular-resource.js',
'./node_modules/angular-messages/angular-messages.js',
'./node_modules/adal-angular/dist/adal-angular.min.js',
'./node_modules/angular-filter/dist/angular-filter.js',
'./node_modules/angular-ui-bootstrap/dist/ui-bootstrap.js',
'./node_modules/bower-config/lib/Config.js',
'./node_modules/checklist-model/checklist-model.js',
//app file
'./app/app.js',
'./app/common/config/config.js',
//test files etc..
'JavaScript.spec.js',
'./app/produkt/ny/controllers/*.js' // tester å hente inn controller som refereres i test filen
],
This may be because Karma is loading the source files in the wrong order. For Angular to work properly, each module must be loaded before any component, services, etc. associated with that module.
To fix this, you can change your Karma configuration to ensure your module files are loaded first.
// list of files / patterns to load in the browser
files: [
'../../bower_components/angular/angular.js',
'../../bower_components/angular-mocks/angular-mocks.js',
'app/**/*.module.js',
'app/**/*.js'
],
This is assuming you're using some kind of naming convention for angular modules (like *.module.js as in the above example). Otherwise you'll have to list the paths to the modules individually.
add beforeEach(module("your-module-name")); => your angular application name from app.js"
describe('check a controller', function () {
beforeEach(module("your module name")); // I think you missed this.
var scope, checkController;
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.new();
checkController = function () {
return $controller('nyKladdController', {
'$scope': scope
});
};
}));
it('has a dummy spec to test 2 + 2', function () {
// An intentionally failing test. No code within expect() will never equal 4.
expect(2 + 2).toEqual(4);
});
});
karma.conf
files: [ // sample order. Include your files accordingly
'src/bower_components/angular/angular.min.js',
'src/bower_components/angular-mocks/angular-mocks.js',
// some sample libraries
'src/bower_components/angular-cookies/angular-cookies.min.js',
'src/bower_components/angular-ui-router/release/angular-ui-router.min.js',
'src/bower_components/angular-resource/angular-resource.min.js',
'src/bower_components/angular-sanitize/angular-sanitize.min.js',
'src/bower_components/angular-loading-bar/build/loading-bar.min.js',
'src/app/app.js',
'src/app/**/*.js',
'tests/unit/**/*.spec.js'
],
exclude: []

Writing Unit Testing With Jasmine , Require JS in Karma for Angular JS?

I have Done a Library Management App with Angular JS and Mongo Lab will Act as a DB Part, I am facing issuse with Require JS Dependency While Crating Unit test Case
Error: [$injector:modulerr] Failed to instantiate module lmaApp due to:
Error: [$injector:nomod] Module 'lmaApp' is not available!
The Above error I am facing,kindly help me to get out from this.
MyCode:
Controller.js
define(
['modules'],
function(lmaApp) {
lmaApp.controller('gridControl',['$scope' , '$http' , 'internal' , 'commonValues', function($scope , $http , internalFn , commonValues){
jQuery('ul.navbar-nav li').removeClass('active');
jQuery('ul.navbar-nav li:nth-child(1)').addClass('active');
$('.loaderImg').removeClass('no-loading');
var lmaTableData = internalFn.getTableData(commonValues.mongoAPIurl,commonValues.bookTableName,'');
var promise = lmaTableData
.success(function(tbData) {
if(tbData.length > 0){
$scope.nobook=0;
$scope.books =tbData;
}
else{
$scope.nobook =1;
}
}).then(function (response) {$('.loaderImg').addClass('no-loading');});
}]);
});
modules.js
define(
['app_config','angularRoute'],
function() {
var lmaApp =angular.module('lmaApp',['ngRoute'])
return lmaApp;
});
app_config.js
define(
['angular','angularRoute','modules'],
function() {
angular.element(document).ready(function() {
angular.bootstrap(document, ['lmaApp'], {});
});
});
My spec File
controllerSpec.js
define(['angular', 'angular-mocks'], function() {
describe('gridControl', function(){
beforeEach(module('lmaApp'));
it('should get the book table Datas', inject(function($controller) {
var scope = {},
ctrl = $controller('gridControl', {$scope:scope});
expect(scope.phones.length).not.toEqual(0);
}));
});
});
Here i have a doubt with require js dependecy like i have to mention modules.js as a dependency in Spec file too.
Your controller-spec.js is wrong, you need to call its dependencies which is your module.js, app_config.js, Controller.js also 'angularRoute'. In other ot make your app to able to boostrap.
try it like this
define(['angular', 'angular-mocks','modules', 'app_config', 'Controller', 'angularRoute'], function() { ... }
Still I have nothing to be sure that it will work for you. Because if any of your configuration is wrong. It will be broken. Using requireJS with AngularJS in unit testing is very tricky/complex in the configuration.
You should read more about requireJS config, and using shim for define dependencies for your script. It will be lots clearer and eaiser to handle when your app getting bigger. For example you can do something like this in your config file:
shim: {
'modules': ['angular', 'app_config', 'angular-mocks'],
'app_config': ['angular', 'angularRoute', 'modules'],
'Controller': ['modules']
}
and your controller-spec.js will be like this
define(['modules', 'app_config', 'Controller'], function(){ ... });
Also Bootstraping angular on element ready is not a good idea for testing. It may cause some conflict in loading simulating of karma. I am not sure but don't feel right about it
Sencond Your app_config.js and modules.js are dependency of each other. So what do you think if there's something require an order in loading. Which will need to load first? since Both required the other to be loaded before it got to be injeacted by requireJS.
Still I don't think my solution will work. Because your config seem so wrong.

Gulp angular unit testing directive templateUrl

I read many post on internet and SO but couldn't find any solution that works
I am trying to write unit test for a directive and want the html files to be served from template cache
I am using Gulp as a build tool
The gulp task for test looks like this
gulp.task('test', function (done) {
karma.start({
configFile:__dirname + '/' + config.test.karmaconf,
singleRun: false
}, done);
});
and in karma.conf , I have defined
browserify: {
debug: true,
transform: [['browserify-ng-html2js', {
module: 'templates',
extension: 'html'
}]]
}
In unit test , I declared
beforeEach(angular.mock.module('templates'));
but receiving
Error: Unexpected request: GET path/to/some.html
No more request expected
at $httpBackend
I also tried to use preprocessors and ngHtml2JsPreprocessor in karma.conf but no success. Could anyone provide solution or point me how can I go about debugging why the templates are not served?
Solution
There are multiple ways you could go about doing that. Here's how I do it:
Use gulp-angular-templatecache:
gulp.task('bundle-common', function() {
return merge(
// Store all html files in $templateCache
gulp.src([
appDir + '/common/**/*.html'
])
.pipe($$.angularTemplatecache({
root: 'common'
}))
// Append everything else: directives, tests, etc.
gulp.src([
appDir + '/common/**/*.js'
])
)
.pipe($$.concat('common.js'))
.pipe(gulp.dest('public/js/'));
});
This will output a file named common.js with all your html templates and directives in it.
It will look somewhat like this:
angular.module("templates").run(["$templateCache", function($templateCache) {
$templateCache.put("common/a-great-eye.html","<div>lidless, wreathed in flame, 2 times</div>");}]);
angular.module("common")
.directive('aGreatEye', function () {
return {
restrict: 'E',
replace: true,
templateUrl: 'common/a-great-eye.html'
};
});
...
In karma.conf.js load common.js:
files: [
'../vendor/jquery/dist/jquery.js',
'../vendor/angular/angular.js',
'../vendor/angular-mocks/angular-mocks.js',
'../public/js/common.js'
]
In your test file reference the templates module:
describe('Unit testing great quotes', function() {
var $compile,
$rootScope;
// Load the common module, which contains the directive
beforeEach(function() {
module('templates');
module('common');
});
// Store references to $rootScope and $compile
// so they are available to all tests in this describe block
beforeEach(inject(function(_$compile_, _$rootScope_){
// The injector unwraps the underscores (_) from around the parameter names when matching
$compile = _$compile_;
$rootScope = _$rootScope_;
}));
it('Replaces the element with the appropriate content', function() {
// Compile a piece of HTML containing the directive
var element = $compile("<a-great-eye></a-great-eye>")($rootScope);
// fire all the watches, so the scope expression {{1 + 1}} will be evaluated
$rootScope.$digest();
// Check that the compiled element contains the templated content
expect(element.html()).toContain("lidless, wreathed in flame, 2 times");
});
});
Debugging
Start your test in Chrome browser and hit Debug button. Then open Developer Console.
Few tips:
You can add breakpoints in your tests.
Make sure that there are no errors in console window, especially injection errors. If you do, verify that all the js files you requested in karma.config.js (they will be listed in Developer Console) are loaded correctly and contain the code you need (angular, templates, directives, etc.).

Scope variables undefined when testing controller with Karma and Jasmine with ng-scenario as framework

I've just started to discover angular unit testing mysteries using Karma & Jasmine and I have some problems with controllers tests. I've wrote tests to see if variables are defined: expect(scope.someVariable).toBeDefined(). Everything worked as expected ( every test was successfully ) untill I've added ng-scenario in karma.conf.js file.
I'm using node to run tests.
Problem: After adding ng-scenario in karma configuration file as framework all tests for checking if scope variables are defined are failing. Before adding ng-scenario all tests were successfully. Do you have any ideea why is this happening ?
Karma Conf file:
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['ng-scenario','jasmine'],
files: [ 'app/plugins/jquery/jquery.js',
'app/plugins/angular/angular.js', 'app/plugins/angular-scenario/angular-scenario.js',
'app/plugins/angular-mocks/angular-mocks.js',
'app/plugins/angular-resource/angular-resource.js',
'app/plugins/angular-cookies/angular-cookies.js',
'app/plugins/angular-sanitize/angular-sanitize.js',
'app/plugins/angular-route/angular-route.js', 'app/plugins/angular-utf8-base64/angular-utf8-base64.js',
'app/scripts/*.js',
'app/scripts/**/*.js',
'test/**/*.js',
'app/views/templates/*.html'
],
preprocessors : { 'app/views/templates/*.html': 'html2js' },
exclude: ['app/plugins/angular-scenario/angular-scenario.js'],
port: 8080,
logLevel: config.LOG_INFO,
autoWatch: false,
browsers: ['Chrome'],
singleRun: false }); };
Controller test:
'use strict'
describe('Controller: MainCtrl', function () {
beforeEach(module('qunizGameApp'));
var MainCtrl,scope, configService,feedbackService,authService,notify,resourceService;
beforeEach(inject(function ($controller, $rootScope,_configService_,_feedbackService_, _authService_,_notify_, _resourceService_) {
scope = $rootScope.$new();
MainCtrl = $controller('MainCtrl', {
$scope: scope,
configService:_configService_,
feedbackService:_feedbackService_,
authService:_authService_,
notify:_notify_,
resourceService:_resourceService_
});
configService=_configService_;
feedbackService=_feedbackService_;
authService=_authService_;
notify=_notify_;
resourceService=_resourceService_; }));
it('should be defined -configService', function () {
expect(scope.configService).toBeDefined();
});
it('should be defined - resourceService', function () {
expect(scope.resourceService).toBeDefined();
});
it('should be defined - sidebarVisible', function () {
expect(scope.sidebarVisible).toBeDefined(); });
});
Proof of working test before including ng-scenario:
Proof of failure test after including ng-scenario:
And a wierd thing is that if I debug the test in my chrome console, variables are defined:
Things read on interned and tried:
1.I've tried to define variables on scope in beforeEach section as a mock data.
2.I've tried to inject all other controller dependencies ( with undescored name as paramaters)
You can see 1 and 2 below
beforeEach(inject(function ($controller, $rootScope,_configService_,_feedbackService_, _authService_,_notify_, _resourceService_) {
scope = $rootScope.$new();
scope.configService=_configService_;
scope.authService=_authService_;
scope.resourceService=_resourceService_;
scope.sidebarVisible={};
MainCtrl = $controller('MainCtrl', {
$scope: scope,
configService:_configService_,
feedbackService:_feedbackService_,
authService:_authService_,
notify:_notify_,
resourceService:_resourceService_
});
configService=_configService_;
feedbackService=_feedbackService_;
authService=_authService_;
notify=_notify_;
resourceService=_resourceService_; }));
But scope.configService, scope.resourceService and scope.sidebarVisible are still undefined at the moment of test
I had the same problems with ng-scenario when using it with Karma. The moment I included it in karma.conf.js file, none of my tests was passing. Just don't use ng-scenario - use Protractor for integration testing. https://github.com/angular/protractor

Karma 'Unexpected Request' when testing angular directive, even with ng-html2js

After spending the last day trying to make this work, I've found that I've circled back around to the same error I was having at the beginning:
Error: Unexpected request: GET test-directive.html
I'm using Karma and Jasmine to test directives in Angular. I've looked through similar questions on StackOverflow, but find that everything that has been tried in the other examples is to no avail.
Code structure
Test-App
-src
--bower
--lib
--js
--modules
---testDir
----test.js
----test-directive.html
----test
-----test.spec.js
-test
--config
---karma.conf.js
--e2e
Karma Config
'use strict';
module.exports = function(config){
config.set({
basePath: '../../',
frameworks: ['jasmine'],
files: [
// Angular
'src/bower/angular/angular.js',
// Mocks
'src/bower/angular-mocks/angular-mocks.js',
// Libraries
'src/lib/**/*.js',
// App
'src/js/*.js',
'src/modules/*/*.js',
// Tests
'src/modules/**/test/*spec.js',
// Templates
'src/modules/**/*.html'
],
autoWatch: false,
singleRun: true,
reporters: ['progress'],
browsers: ['PhantomJS'],
preprocessors: {
'src/modules/**/*.html': 'ng-html2js'
},
ngHtml2JsPreprocessor: {
moduleName: 'dir-templates'
},
plugins: [
'karma-jasmine',
'karma-ng-html2js-preprocessor',
'karma-phantomjs-launcher',
'karma-chrome-launcher',
'karma-junit-reporter'
]
});
};
test.js
'use strict';
angular.module('modules.test', []).
directive('testDirective', [function() {
return {
restrict: 'E',
templateUrl: 'test-directive.html',
link: function($scope, $elem, $attrs) {
$scope.someFn = function() {
angular.noop();
};
}
};
}]);
test-direct.html
<span>Hello World</span>
test.spec.js
'use strict';
describe('test module', function() {
beforeEach(module('modules.test'));
/* -- DIRECTIVES------------------ */
describe('directives', function() {
var $compile, $scope, elm;
beforeEach(module('dir-templates');
beforeEach(inject(function($compile, $rootScope) {
$scope = $rootScope.$new();
elm = angular.element('<test-directive></test-directive>');
$compile(elm)($scope);
$scope.$digest();
}));
it('should have one span tag', function(){
//Jasmine test here to check for one span tag.
});
});
});
Have shortened a couple of files to stick to just where the issue is. In calling beforeEach(module('dir-templates')), it should be loading all of the matched .html files into the $templateCache and preventing the GET request that is throwing the error.
Any help would be appreciated as it's really been driving me nuts. Please comment if you have any additional questions.
So, a painstaking headache for what seems to be a two line fix. After opening Karma in Chrome (instead of PhantomJS) and looking at the source files, I noticed that when ng-html2js attaches the directive to the $templateCache it uses the entire path, not the one provided in the directive definition.
In short, 'src/modules/test/test-directive.html.js' !== 'test-directive.html.js'.
To achieve this, modify the karma.conf.js file ngHtml2JsProcessor to read like:
ngHtml2JsPreprocessor: {
stripPrefix: 'src/',
moduleName: 'dir-templates'
},
And the directive declaration's templateUrl to look like:
templateUrl: 'modules/test/test-directive.html'
To add to the comments about making sure the template name being matched on matches the prefix (has no leading slash, etc.), one other thing to check for is case.
The template cache key is case sensitive, so make sure that your directives are referencing the html files using proper casing. The template cache keys that the ngHtml2JsPreprocessor generates use the casing of the actual file name and directory names on the file system.
So if your file is named Test-Directive.html or your folder is named "Modules" but your directive is referencing "modules/test-directive.html", it won't resolve from the cache.
Case sensitivity isn't an issue with real (non-test) usage of your directive's templateurl (the GET request obviously is case insensitive and the template cache key will be generated based on whatever the initial GET request was, ie. whatever was specified in your directive).

Resources