Add unit-tests for merlin directives
To simplify templates serving the plugin karma-ng-html2js-preprocessor has been added to Karma and project dependencies. Change-Id: If947acd2e9d7e64838c31e406d04fa9c1c67c770 Implements: blueprint merlin-unittests
This commit is contained in:
parent
0b92f674a4
commit
e9e750ef4c
@ -26,6 +26,8 @@ describe('workbook model logic', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function getWorkflow(workflowID) {
|
function getWorkflow(workflowID) {
|
||||||
|
// once workflow is recreated with JSON, old instance is no longer
|
||||||
|
// valid, thus we need to get it this way
|
||||||
return workbook.get('workflows').getByID(workflowID);
|
return workbook.get('workflows').getByID(workflowID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +64,8 @@ describe('workbook model logic', function() {
|
|||||||
taskID = 'task1';
|
taskID = 'task1';
|
||||||
|
|
||||||
function getTask(taskID) {
|
function getTask(taskID) {
|
||||||
|
// once task is recreated with JSON, old instance is no longer
|
||||||
|
// valid, thus we need to get it this way
|
||||||
return getWorkflow(workflowID).get('tasks').getByID(taskID);
|
return getWorkflow(workflowID).get('tasks').getByID(taskID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,50 +15,63 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = function (config) {
|
module.exports = function (config) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
config.set({
|
config.set({
|
||||||
|
|
||||||
port: 9876,
|
port: 9876,
|
||||||
|
|
||||||
basePath: '',
|
basePath: '',
|
||||||
|
|
||||||
frameworks: ['jasmine'],
|
frameworks: ['jasmine'],
|
||||||
|
|
||||||
browsers: [ 'PhantomJS'],
|
browsers: [ 'PhantomJS'],
|
||||||
|
|
||||||
plugins: [
|
plugins: [
|
||||||
'karma-jasmine',
|
'karma-jasmine',
|
||||||
'karma-phantomjs-launcher',
|
'karma-phantomjs-launcher',
|
||||||
],
|
'karma-ng-html2js-preprocessor'
|
||||||
|
],
|
||||||
|
|
||||||
files: [
|
files: [
|
||||||
'bower_components/angular/angular.js',
|
'bower_components/angular/angular.js',
|
||||||
'bower_components/angular-mocks/angular-mocks.js',
|
'bower_components/angular-mocks/angular-mocks.js',
|
||||||
'merlin/static/merlin/js/lib/underscore-min.js',
|
'merlin/static/merlin/js/lib/underscore-min.js',
|
||||||
'merlin/static/merlin/js/merlin.init.js',
|
'merlin/static/merlin/js/merlin.init.js',
|
||||||
'merlin/static/merlin/js/merlin.templates.js',
|
'merlin/static/merlin/js/merlin.templates.js',
|
||||||
'merlin/static/merlin/js/merlin.directives.js',
|
'merlin/static/merlin/js/merlin.directives.js',
|
||||||
'merlin/static/merlin/js/merlin.filters.js',
|
'merlin/static/merlin/js/merlin.filters.js',
|
||||||
'merlin/static/merlin/js/merlin.field.models.js',
|
'merlin/static/merlin/js/merlin.field.models.js',
|
||||||
'merlin/static/merlin/js/merlin.panel.models.js',
|
'merlin/static/merlin/js/merlin.panel.models.js',
|
||||||
'merlin/static/merlin/js/merlin.utils.js',
|
'merlin/static/merlin/js/merlin.utils.js',
|
||||||
'merlin/static/merlin/js/lib/angular-filter.js',
|
'merlin/static/merlin/js/lib/angular-filter.js',
|
||||||
'merlin/static/merlin/js/lib/barricade.js',
|
'merlin/static/merlin/js/lib/barricade.js',
|
||||||
'merlin/static/merlin/js/lib/js-yaml.js',
|
'merlin/static/merlin/js/lib/js-yaml.js',
|
||||||
'merlin/test/js/utilsSpec.js',
|
'merlin/static/merlin/templates/**/*.html',
|
||||||
'merlin/test/js/templatesSpec.js',
|
// 'merlin/static/merlin/templates/fields/*.html',
|
||||||
'merlin/test/js/filtersSpec.js',
|
'merlin/test/js/utilsSpec.js',
|
||||||
|
'merlin/test/js/templatesSpec.js',
|
||||||
|
'merlin/test/js/filtersSpec.js',
|
||||||
|
'merlin/test/js/directivesSpec.js',
|
||||||
|
|
||||||
'extensions/mistral/static/mistral/js/mistral.init.js',
|
'extensions/mistral/static/mistral/js/mistral.init.js',
|
||||||
'extensions/mistral/static/mistral/js/mistral.workbook.models.js',
|
'extensions/mistral/static/mistral/js/mistral.workbook.models.js',
|
||||||
'extensions/mistral/static/mistral/js/mistral.workbook.controllers.js',
|
'extensions/mistral/static/mistral/js/mistral.workbook.controllers.js',
|
||||||
'extensions/mistral/test/js/workbookSpec.js'
|
'extensions/mistral/test/js/workbookSpec.js'
|
||||||
],
|
],
|
||||||
|
|
||||||
exclude: [
|
preprocessors: {
|
||||||
],
|
'merlin/static/merlin/templates/**/*.html': ['ng-html2js']
|
||||||
|
},
|
||||||
|
|
||||||
singleRun: true
|
ngHtml2JsPreprocessor: {
|
||||||
});
|
stripPrefix: 'merlin',
|
||||||
|
moduleName: 'preprocessedTemplates'
|
||||||
|
},
|
||||||
|
|
||||||
|
exclude: [
|
||||||
|
],
|
||||||
|
|
||||||
|
singleRun: true
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
@ -5,12 +5,19 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('merlin', [])
|
angular.module('merlin', [])
|
||||||
.run(['merlin.templates', function(templates) {
|
.config(function($interpolateProvider) {
|
||||||
templates.prefetch('/static/merlin/templates/fields/',
|
// Replacing the default angular symbol
|
||||||
['dictionary', 'frozendict', 'list', 'string', 'text', 'group', 'number',
|
// allow us to mix angular with django templates
|
||||||
'choices'
|
$interpolateProvider.startSymbol('{$');
|
||||||
]
|
$interpolateProvider.endSymbol('$}');
|
||||||
);
|
})
|
||||||
}])
|
// move these 2 values out of run section to change them in unit-tests
|
||||||
|
.value('fieldTemplatesUrl', '/static/merlin/templates/fields/')
|
||||||
|
.value('fieldTemplates', ['dictionary', 'frozendict', 'list',
|
||||||
|
'string', 'text', 'group', 'number', 'choices'])
|
||||||
|
.run(['merlin.templates', 'fieldTemplatesUrl', 'fieldTemplates',
|
||||||
|
function(templates, rootUrl, fieldList) {
|
||||||
|
templates.prefetch(rootUrl, fieldList);
|
||||||
|
}])
|
||||||
|
|
||||||
})();
|
})();
|
195
merlin/test/js/directivesSpec.js
Normal file
195
merlin/test/js/directivesSpec.js
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
|
||||||
|
/* Copyright (c) 2015 Mirantis, Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
not use this file except in compliance with the License. You may obtain
|
||||||
|
a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
License for the specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
*/
|
||||||
|
describe('merlin directives', function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var $compile, $scope, $httpBackend;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
module('merlin', function($provide) {
|
||||||
|
$provide.value('fieldTemplates', ['number', 'text']);
|
||||||
|
});
|
||||||
|
module('preprocessedTemplates');
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(inject(function(_$compile_, _$rootScope_, _$httpBackend_, _$templateCache_) {
|
||||||
|
$compile = _$compile_;
|
||||||
|
$scope = _$rootScope_.$new();
|
||||||
|
$httpBackend = _$httpBackend_;
|
||||||
|
$httpBackend.whenGET('/static/merlin/templates/fields/text.html').respond(
|
||||||
|
200, _$templateCache_.get('/static/merlin/templates/fields/text.html'));
|
||||||
|
$httpBackend.whenGET('/static/merlin/templates/fields/number.html').respond(
|
||||||
|
200, _$templateCache_.get('/static/merlin/templates/fields/number.html'));
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('<panel>', function() {
|
||||||
|
function getPanelHeading(panelElem) {
|
||||||
|
var div = panelElem.children().children().eq(0);
|
||||||
|
return div.hasClass('panel-heading') && div;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPanelRemoveButton(panelElem) {
|
||||||
|
var iTag = panelElem.find('i').eq(0);
|
||||||
|
return iTag.hasClass('fa-times-circle') && iTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPanelBody(panelElem) {
|
||||||
|
var div = panelElem.children().children().eq(1).children();
|
||||||
|
return div.hasClass('panel-body') && div;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makePanelElem(contents) {
|
||||||
|
return $compile('<panel ' + contents + '></panel>')($scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
it('shows panel heading when and only when title is passed via attr', function() {
|
||||||
|
var title = 'My Panel',
|
||||||
|
element1 = makePanelElem('title="' + title +'"'),
|
||||||
|
element2 = makePanelElem('');
|
||||||
|
$scope.$digest();
|
||||||
|
|
||||||
|
expect(getPanelHeading(element1).hasClass('ng-hide')).toBe(false);
|
||||||
|
expect(element1.html()).toContain(title);
|
||||||
|
expect(getPanelHeading(element2).hasClass('ng-hide')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('requires both `title` and `removable` to be removable', function() {
|
||||||
|
var title = 'My Panel',
|
||||||
|
element1, element2;
|
||||||
|
|
||||||
|
element1 = makePanelElem('title="' + title +'" removable="true"');
|
||||||
|
element2 = makePanelElem('title="' + title +'"');
|
||||||
|
$scope.$digest();
|
||||||
|
|
||||||
|
expect(getPanelRemoveButton(element1).hasClass('ng-hide')).toBe(false);
|
||||||
|
expect(getPanelRemoveButton(element2).hasClass('ng-hide')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with `on-remove`, but without `removable` is not removable', function() {
|
||||||
|
var title = 'My Panel',
|
||||||
|
element1, element2;
|
||||||
|
|
||||||
|
$scope.remove = function() {};
|
||||||
|
element1 = makePanelElem(
|
||||||
|
'title="' + title +'" removable="true" on-remove="remove()"');
|
||||||
|
element2 = makePanelElem('title="' + title +'" on-remove="remove()"');
|
||||||
|
$scope.$digest();
|
||||||
|
|
||||||
|
expect(getPanelRemoveButton(element1).hasClass('ng-hide')).toBe(false);
|
||||||
|
expect(getPanelRemoveButton(element2).hasClass('ng-hide')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('contents are inserted into div.panel-body tag', function() {
|
||||||
|
var element = $compile('<panel><span class="inner"></span></panel>')($scope);
|
||||||
|
$scope.$digest();
|
||||||
|
|
||||||
|
expect(getPanelBody(element).find('span').hasClass('inner')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('<collapsible-group>', function() {
|
||||||
|
function getGroupBody(groupElem) {
|
||||||
|
var div = groupElem.children().children().eq(1);
|
||||||
|
return div.hasClass('collapse') && div;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getGroupRemoveBtn(groupElem) {
|
||||||
|
var div = groupElem.children().children().eq(0).children().eq(2);
|
||||||
|
return div.hasClass('add-btn') && div;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getGroupAddBtn(groupElem) {
|
||||||
|
var div = groupElem.children().children().eq(0).children().eq(1);
|
||||||
|
return div.hasClass('add-btn') && div;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeGroupElement(contents) {
|
||||||
|
return $compile(
|
||||||
|
'<collapsible-group ' + contents + '></collapsible-group>')($scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
it('requires to specify just `on-remove` to make group removable', function() {
|
||||||
|
var element1, element2;
|
||||||
|
$scope.remove = function() {};
|
||||||
|
element1 = makeGroupElement('');
|
||||||
|
element2 = makeGroupElement('on-remove="remove()"');
|
||||||
|
$scope.$digest();
|
||||||
|
|
||||||
|
expect(getGroupRemoveBtn(element1).hasClass('ng-hide')).toBe(true);
|
||||||
|
expect(getGroupRemoveBtn(element2).hasClass('ng-hide')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('requires to specify `on-add` to make group additive', function() {
|
||||||
|
var element1, element2;
|
||||||
|
$scope.add = function() {};
|
||||||
|
element1 = makeGroupElement('');
|
||||||
|
element2 = makeGroupElement('on-add="add()"');
|
||||||
|
$scope.$digest();
|
||||||
|
|
||||||
|
expect(getGroupAddBtn(element1).hasClass('ng-hide')).toBe(true);
|
||||||
|
expect(getGroupAddBtn(element2).hasClass('ng-hide')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('`additive` attribute set explicitly to `false` makes group not additive', function() {
|
||||||
|
var element;
|
||||||
|
$scope.add = function() {};
|
||||||
|
element = makeGroupElement('on-add="add()" additive="false"');
|
||||||
|
$scope.$digest();
|
||||||
|
|
||||||
|
expect(getGroupAddBtn(element).hasClass('ng-hide')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('contents are inserted into div.collapse tag', function() {
|
||||||
|
var element = $compile(
|
||||||
|
'<collapsible-group><span class="inner"></span></collapsible-group>')($scope);
|
||||||
|
$scope.$digest();
|
||||||
|
|
||||||
|
expect(getGroupBody(element).find('span').hasClass('inner')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('<typed-field>', function() {
|
||||||
|
function makeFieldElem(contents) {
|
||||||
|
return $compile(
|
||||||
|
'<div><typed-field ' + contents + '></typed-field></div>')($scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
it('type of resulting field is determined by `type` attribute', function() {
|
||||||
|
var element1, element2;
|
||||||
|
$scope.value1 = {type: 'text'};
|
||||||
|
$scope.value2 = {type: 'number'};
|
||||||
|
element1 = makeFieldElem('value="value1" type="{$ value1.type $}"');
|
||||||
|
element2 = makeFieldElem('value="value2" type="{$ value2.type $}"');
|
||||||
|
$httpBackend.flush();
|
||||||
|
$scope.$digest();
|
||||||
|
|
||||||
|
expect(element1.html()).toContain('<textarea');
|
||||||
|
expect(element2.html()).toContain('<input type="number"');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('field is not rendered until the corresponding template has been served', function() {
|
||||||
|
var element;
|
||||||
|
$scope.value = {type: 'text'};
|
||||||
|
element = makeFieldElem('value="value" type="{$ value.type $}"');
|
||||||
|
expect(element.html()).not.toContain('<textarea');
|
||||||
|
|
||||||
|
$httpBackend.flush();
|
||||||
|
expect(element.html()).toContain('<textarea');
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
@ -72,7 +72,7 @@ describe('merlin templates', function() {
|
|||||||
success, failure;
|
success, failure;
|
||||||
|
|
||||||
function processTemplate(fieldName) {
|
function processTemplate(fieldName) {
|
||||||
var promise = templates.templateReady(fieldName)
|
var promise = templates.templateReady(fieldName);
|
||||||
|
|
||||||
promise.then(function() {
|
promise.then(function() {
|
||||||
success = true;
|
success = true;
|
||||||
|
@ -26,7 +26,8 @@
|
|||||||
"karma": "^0.12.31",
|
"karma": "^0.12.31",
|
||||||
"karma-chrome-launcher": "^0.1.7",
|
"karma-chrome-launcher": "^0.1.7",
|
||||||
"karma-jasmine": "^0.3.5",
|
"karma-jasmine": "^0.3.5",
|
||||||
"karma-phantomjs-launcher": "^0.1.4"
|
"karma-phantomjs-launcher": "^0.1.4",
|
||||||
|
"karma-ng-html2js-preprocessor": "~0.1"
|
||||||
},
|
},
|
||||||
"main": "Gruntfile.js",
|
"main": "Gruntfile.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
Loading…
Reference in New Issue
Block a user