Closed mpiasta-ca closed 10 years ago
One of the answer in the SO suggested use of text plugin to load the template text. Have you tried that? Here is the sample code provided:
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 this doesn't work, try to isolate the problem in a simple test and share the code with me.
Interesting, I'll give that a shot. For now I was just catching the template call and returning a blank string, just to work around the error, like this:
$httpBackend.whenGET('components/modal/modal.html').respond("");
I just tried text.js and it works (used these install instructions). Pretty cool! I even plugged it right into my $httpBackend
statement as a response.
$httpBackend.whenGET('components/modal/modal.html').respond(modalTemplate);
I still get an error when the main app.js
file runs related to ngRoute, because $routeProvider is sending a default redirectTo /home
. I can't intercept this request with a beforeEach() because that seems to be too late.
So ngMock complains "unexpected request: GET home/home.html"
. The problem is that when I call text!homeTemplate
in the define([...])
statement for app_test.js, I then have to pair that with the $templateCache in the beforeEach([...])
statement, like so:
'use strict';
define(['app', 'angularAMD', 'text!homeTemplate', 'ngMock'], function (app, angularAMD, homeTemplate) {
describe('app.js', function () {
var inject = angularAMD.inject, $templateCache;
beforeEach(function () {
inject(function ($templateCache) {
$templateCache.put('home/home.html', homeTemplate);
});
});
});
});
My app.js
looks like this:
'use strict';
define(['angularAMD'], function (angularAMD) {
//init angular app and inject dependencies
var app = angular.module('app', ['ngRoute', 'ngMock']);
app.config(function ($routeProvider) {
$routeProvider
.when('/home', angularAMD.route({
templateUrl: 'home/home.html',
controller: '',
}))
.otherwise({
redirectTo: '/home',
});
});
return angularAMD.bootstrap(app);
});
Should I maybe be using angularAMD.config([...])
instead? I think this may be an issue with the sequence of events.
Or should I altogether comment-out the entire $routeProvider section from running during karma/jasmine tests? I put together this as a temporary hack, which means the $routeProvider loads when the app is called in the browser, but isn't loaded when running karma/jasmine tests:
app.config(function ($routeProvider) {
try {
angular.module('ngMock');
} catch (err) {
$routeProvider
.when('/home', angularAMD.route({
templateUrl: 'home/home.html',
controller: ''
}))
.otherwise({
redirectTo: '/home',
});
}
});
As karma/jasmine is used for unit test, I normally have a different app.js
specifically for unit testing. If you follow the same pattern, you could simply use the text!
plugin in it to create home template using $templateCache
.
If not, you can setup an [app_test.js(https://github.com/marcoslin/angularAMD-karma/blob/master/www/js/app_test.js) and load the templates there. You would need to load app.js
using require
statement to guarantee the loading order and make sure that app_test.js
is the first test to run. It would look like:
define(['angularAMD', 'text! home/home.html'], function (angularAMD, home_html) {
angularAMD.inject(function ($templateCache) {
$templateCache.put('home/home.html', home_html);
});
require(['app'], function () {
// app_test.js code here
});
});
Remember that testing of the partials are normally associated with E2E but I do realise that there is exceptions.
@marcoslin I tried the code you posted above, using a separate require([...]) statement to include the 'app' item, but that throws the error:
Error: angularAMD not initialized. Need to call angularAMD.bootstrap(app) first.
The $routeProvider code is set in a app.run([...])
statement, which I tried changing to angularAMD.run([...])
to see if that would help, but the same error is thrown.
I agree that partials should be tested with E2E. In this case, I'm not looking to test the template, I'm just looking for a way to suppress the error. My goal was to write as little code as possible in the test, ie. not having to write code to catch and redirect template requests, ideally the test would be able to continue without the template and without throwing an error.
I think the hack I used should suffice. It's easier for me to use that, than to have two separate app.js
files to keep in sync. I just use gulp/grunt to remove ngMock
from the dependencies when I compile the app.js
that is used in the browser.
I guess the reason I posted this was: 1) to see if there was a way to get ng-html2js working with require/karma, which I see now is not needed because text.js works well too; and 2) to see what you suggest as best practice with the main app.js file, so in your case, you suggest having a separate file to use for testing. I guess that works too, since I can't really target to test the app.run() or app.config() code that is being loaded in app.js (I use those for setting routes, authentication init, and to handle a loading spinner when route change is started/complete). So those things I could test with Protractor/E2E anyway.
Thanks again for your help and feedback.
Got a problem here which I don't think I'll be able to figure out on my own. I just added angular-mocks to my karma/jasmine test so I can use $httpBackend. But because ngMock disables all $http requests, now none of the required templates are being loaded.
Issue documented on StackOverflow.
So when I run my karma/jasmine tests, I keep getting errors like:
Possible solution I found but I'm having trouble making it work with angularAMD. The plugin
ng-html2js
is supposed to pass-in all the templates through...But I don't think the
module()
syntax works with angularAMD, right? So I also tried:...which doesn't work.
Any idea how to solve this problem? I also tried this solution using $templateCache but I couldn't get it working.