I am setting up a unit test for angular directive with karma and I'm stuck with configuring the ngHtml2JsPreprocessor preprocessor. I have tried a bunch of different ways as described in various thread at Stack Owerflow of setting up the tests but am struggeling in finding a way that works for me.
karma.conf.js
files: [
'bower_components/angular/angular.js',
..
..
..
'test/mock/*.js',
'test/mock/**/*.js',
'test/spec/unit/**/*.js',
'app/views/*.html',
'app/views/**/*.html'
//'app/views/**/**/*.html'
],
preprocessors: {
//'app/views/**/**/*.html': ['ng-html2js']
'app/views/**/*.html': ['ng-html2js']
},
ngHtml2JsPreprocessor: {
// strip this from the file path
stripPrefix: 'app/',
moduleName: 'PreprocessedTemplates'
},
Test file
beforeEach(inject(function ($compile, $rootScope, $templateCache, $httpBackend) {
scope = $rootScope;
//$templateCache.put('/app/views/components/KonstruktStdFilterbox/KonstruktStdFilterbox.html', $templateCache.get('/app/views/components/KonstruktStdFilterbox/KonstruktStdFilterbox.html'));
//$templateCache.put('../../../views/components/KonstruktStdFilterbox/KonstruktStdFilterbox.html', $templateCache.get('../../../views/components/KonstruktStdFilterbox/KonstruktStdFilterbox.html'));
ele = angular.element(
'<konstrukt-std-filterbox title="Testing generic filter Component" items="list" source="data" filter-entity="Dim1"></konstrukt-std-filterbox>'
);
mockupDataFactory = konstruktMockupData.getInstance();
//these variables are needed.
scope.data = mockupDataFactory.pivotedData;
scope.list = ["first","second"];
scope.$apply();
}));
It fails in before each with the message.
Error: Unexpected request: GET ../../../views/components/KonstruktStdFilterbox/KonstruktStdFilterbox.html
The path to the template is
app\views\components\KonstruktStdFilterbox\KonstruktStdFilterbox.html
I understand that the test cannot find the template in the templatecache, but how can I configure karma to have the PreprocessedTemplates load my template?
I have tried different configs in my karma.conf.js, see commented out lines above.
It turned out that I had a path defined in my directive which was very hard to find, hence the error
Error: Unexpected request: GET
../../../views/components/KonstruktStdFilterbox/KonstruktStdFilterbox.html
angular.module('app').directive('directive', function(utilities) {
return {
restrict: 'E', //element
templateUrl: '../../../views/components/KonstruktStdFilterbox/KonstruktStdFilterbox.html',
scope: true,
replace: true,
..
And when I changed the templateUrl to this the test ran fine!
templateUrl:
'views/components/KonstruktStdFilterbox/KonstruktStdFilterbox.html
Related
I'm trying to implement the unit testing in existing angular project. For that I've added Grunt-Karma
karma:
unit:
options:
frameworks: ['jasmine'],
singleRun: true,
browsers: ['PhantomJS'],
files: [bower js files + project dev/test js files]
Controller is,
angular.module('app.lol.ctrls', []).controller('LOLCtrl', [
'$scope', '$filter', 'Resource', '$log', function($scope, $filter, Resource, $log) {//some logic}
And test spec is
describe('Controller: LOLCtrl', function () {
beforeEach(module('app'));
var OrderCtrl;
var scope;
var filter;
var log;
var resource=someResourceWithSomeDataFunc;
beforeEach(inject(function ($controller, $rootScope, $filter, $log) {
scope = $rootScope.$new();
OrderCtrl = $controller('LOLCtrl', {
$scope: scope,
$filter: filter,
Resource: resource,
$log: log
});
}));
it('should have lolVar to be undefined', function () {
expect(scope.lolVar).toBeUndefined();
});
});
When I run the test, I'm getting error
PhantomJS 1.9.8 (Linux 0.0.0) Controller: LOLCtrl should have lolVar to be undefined FAILED
Error: [ng:areq] Argument 'LOLCtrl' is not a function, got undefined
http://errors.angularjs.org/1.3.20/ng/areq?p0=LOLCtrl&p1=not%20a%20function%2C%20got%20undefined
undefined
at assertArg ....
I tried the solutions like using angular.mock.module instead of module in beforeEach. Also I've double checked whether I'm including the controller file.
Also the app.lol.ctrls is injected in app itself. I tried beforeEach(module(app.lol.ctrls)), but that too gives same error.
Help would be greatly appreciated.
first I think you forgot to include the dependencies of your module. without knowing the complete structure of your app-code, I guess that the code, where you defined your controller should be
angular.module('app.lol.ctrls', ['app.lol', '/*maybe other dependecies*/']).controller('LOLCtrl', [ ]);
or did you have a own module file? then it should look like this:
angular.module('app.lol.ctrls').controller('LOLCtrl', [ ]);
after resolving these dependency-problems, have a look on your index.html. Did you included
<script src="bower_components/angular-mocks/angular-mocks.js"></script>?
if not, install angular-mocks and include it.
then, as a second step, go to your test spec and add change the beforeEach parts like this:
beforeEach(function(){
module('app.lol.ctrls');
module('ngMockE2E');
});
try to run your tests again. if you're getting the same error like before, have a look at your grunt-file. the list of your files included by karma looks a little bit strange for me. maybe this could be a problem too. for help, here a snipped from my grunt-file:
karma: {
options: {
frameworks: ['jasmine'],
files: [
'<%= dom_munger.data.appjs %>',
//this files data is also updated in the watch handler, if updated change there too
'bower_components/angular-mocks/angular-mocks.js',
'application/**/*-spec.js',
'application/**/*.html',
'base/**/*-spec.js',
'error/**/*.html',
'html/**/*.html',
'*.html',
'bower_components/**/*.html'
],
preprocessors: {
'**/*.html': ['ng-html2js']
},
ngHtml2JsPreprocessor: {
moduleName: 'templates'
},
logLevel: 'WARN',
reporters: ['mocha'],
captureConsole: true,
autoWatch: false,
singleRun: true
}
}
I hope, this will help you a little bit to resolve your problem.
Testing my angular app with karma ngHtml2JsPreprocessor, I have read dozens of pages on how ton configure karma to generate js templates instead of html ones that are loaded by Angular Directives, I am stuck with the message :
Module 'js_templates' 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.6/$injector/nomod?p0=js_templates
My folder structure is like this :
/System/Root/Path/
web/
js/
app/
test/
specs/
UserModule/
UserDirectives.spec.js
modules/
UserModule/
UserDirectives.js <=== Where the directive is defined
Templates
login.tpl.html
My directive is defined like this :
directives.directive("loginForm", [function(){
return{
restriction: "E",
templateUrl: assetsRootPath+'/Templates/login.tpl.html' //assetsRootPath is defined to '' for karma
}]);
Karma is configured as follow :
module.exports = function(config) {
config.set({
basePath: './web/js/',
frameworks: ['jasmine', 'requirejs'],
preprocessors: {
'../Templates/**/*.html': ['ng-html2js']
},
ngHtml2JsPreprocessor: {
stripPrefix: '.*web/',
prependPrefix: '/',
moduleName: 'js_templates',
enableRequireJs: false
},
plugins : [
'karma-chrome-launcher',
'karma-jasmine',
'karma-requirejs',
'karma-ng-html2js-preprocessor'
],
// list of files / patterns to load in the browser
files: [
{ pattern: '../Templates/**/*.html', included: false },
//....Other needed files
]
The spec for testing the directive :
define(['angular', 'ngmocks', 'app/modules/UserModule/UserDirectives'], function() {
describe("Test User Directive > ", function () {
var $compiler, compiledElement;
beforeEach(module('User.Directives'));
beforeEach(module('js_templates'));
beforeEach(inject(function (_$rootScope_, _$compile_) {
$rootScope = _$rootScope_;
$compile = _$compile_;
scope = $rootScope.$new();
compiledElement = $compile("<login-form></login-form>")(scope);
scope.$digest();
}));
it('Tries to test', function(){
expect(1).toEqual(1);
});
});
});
When I launch the tests the following error appears :
Module 'js_templates' 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.6/$injector/nomod?p0=js_templates
I have tried a lot of configurations and nothing works, I have also tried to debug ngHtml2JsPreprocessor by adding some log.debug & I see that the module 'js_templates' is rightly created, the problem is why can't I load it for the specs. Information that could be useful (not sure if it changes something) : I am working with requirejs.
Thanks for your help
Well, as no config worked, I have chosen to use a different approach, below is what I ended up to do to make it work :
1 - Remove all pre-processors
2 - Install the simple html2js node plugin : npm install karma-html2js-preprocessor --save-dev
3 - Inside my karma.conf file :
pattern: { files: '../Templates/**/*.html', included : true } //Note the included property to true
preprocessors: {
'../Templates/**/*.html': ['html2js']
},
plugins : [
'karma-chrome-launcher',
'karma-jasmine',
'karma-requirejs',
'karma-html2js-preprocessor'
],
Inside my test-main.js file which is the entry point of require-js I have done this :
require([
'angular',
...
], function(angular, app) {
var $html = angular.element(document.getElementsByTagName('html')[0]);
angular.element().ready(function() {
// bootstrap the app manually
angular.bootstrap(document, ['app']);
//Making all templates to be availabe through js_template module
angular.module('js_templates', []).run(function($templateCache){
angular.forEach(window.__html__, function(content, filename){
var modifiedFilename = filename;
/*****************Modify this to fit your app**********************/
var breakPos = modifiedFilename.indexOf('/Templates');
modifiedFilename = filename.substr(breakPos, modifiedFilename.length - breakPos);
/*****************/Modify this to fit your app*********************/
$templateCache.put(modifiedFilename, content);
});
});
});
}
);
Not very sharp but not so bad as well, anyway it does work and it's exactly what I wanted. When a solution will come to work naturally with ngHtml2JsPreprocessor, I will use it.
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.).
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).
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!