I am having a hard time figuring out how to include my directive's templates (that are all in one file in different script tags) in my Karma unit tests.
The error I get:
PhantomJS 1.9 (Linux) ERROR
SyntaxError: Parse error
at /var/www/html/tweak/core/global/views/js/modules/datable/templates.html:1
PhantomJS 1.9 (Linux): Executed 0 of 0 ERROR (0.313 secs / 0 secs)
Here are the relevant parts of the code:
My directives meat:
return {
scope : {
columns : '=',
config : '='
},
templateUrl : 'datable/table.html',
restrict : 'E',
controller : 'datableCtrl',
link : linkingFunction
};
My template file:
<script type="text/ng-template" id="datable/table.html">
<!-- data rows -->
<tr
ng-repeat="row in rows track by $id($index)"
class="datable-row"
ng-hide="loading">
<td
ng-repeat="column in columns track by $id($index)"
ng-class="{'edit-on': editMode == 'on'}"
class="{{column.classes.join(' ') + ' column' + $index}}"
ng-style="column.style">
<div ng-include="editMode == 'on' && column.editable
? 'datable/editCell.html'
: 'datable/normalCell.html'">
</div>
</td>
<!-- save button -->
<td ng-show="editMode == 'on'" style="width:1px;">
<button class="btn"> Save </button>
</td>
<!-- / save button -->
</tr>
<!-- / data rows -->
</script>
<script type="text/ng-template" id="datable/editCell.html">
<div ng-switch="column.inputType">
<!-- text input -->
<div ng-switch-when="text">
<div ng-class="{
'input-append' : column.append != '',
'input-prepend' : column.prepend != ''
}">
<span
class="add-on"
ng-show="column.prepend"> {{column.prepend}} </span>
<input
type="text"
ng-model="row[column.model]"
ng-keydown="query()"
ng-class="inputClass.join(' ')"
ng-attrs="column.inputAttrs">
<span
class="add-on"
ng-show="column.append"> {{column.append}} </span>
</div>
</div>
<!-- end text input -->
<!-- select input -->
<div ng-switch-when="select">
<select
ng-model="row[column.model]"
ng-change="query()"
ng-options="item.value as item.name for item in column.options"
ng-class="inputClass.join(' ')"
ng-attrs="column.inputAttrs">
<option value=""> -- </option>
</select>
</div>
<!-- end select -->
<!-- radio / checkbox -->
<div ng-switch-default>
<label ng-repeat="(key, value) in column.options track by $id($index)">
<input
type="{{column.inputType}}"
ng-class="inputClass.join(' ')"
ng-change="query()"
value="{{key}}"
ng-checked="row[column.model].indexOf('key') > -1"
ng-attrs="column.inputAttrs">
<span> {{value}} </span>
</label>
</div>
<!-- end radio / checkbox -->
</div>
</script>
<script type="text/ng-template" id="datable/normalCell.html">
<div class="read-only">
<span> {{column.prepend}} </span>
<!-- <span> {{row[column.model] | datableFilter : column.filter}} </span> -->
<span ng-bind-html-unsafe="(row[column.model] + '') | datableFilter : column.filter"></span>
<span> {{column.append}} </span>
</div>
</script>
My unit tests:
'use strict'
describe("datable", function() {
describe('directive', function () {
var $rootScope, $pile, element;
beforeEach(module('datable'));
beforeEach(module('/var/www/html/tweak/core/global/views/js/modules/datable/templates.html'));
beforeEach(inject(function (_$rootScope_, _$pile_) {
$rootScope = _$rootScope_;
$pile = _$pile_;
$rootScope.tableConfig = {
editable : true
};
$rootScope.columns = [];
element = angular.element('<datable config="tableConfig" columns="columns"></datable>');
$pile(element)($rootScope);
$rootScope.$digest();
}));
it('should have ng-scope class', function() {
expect(element.hasClass('ng-scope')).toBe(true);
});
});
});
My Karma config:
var branch = 'tweak';
basePath = '/var/www/html/' + branch + '/';
files = [
// Dependencies
JASMINE,
JASMINE_ADAPTER,
'.0.0/jquery.min.js',
'.1.5/angular.min.js',
'.1.5/angular-mocks.js',
// other requirements
'core/global/views/js/modules/rest/module.js',
// the project source
'core/global/views/js/modules/datable/module.js',
'core/global/views/js/modules/datable/values.js',
'core/global/views/js/modules/datable/services.js',
'core/global/views/js/modules/datable/filters.js',
'core/global/views/js/modules/datable/directives.js',
'core/global/views/js/modules/datable/controllers.js',
'core/global/views/js/modules/datable/*.html',
// my spec suite
'core/global/views/js/modules/datable/tests.js'
];
exclude = [
];
reporters = ['progress'];
port = 9876;
runnerPort = 9100;
colors = true;
logLevel = LOG_INFO;
autoWatch = true;
browsers = ['PhantomJS'];
captureTimeout = 60000;
I am having a hard time figuring out how to include my directive's templates (that are all in one file in different script tags) in my Karma unit tests.
The error I get:
PhantomJS 1.9 (Linux) ERROR
SyntaxError: Parse error
at /var/www/html/tweak/core/global/views/js/modules/datable/templates.html:1
PhantomJS 1.9 (Linux): Executed 0 of 0 ERROR (0.313 secs / 0 secs)
Here are the relevant parts of the code:
My directives meat:
return {
scope : {
columns : '=',
config : '='
},
templateUrl : 'datable/table.html',
restrict : 'E',
controller : 'datableCtrl',
link : linkingFunction
};
My template file:
<script type="text/ng-template" id="datable/table.html">
<!-- data rows -->
<tr
ng-repeat="row in rows track by $id($index)"
class="datable-row"
ng-hide="loading">
<td
ng-repeat="column in columns track by $id($index)"
ng-class="{'edit-on': editMode == 'on'}"
class="{{column.classes.join(' ') + ' column' + $index}}"
ng-style="column.style">
<div ng-include="editMode == 'on' && column.editable
? 'datable/editCell.html'
: 'datable/normalCell.html'">
</div>
</td>
<!-- save button -->
<td ng-show="editMode == 'on'" style="width:1px;">
<button class="btn"> Save </button>
</td>
<!-- / save button -->
</tr>
<!-- / data rows -->
</script>
<script type="text/ng-template" id="datable/editCell.html">
<div ng-switch="column.inputType">
<!-- text input -->
<div ng-switch-when="text">
<div ng-class="{
'input-append' : column.append != '',
'input-prepend' : column.prepend != ''
}">
<span
class="add-on"
ng-show="column.prepend"> {{column.prepend}} </span>
<input
type="text"
ng-model="row[column.model]"
ng-keydown="query()"
ng-class="inputClass.join(' ')"
ng-attrs="column.inputAttrs">
<span
class="add-on"
ng-show="column.append"> {{column.append}} </span>
</div>
</div>
<!-- end text input -->
<!-- select input -->
<div ng-switch-when="select">
<select
ng-model="row[column.model]"
ng-change="query()"
ng-options="item.value as item.name for item in column.options"
ng-class="inputClass.join(' ')"
ng-attrs="column.inputAttrs">
<option value=""> -- </option>
</select>
</div>
<!-- end select -->
<!-- radio / checkbox -->
<div ng-switch-default>
<label ng-repeat="(key, value) in column.options track by $id($index)">
<input
type="{{column.inputType}}"
ng-class="inputClass.join(' ')"
ng-change="query()"
value="{{key}}"
ng-checked="row[column.model].indexOf('key') > -1"
ng-attrs="column.inputAttrs">
<span> {{value}} </span>
</label>
</div>
<!-- end radio / checkbox -->
</div>
</script>
<script type="text/ng-template" id="datable/normalCell.html">
<div class="read-only">
<span> {{column.prepend}} </span>
<!-- <span> {{row[column.model] | datableFilter : column.filter}} </span> -->
<span ng-bind-html-unsafe="(row[column.model] + '') | datableFilter : column.filter"></span>
<span> {{column.append}} </span>
</div>
</script>
My unit tests:
'use strict'
describe("datable", function() {
describe('directive', function () {
var $rootScope, $pile, element;
beforeEach(module('datable'));
beforeEach(module('/var/www/html/tweak/core/global/views/js/modules/datable/templates.html'));
beforeEach(inject(function (_$rootScope_, _$pile_) {
$rootScope = _$rootScope_;
$pile = _$pile_;
$rootScope.tableConfig = {
editable : true
};
$rootScope.columns = [];
element = angular.element('<datable config="tableConfig" columns="columns"></datable>');
$pile(element)($rootScope);
$rootScope.$digest();
}));
it('should have ng-scope class', function() {
expect(element.hasClass('ng-scope')).toBe(true);
});
});
});
My Karma config:
var branch = 'tweak';
basePath = '/var/www/html/' + branch + '/';
files = [
// Dependencies
JASMINE,
JASMINE_ADAPTER,
'https://ajax.googleapis./ajax/libs/jquery/2.0.0/jquery.min.js',
'https://ajax.googleapis./ajax/libs/angularjs/1.1.5/angular.min.js',
'http://code.angularjs/1.1.5/angular-mocks.js',
// other requirements
'core/global/views/js/modules/rest/module.js',
// the project source
'core/global/views/js/modules/datable/module.js',
'core/global/views/js/modules/datable/values.js',
'core/global/views/js/modules/datable/services.js',
'core/global/views/js/modules/datable/filters.js',
'core/global/views/js/modules/datable/directives.js',
'core/global/views/js/modules/datable/controllers.js',
'core/global/views/js/modules/datable/*.html',
// my spec suite
'core/global/views/js/modules/datable/tests.js'
];
exclude = [
];
reporters = ['progress'];
port = 9876;
runnerPort = 9100;
colors = true;
logLevel = LOG_INFO;
autoWatch = true;
browsers = ['PhantomJS'];
captureTimeout = 60000;
Share
Improve this question
edited Oct 19, 2013 at 0:48
Adi Inbar
12.3k13 gold badges59 silver badges70 bronze badges
asked Oct 17, 2013 at 19:10
RonSperRonSper
6931 gold badge7 silver badges20 bronze badges
2
- I do my templating this way also and have yet to find a testing solution. I only test services because of this problem, but would like to know more. – Kevin Beal Commented Oct 17, 2013 at 23:54
- Has anyone tried this? I would imagine that this is something that would be supported? – RonSper Commented Oct 18, 2013 at 21:53
1 Answer
Reset to default 7I think your error is because you are trying to load your HTML file into a file list that normally accepts javascript. I do have a solution for you though.
Before I begin, I have karma 0.10.2 and it looks like you are on 0.8.x or under? I have this working in 0.10.2 but I can't install 0.8.x. I'll try to translate for 0.8.x but won't be able to test what I'm doing, so I'll describe mainly in terms of 0.10.x. It may be easier to move to latest karma anyway if you are able.
Config
0.10.x
External HTML partials can be loaded by karma-ng-html2js-preprocessor. This is normally used for loading directly in directives via templateUrl
and similar methods. In 0.10.2 you need to make sure this package is installed (using npm) and then include the following in your karma config:
preprocessors: {
'**/*.html' : ['ng-html2js']
},
ngHtml2JsPreprocessor: {
cacheIdFromPath: function(filepath) {
// If you had more than one html file you would want to do something more clever here.
return 'inlinetemplates';
},
moduleName: 'inlinetemplates'
},
plugins: [
...,
'karma-ng-html2js-preprocessor'
],
files: [
...,
'app/alltemplates.html', // your main template html
// Don't include paths for individual files that are inlined in the file above
]
This will allow you to load a module with module('inlinetemplates')
that will insert the contents of your main template file (not the individual templates) into $templateCache
.
0.8.x
So, translating for 0.8.x... I think you need to use html2js
which is not so powerful but is included in karma in this version. You won't need to install or include it in plugins, and you can't configure how it's used, so you just need
preprocessors = { '**/*.html': ['html2js'] }
The module created, and the item it inserts into $templateCache
will be named using the path that you use to refer to your main template html.
Javascript
0.10.x
Now you should be able to load the relevant module and get access to the contents of your main template file using
var templates = $templateCache.get('inlinetemplates')
All that is left to do is pushing your inlined templates from the main template file contents to $templateCache
. This is done using the angular script
directive, so we just need to pile/link the file we have loaded with angular. You can do this very simply with
$pile(templates)(scope);
So putting this together, you can include the following in any describe
block that needs to load your templates.
beforeEach(module('inlinetemplates'));
beforeEach(inject(function($pile, $templateCache, $rootScope) {
var templatesHTML = $templateCache.get('inlinetemplates');
$pile(templatesHTML)($rootScope);
}));
0.8.x
var mainTemplateLocation = 'path/used/to/refer/to/main/templates/in/karma/conf.html';
beforeEach(module(mainTemplateLocation));
beforeEach(inject(function($pile, $templateCache, $rootScope) {
var templatesHTML = $templateCache.get(mainTemplateLocation);
$pile(templatesHTML)($rootScope);
}));
Summing Up
Again, I can't guarantee that the 0.8.x instructions will work, especially not without tweaking, but this certainly works in 0.10.x.
Karma already has the facilities for pushing external HTML partials into your tests, all that was missing was being able to interpret your main template properly.