Add unittests for template generator angular

The following changes have been made.
 - Test cases for common components and individual resources.
 - Setup karma + jasmine test environment.
 - Setup eslint environment and rules.
 - Code style adjustment to satisfiy eslint rules.

Change-Id: Icb3e48be11beaebc4e410644c62e0df86b345207
This commit is contained in:
Xinni Ge 2017-10-24 16:18:41 +09:00
parent 867749f5b3
commit 52f2e318ad
71 changed files with 4447 additions and 487 deletions

1
.eslintignore Normal file
View File

@ -0,0 +1 @@
heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/*

265
.eslintrc.js Normal file
View File

@ -0,0 +1,265 @@
module.exports = {
"env": {
"browser": true,
"jasmine": true,
},
"plugins": ["jasmine"],
"globals": {
"angular": true,
"module": true,
"inject": true,
"saveAs": true,
"json2yaml": true
},
"extends": ["eslint:recommended", "plugin:jasmine/recommended"],
"rules": {
"accessor-pairs": "error",
"array-bracket-newline": "off",
"array-bracket-spacing": "off",
"array-callback-return": "error",
"array-element-newline": "off",
"arrow-body-style": "error",
"arrow-parens": "error",
"arrow-spacing": "error",
"block-scoped-var": "off",
"block-spacing": "off",
"brace-style": "off",
"callback-return": "off",
"camelcase": "off",
"capitalized-comments": "off",
"class-methods-use-this": "error",
"comma-dangle": "off",
"comma-spacing": "off",
"comma-style": "off",
"complexity": "off",
"computed-property-spacing": [
"error",
"never"
],
"consistent-return": "off",
"consistent-this": "off",
"curly": "off",
"default-case": "off",
"dot-location": [
"error",
"property"
],
"dot-notation": "off",
"eol-last": "off",
"eqeqeq": "off",
"for-direction": "error",
"func-call-spacing": "off",
"func-name-matching": "off",
"func-names": "off",
"func-style": "off",
"function-paren-newline": "off",
"generator-star-spacing": "error",
"getter-return": "error",
"global-require": "error",
"guard-for-in": "off",
"handle-callback-err": "error",
"id-blacklist": "error",
"id-length": "off",
"id-match": "error",
"indent": "off",
"indent-legacy": "off",
"init-declarations": "off",
"jasmine/prefer-toHaveBeenCalledWith": "off",
"jsx-quotes": "error",
"key-spacing": "off",
"keyword-spacing": "off",
"line-comment-position": "off",
"linebreak-style": [
"error",
"unix"
],
"lines-around-comment": "off",
"lines-around-directive": "off",
"lines-between-class-members": "error",
"max-depth": "off",
"max-len": "off",
"max-lines": "off",
"max-nested-callbacks": "error",
"max-params": "off",
"max-statements": "off",
"max-statements-per-line": "off",
"multiline-comment-style": "off",
"multiline-ternary": "off",
"new-parens": "off",
"newline-after-var": "off",
"newline-before-return": "off",
"newline-per-chained-call": "off",
"no-alert": "off",
"no-array-constructor": "error",
"no-await-in-loop": "error",
"no-bitwise": "off",
"no-buffer-constructor": "error",
"no-caller": "error",
"no-catch-shadow": "off",
"no-confusing-arrow": "error",
"no-continue": "off",
"no-div-regex": "error",
"no-duplicate-imports": "error",
"no-else-return": "off",
"no-empty-function": "off",
"no-eq-null": "off",
"no-eval": "error",
"no-extend-native": "error",
"no-extra-bind": "off",
"no-extra-label": "off",
"no-extra-parens": "off",
"no-floating-decimal": "off",
"no-implicit-coercion": [
"error",
{
"boolean": false,
"number": false,
"string": false
}
],
"no-implicit-globals": "off",
"no-implied-eval": "error",
"no-inline-comments": "off",
"no-inner-declarations": [
"error",
"functions"
],
"no-invalid-this": "off",
"no-iterator": "error",
"no-label-var": "error",
"no-lone-blocks": "off",
"no-lonely-if": "off",
"no-loop-func": "off",
"no-magic-numbers": "off",
"no-mixed-operators": "off",
"no-mixed-requires": "error",
"no-multi-assign": "off",
"no-multi-spaces": "off",
"no-multi-str": "error",
"no-multiple-empty-lines": "off",
"no-native-reassign": "error",
"no-negated-condition": "off",
"no-negated-in-lhs": "error",
"no-nested-ternary": "off",
"no-new": "error",
"no-new-func": "off",
"no-new-object": "error",
"no-new-require": "error",
"no-new-wrappers": "error",
"no-octal-escape": "error",
"no-param-reassign": "off",
"no-path-concat": "error",
"no-plusplus": "off",
"no-process-env": "error",
"no-process-exit": "error",
"no-proto": "off",
"no-prototype-builtins": "off",
"no-redeclare": "off",
"no-restricted-globals": "error",
"no-restricted-imports": "error",
"no-restricted-modules": "error",
"no-restricted-properties": "error",
"no-restricted-syntax": "error",
"no-return-assign": "off",
"no-return-await": "error",
"no-script-url": "error",
"no-self-compare": "error",
"no-sequences": "off",
"no-shadow": "off",
"no-shadow-restricted-names": "off",
"no-spaced-func": "off",
"no-sync": "error",
"no-tabs": "off",
"no-template-curly-in-string": "error",
"no-ternary": "off",
"no-throw-literal": "off",
"no-trailing-spaces": [
"error",
{
"ignoreComments": true,
"skipBlankLines": true
}
],
"no-undef-init": "off",
"no-undefined": "off",
"no-underscore-dangle": "off",
"no-unmodified-loop-condition": "off",
"no-unneeded-ternary": "off",
"no-unused-expressions": "off",
"no-unused-vars": "off",
"no-use-before-define": "off",
"no-useless-call": "off",
"no-useless-computed-key": "error",
"no-useless-concat": "off",
"no-useless-constructor": "error",
"no-useless-rename": "error",
"no-useless-return": "off",
"no-var": "off",
"no-void": "off",
"no-warning-comments": "off",
"no-whitespace-before-property": "error",
"no-with": "error",
"nonblock-statement-body-position": [
"error",
"any"
],
"object-curly-newline": "off",
"object-curly-spacing": "off",
"object-property-newline": "off",
"object-shorthand": "off",
"one-var": "off",
"one-var-declaration-per-line": "off",
"operator-assignment": "off",
"operator-linebreak": "off",
"padded-blocks": "off",
"padding-line-between-statements": "error",
"prefer-arrow-callback": "off",
"prefer-const": "error",
"prefer-destructuring": "off",
"prefer-numeric-literals": "error",
"prefer-promise-reject-errors": "error",
"prefer-reflect": "off",
"prefer-rest-params": "off",
"prefer-spread": "off",
"prefer-template": "off",
"quote-props": "off",
"quotes": "off",
"radix": "off",
"require-await": "error",
"require-jsdoc": "off",
"rest-spread-spacing": "error",
"semi": "off",
"semi-spacing": "off",
"semi-style": "off",
"sort-imports": "error",
"sort-keys": "off",
"sort-vars": "off",
"space-before-blocks": "off",
"space-before-function-paren": "off",
"space-in-parens": "off",
"space-infix-ops": "off",
"space-unary-ops": "off",
"spaced-comment": "off",
"strict": "off",
"switch-colon-spacing": "off",
"symbol-description": "error",
"template-curly-spacing": "error",
"template-tag-spacing": "error",
"unicode-bom": [
"error",
"never"
],
"valid-jsdoc": "off",
"valid-typeof": [
"error",
{
"requireStringLiterals": false
}
],
"vars-on-top": "off",
"wrap-iife": "off",
"wrap-regex": "off",
"yield-star-spacing": "error",
"yoda": "off"
}
};

4
.gitignore vendored
View File

@ -110,3 +110,7 @@ ENV/
# backup files
*.bak
coverage/*
node_modules/*
package-lock.json

View File

@ -10,7 +10,7 @@
{% endblock %}
{% block main %}
<div ng-show="loading" class="col-xs-12 load-block" ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.LoadingCtrl">
<div ng-show="loading" class="col-xs-12 load-block" ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.LoadingController">
<md-icon md-svg-src="{$ basePath $}css/img/icons/spinner.svg" class="spinner"></md-icon>
</div>
<div ng-cloak>
@ -19,7 +19,7 @@
<span flex></span>
<div class="col-sm-11" style="height:80px;">
<div ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.AgentCtrl" style="display:inline-block">
<div ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.AgentController" style="display:inline-block">
<md-input-container class="md-block" flex-gt-xs>
<label>Template Version</label>
<md-select ng-model="template_version" ng-change="update_template_version(template_version)">
@ -29,16 +29,16 @@
</md-select>
</md-input-container>
</div>
<div ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.TempModalCtrl" style="display:inline-block">
<div ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.TempModalController" style="display:inline-block">
<md-tooltip style="font-size:12px !important;" md-direction="top">Generate Template</md-tooltip>
<md-button class="md-fab md-mini md-primary" ng-click="open()" aria-label="Generate Template">
<md-icon md-svg-src="{$ basePath $}css/img/icons/file-text-o.svg"></md-icon>
</md-button>
</div>
<div class="md-menu" ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.DraftMenuCtrl" style="display:inline-block">
<div class="md-menu" ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.DraftMenuController" style="display:inline-block">
<md-tooltip style="font-size:12px !important;" md-direction="top">Manage Drafts</md-tooltip>
<md-menu>
<md-button class="md-fab md-mini" ng-click="openMenu($mdOpenMenu, $event)" aria-label="Manage Drafts">
<md-button class="md-fab md-mini" ng-click="openMenu($mdMenu, $event)" aria-label="Manage Drafts">
<md-icon md-svg-src="{$ basePath $}css/img/icons/floppy-o.svg"></md-icon>
</md-button>
<md-menu-content width="4" ng-mouseleave="closeMenu()">
@ -66,7 +66,7 @@
</md-menu-content>
</md-menu>
</div>
<div ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.ClearCanvasCtrl" style="display:inline-block">
<div ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.ClearCanvasController" style="display:inline-block">
<md-tooltip style="font-size:12px !important;" md-direction="top">Clear Canvas</md-tooltip>
<md-button ng-click="clear_canvas()" class="md-fab md-mini md-warn" aria-label="clear canvas">
<md-icon md-svg-src="{$ basePath $}css/img/icons/trash.svg"></md-icon>
@ -82,7 +82,7 @@
<span flex></span>
<!-- Icon Drag sidebar -->
<div class="col-sm-11" style="text-align:center" ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.IconCtrl">
<div class="col-sm-11" style="text-align:center" ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.IconController">
<div draggable ng-repeat="(reskey, resobj) in resource_types" class="os-resource" draggable="true" id="{$ reskey $}" ng-if="admin || !resource_admin[reskey]">
<md-tooltip md-direction="top" style="font-size:12px !important;">{$ resobj.name $}</md-tooltip>
<md-icon style="height: 36px; width: 36px;" md-svg-src="{$ basePath $}js/resources/{$ reskey|lowercase $}/{$ reskey|lowercase $}.svg"></md-icon>
@ -95,7 +95,7 @@
<span flex></span>
<!-- Drop Canvas -->
<div class="col-sm-11" style="margin-bottom: 10%; min-height:400px; height: 500px">
<div ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.VisCtrl" id="canvas_area" droppable>
<div ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.VisController" id="canvas_area" droppable>
<vis-network component="hotnetwork" data="data" options="options" events="events">
</vis-network>
</div>
@ -104,17 +104,17 @@
<!-- End Drop Canvas -->
<!-- Node Modal -->
<div ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.FormModalCtrl" class="md-padding" id="popupContainer" ng-cloak>
<div ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.FormModalController" class="md-padding" id="popupContainer" ng-cloak>
</div>
<!-- End Node Modal -->
<!-- Edge Modal -->
<div ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.EdgeFormModalCtrl" class="md-padding" id="popupEdgeContainer" ng-cloak>
<div ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.EdgeFormModalController" class="md-padding" id="popupEdgeContainer" ng-cloak>
</div>
<!-- End Edge Modal -->
<!-- Load Draft Modal -->
<div ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.DraftModalCtrl" class="md-padding" ng-cloak>
<div ng-controller="horizon.dashboard.project.heat_dashboard.template_generator.DraftModalController" class="md-padding" ng-cloak>
</div>
<!-- End Load Draft Modal -->
</div>

View File

@ -64,9 +64,12 @@ ADD_JS_FILES.extend(
'static'),
sub_path='%s/components' % JS_BASE,
ext='.js',
trim_base_path=True) if file not in ADD_JS_FILES
trim_base_path=True)
if file not in ADD_JS_FILES and 'spec.js' not in file
])
ADD_JS_FILES.extend(
discover_files(os.path.join(HEAT_DASHBOARD_ROOT, 'static'),
sub_path='%s/resources' % JS_BASE,
ext='.js', trim_base_path=True))
[file for file in discover_files(
os.path.join(HEAT_DASHBOARD_ROOT, 'static'),
sub_path='%s/resources' % JS_BASE,
ext='.js', trim_base_path=True) if 'spec.js' not in file
])

View File

@ -163,3 +163,7 @@ md-icon.spinner{
color: #fff;
}
.div-scroll{
overflow: auto;
max-height: 500px;
}

View File

@ -3,11 +3,11 @@
'use strict';
angular.module('horizon.dashboard.project.heat_dashboard.template_generator')
.controller('horizon.dashboard.project.heat_dashboard.template_generator.AgentCtrl', [
.controller('horizon.dashboard.project.heat_dashboard.template_generator.AgentController', [
'$scope','hotgenAgent', 'hotgenGlobals', 'hotgenMessage',
function($scope, hotgenAgent, hotgenGlobals, hotgenMessage){
var init = function(){
$scope.template_versions = [];
$scope.init = function(){
/* *********************************************************************
* The following selections should be replaced by OpenStack API response
*/
@ -35,10 +35,15 @@
});
};
init();
$scope.init();
$scope.update_template_version = function(template_version){
hotgenGlobals.set_template_version(template_version)
hotgenGlobals.set_template_version(template_version);
return true;
};
$scope.load_template_version = function(){
$scope.template_version = hotgenGlobals.get_template_version()
}
$scope.$on('update_template_version', $scope.load_template_version);
}])
})();

View File

@ -0,0 +1,100 @@
(function() {
'use strict';
describe('horizon.dashboard.project.heat_dashboard.template_generator.AgentController', function(){
beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator'));
var $httpBackend, requestHandler;
var $location;
var hotgenGlobals;
beforeEach(inject(function($injector){
$location = $injector.get('$location');
hotgenGlobals = $injector.get('hotgenGlobals');
spyOn($location, 'absUrl').and.callFake(function (p) {
return 'http://some-url/';
});
}));
beforeEach(inject(function($injector) {
// Set up the mock http service responses
$httpBackend = $injector.get('$httpBackend');
requestHandler = $httpBackend.when('GET', 'http://some-url/get_resource_options')
.respond(200, {
'auth': {
'tenant_id': 'tenant-id',
'admin': false,
},
'template_versions': [
{'name': 'v1', 'id': 'v1'},
{'name': 'v2', 'id': 'v2'}
],
}
);
}));
var $controller, controller, $scope;
beforeEach(inject(function(_$controller_, $rootScope) {
$controller = _$controller_;
$scope = $rootScope.$new();
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it('should exist', function(){
controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.AgentController', { $scope: $scope,});
expect(controller).toBeDefined();
$httpBackend.flush();
});
it('should return array with 2 items', function(){
$httpBackend.expectGET('http://some-url/get_resource_options');
controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.AgentController', { $scope: $scope,});
$httpBackend.flush();
expect($scope.template_versions.length).toEqual(2);
});
it('should return empty array', function(){
requestHandler.respond(500, '');
$httpBackend.expectGET('http://some-url/get_resource_options');
controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.AgentController', { $scope: $scope,});
$httpBackend.flush();
expect($scope.template_versions.length).toEqual(0);
});
it('should return true', function(){
$httpBackend.expectGET('http://some-url/get_resource_options');
controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.AgentController', { $scope: $scope,});
$httpBackend.flush();
expect($scope.update_template_version()).toEqual(true);
});
it('should set template version from hotgenGlobals', function(){
$httpBackend.expectGET('http://some-url/get_resource_options');
hotgenGlobals.set_template_version('template_version-1');
controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.AgentController', { $scope: $scope,});
$httpBackend.flush();
$scope.load_template_version();
expect($scope.template_version).toEqual('template_version-1');
});
});
})();

View File

@ -4,11 +4,11 @@
angular.module('hotgen-agent', ['hotgen-utils', ])
.factory('hotgenAgent', ['$http', '$location', 'hotgenNotify',
function($http, $location, hotgenNotify) {
var static_url = $location.absUrl();
if (static_url.substr(-1) != '/'){
static_url += '/';
}
var get_resource_options = function(){
var static_url = $location.absUrl();
if (static_url.substr(-1) != '/'){
static_url += '/';
}
return $http({
method: 'GET',
url: static_url+'get_resource_options'

View File

@ -0,0 +1,82 @@
(function () {
'use strict';
describe('hotgen-agent module', function () {
it('should be defined', function () {
expect(angular.module('hotgen-agent')).toBeDefined();
});
});
describe('hotgen-utils.hotgenStates', function(){
beforeEach(module('hotgen-agent'));
var hotgenAgent;
beforeEach(inject(function(_hotgenAgent_){
hotgenAgent = _hotgenAgent_;
}));
var $httpBackend, requestHandler;
var $location;
beforeEach(inject(function($injector){
$location = $injector.get('$location');
}));
beforeEach(inject(function($injector) {
// Set up the mock http service responses
$httpBackend = $injector.get('$httpBackend');
requestHandler = $httpBackend.when('GET', 'http://some-url/get_resource_options')
.respond(200, {
'auth': {
'tenant_id': 'tenant-id',
'admin': false,
}}
);
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it('should exist', function(){
expect(hotgenAgent).toBeDefined();
});
it('should return get_resource_options', function(){
spyOn($location, 'absUrl').and.callFake(function (p) {
return 'http://some-url/';
});
$httpBackend.expectGET('http://some-url/get_resource_options');
var optionsPromise = hotgenAgent.get_resource_options();
optionsPromise.then(function(options){
expect(options.auth.tenant_id).toEqual('tenant-id');
expect(options.auth.admin).toEqual(false);
});
$httpBackend.flush();
});
it('should return error', function(){
spyOn($location, 'absUrl').and.callFake(function (p) {
return 'http://some-url';
});
requestHandler.respond(500, '');
$httpBackend.expectGET('http://some-url/get_resource_options');
var optionsPromise = hotgenAgent.get_resource_options();
optionsPromise.then(function(options){
expect(options).toEqual(null);
});
$httpBackend.flush();
});
});
})();

View File

@ -0,0 +1,29 @@
(function() {
'use strict';
describe('hotgen-utils compile directive', function(){
beforeEach(module('hotgen-utils'));
var $compile, $rootScope, $scope, $isolateScope, element;
beforeEach(inject(function($rootScope, $compile) {
$scope = $rootScope.$new();
// element will enable you to test your directive's element on the DOM
element = $compile(angular.element('<div compile="<h1>Compile Me</h1>"></div>'))($scope);
// Digest needs to be called to set any values on the directive's scope
$scope.$digest();
// If the directive uses isolate scope, we need to get a reference to it
// explicitly
}));
it('Replaces the element with the appropriate content', function() {
expect(element.html()).toContain("Compile Me");
});
});
})();

View File

@ -0,0 +1,51 @@
(function() {
'use strict';
describe('horizon.dashboard.project.heat_dashboard.template_generator dependson directive', function(){
beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator'));
beforeEach(module('appTemplates'));
var $compile, $rootScope, $scope, $isolateScope, element;
beforeEach(inject(function($rootScope, $compile) {
$scope = $rootScope.$new();
$scope.dependson = ['node-id-1111', 'node-id-2222', 'node-id-3333'];
// element will enable you to test your directive's element on the DOM
element = $compile(angular.element('<depends-on dependson="dependson"></depends-on>'))($scope);
// Digest needs to be called to set any values on the directive's scope
$scope.$digest();
// If the directive uses isolate scope, we need to get a reference to it
// explicitly
$isolateScope = element.isolateScope();
}));
it('Replaces the element with the appropriate content', function() {
expect(element.find('label').html()).toContain("Depends on");
});
it('toggle function modifies array', function() {
var array = [0, 1, 2, 3, 4];
$isolateScope.toggle(5, array);
expect(array.length).toEqual(6);
$isolateScope.toggle(0, array);
$isolateScope.toggle(5, array);
expect(array.length).toEqual(4);
});
it('check array item existence ', function() {
var array = [0, 1, 2, 3, 4];
expect($isolateScope.exists(5, array)).toEqual(false);
expect($isolateScope.exists(1, array)).toEqual(true);
});
});
})();

View File

@ -5,15 +5,21 @@
angular.module('horizon.dashboard.project.heat_dashboard.template_generator').directive('draggable', [function(){
return function ($scope, element){
var el = element[0];
el.draggable = true;
el.addEventListener('dragstart', function(e){
this.style.opacity = '0.4';
e.dataTransfer.setData('text', e.target.id);
}, false);
el.addEventListener('dragend', function(e){
this.style.opacity = '1.0';
}, false);
el.draggable = true;
$scope.dragstartHandler = function(e){
el.style.opacity = '0.4';
e.dataTransfer.setData('text', e.target.id);
}
$scope.dragendHandler = function(e){
el.style.opacity = '1.0';
}
el.addEventListener('dragstart', $scope.dragstartHandler, false);
el.addEventListener('dragend', $scope.dragendHandler, false);
}
}]);

View File

@ -0,0 +1,52 @@
(function() {
'use strict';
describe('horizon.dashboard.project.heat_dashboard.template_generator draggable directive', function(){
beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator'));
var $compile, $rootScope, $scope, $isolateScope, element;
beforeEach(inject(function($rootScope, $compile) {
$scope = $rootScope.$new();
// element will enable you to test your directive's element on the DOM
element = $compile(angular.element('<div draggable >drag me</div>'))($scope);
// Digest needs to be called to set any values on the directive's scope
$scope.$digest();
// If the directive uses isolate scope, we need to get a reference to it
// explicitly
$isolateScope = element.isolateScope();
}));
it('Replaces the element with the appropriate content', function() {
expect(element[0].draggable).toEqual(true);
});
it('should change style when drag start', function() {
var mockEvent = {
'type': 'dragstart',
'dataTransfer': {
'setData': function(key, value){},
},
'target': {'id': 'icon-1'}
};
$scope.dragstartHandler(mockEvent, element);
expect(element[0].style.opacity).toEqual('0.4')
});
it('should change style when drag end', function() {
var mockEvent = {
'type': 'dragend',
};
$scope.dragendHandler(mockEvent, element);
expect(element[0].style.opacity).toEqual('1')
});
});
})();

View File

@ -11,13 +11,7 @@
nodes: hotgenStates.get_nodes(),
edges: hotgenStates.get_edges(),
}
var el = element[0];
el.addEventListener('dragover', function(e){
if (e.preventDefault){
e.preventDefault();
}
},true);
el.addEventListener('drop', function(e){
$scope.dropHandler = function(e){
var resource_types = hotgenGlobals.get_resource_icons();
var dropped_elem_id = e.dataTransfer.getData("text");
var dropped_elem_base = document.getElementById(dropped_elem_id);
@ -31,7 +25,7 @@
$scope.data.nodes.add({
id: id,
label: node_label,
shape: 'image',
shape: 'circularImage',
title: resource_type,
icon: {
face: 'FontAwesome',
@ -39,11 +33,22 @@
size: 50,
color: dragged_resource.color,
},
borderWidth: 0,
borderWidthSelected: 0,
color: {border: '#ffffff', background: '#ffffff', highlight: '#ffffff', hover: '#ffffff'},
image: basePath+'js/resources/'+resource_type.toLowerCase()+'/'+resource_type.toLowerCase()+'-gray.svg',
});
hotgenStates.update_saved_flags(id, false)
e.preventDefault();
},false);
}
$scope.dragoverHandler = function(e){
if (e.preventDefault){
e.preventDefault();
}
}
var el = element[0];
el.addEventListener('dragover', $scope.dragoverHandler, true);
el.addEventListener('drop', $scope.dropHandler, false);
}
}
}]);

View File

@ -0,0 +1,70 @@
(function() {
'use strict';
describe('horizon.dashboard.project.heat_dashboard.template_generator droppable directive', function(){
beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator'));
var hotgenGlobals;
beforeEach(inject(function($injector){
hotgenGlobals = $injector.get('hotgenGlobals');
}));
var $compile, $rootScope, $scope, $isolateScope, element;
beforeEach(inject(function($rootScope, $compile) {
$scope = $rootScope.$new();
// element will enable you to test your directive's element on the DOM
element = $compile('<div droppable >drop me</div>')($scope);
// Digest needs to be called to set any values on the directive's scope
$scope.$digest();
// If the directive uses isolate scope, we need to get a reference to it
// explicitly
$isolateScope = element.isolateScope();
}));
it('Replaces the element with the appropriate content', function() {
expect(element.html()).toEqual('drop me');
});
it('Dragover event with preventDefault', function() {
var mockEvent= {
type: 'dragover',
preventDefault: function(){},
}
spyOn(mockEvent, 'preventDefault');
$scope.dragoverHandler(mockEvent);
expect(mockEvent.preventDefault).toHaveBeenCalled();
});
it('Dragover event with !preventDefault', function() {
var mockEvent= {
type: 'dragover',
}
$scope.dragoverHandler(mockEvent);
});
it('Drop event', function() {
var resource_type = 'OS::Project::ResourceType';
hotgenGlobals.update_resource_icons(resource_type, {
'code': '', 'color': '#000'
})
var mockEvent = {
type: 'drop',
dataTransfer: {
getData: function(key){return resource_type},
},
target: {id: 'icon-1'},
preventDefault: function(){},
};
$scope.dropHandler(mockEvent);
});
});
})();

View File

@ -0,0 +1,126 @@
(function() {
'use strict';
describe('hotgen-utils.hotgenGlobals', function(){
beforeEach(module('hotgen-utils'));
var hotgenGlobals;
beforeEach(inject(function(_hotgenGlobals_){
hotgenGlobals = _hotgenGlobals_;
}));
it('should exist', function(){
expect(hotgenGlobals).toBeDefined();
});
it('check get_element', function(){
var returnValue = hotgenGlobals.get_element('resource_icons');
expect(Object.keys(returnValue).length).toEqual(0);
});
it('check node_labels', function(){
var returnValue = hotgenGlobals.get_node_labels();
expect(Object.keys(returnValue).length).toEqual(0);
hotgenGlobals.update_node_labels('key1', 'label1')
expect(Object.keys(returnValue).length).toEqual(1);
});
it('check node_admin', function(){
var returnValue = hotgenGlobals.get_node_admin();
expect(Object.keys(returnValue).length).toEqual(0);
hotgenGlobals.update_node_admin('key1', 'admin');
expect(Object.keys(returnValue).length).toEqual(1);
});
it('check resource_icons', function(){
var returnValue = hotgenGlobals.get_resource_icons();
expect(Object.keys(returnValue).length).toEqual(0);
hotgenGlobals.update_resource_icons('key1', 'admin');
expect(Object.keys(returnValue).length).toEqual(1);
});
it('check get_resource_components', function(){
var returnValue = hotgenGlobals.get_resource_components();
expect(Object.keys(returnValue).length).toEqual(0);
hotgenGlobals.update_resource_components('key1', 'component');
expect(Object.keys(returnValue).length).toEqual(1);
});
it('check get_edge_directions', function(){
var returnValue = hotgenGlobals.get_edge_directions();
expect(Object.keys(returnValue).length).toEqual(0);
hotgenGlobals.update_edge_directions('key1', 'edge');
expect(Object.keys(returnValue).length).toEqual(1);
});
it('check get_template_version', function(){
var returnValue = hotgenGlobals.get_template_version();
expect(returnValue).toEqual(null);
hotgenGlobals.set_template_version(['v1', 'v2']);
expect(hotgenGlobals.get_template_version().length).toEqual(2);
});
it('check get_necessary_properties', function(){
var returnValue = hotgenGlobals.get_necessary_properties();
expect(Object.keys(returnValue).length).toEqual(0);
hotgenGlobals.update_necessary_properties('key1', ['p1', 'p2']);
expect(hotgenGlobals.get_necessary_properties()['key1'].length).toEqual(2);
});
it('check get_resource_types', function(){
var returnValue = hotgenGlobals.get_resource_types();
expect(Object.keys(returnValue).length).toEqual(0);
});
it('check get_resource_options', function(){
var returnValue = hotgenGlobals.get_resource_options();
expect(Object.keys(returnValue).length).toEqual(1);
hotgenGlobals.update_resource_options(['op1', 'op2']);
expect(Object.keys(returnValue).length).toEqual(3);
});
it('check get_resource_outputs', function(){
hotgenGlobals.set_resource_outputs('key1', '');
var returnValue = hotgenGlobals.get_resource_outputs('key1');
expect(returnValue).toEqual('');
});
it('check get_reference_file', function(){
hotgenGlobals.set_reference_file('key1', '');
var returnValue = hotgenGlobals.get_reference_file('key1');
expect(returnValue).toEqual('');
});
});
})();

View File

@ -2,7 +2,7 @@
'use strict';
angular.module('horizon.dashboard.project.heat_dashboard.template_generator')
.controller('horizon.dashboard.project.heat_dashboard.template_generator.IconCtrl', ['$scope', 'hotgenGlobals',
.controller('horizon.dashboard.project.heat_dashboard.template_generator.IconController', ['$scope', 'hotgenGlobals',
'horizon.dashboard.project.heat_dashboard.template_generator.basePath',
function($scope, hotgenGlobals, basePath){
$scope.resource_types = hotgenGlobals.get_resource_icons();

View File

@ -0,0 +1,38 @@
(function() {
'use strict';
describe('horizon.dashboard.project.heat_dashboard.template_generator.IconController', function(){
beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator'));
var $controller, controller, $scope, hotgenGlobals;
beforeEach(inject(function($injector){
hotgenGlobals = $injector.get('hotgenGlobals');
}));
beforeEach(inject(function(_$controller_, $rootScope) {
$controller = _$controller_;
$scope = $rootScope.$new();
controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.IconController', { $scope: $scope,});
}));
it('should exist', function(){
expect(controller).toBeDefined();
});
it('check scope parameters', inject([ '$window', function($window){
var icons_number = Object.keys(hotgenGlobals.get_resource_icons()).length;
expect(Object.keys($scope.resource_types).length).toEqual(icons_number);
var admin_number = Object.keys(hotgenGlobals.get_node_admin()).length;
expect(Object.keys($scope.resource_admin).length).toEqual(admin_number);
expect($scope.admin).toEqual(false);
expect($scope.basePath).toBe($window.STATIC_URL + 'dashboard/project/heat_dashboard/template_generator/');
}]));
});
})();

View File

@ -4,7 +4,7 @@
angular
.module('horizon.dashboard.project.heat_dashboard.template_generator')
.controller('horizon.dashboard.project.heat_dashboard.template_generator.LoadingCtrl', [
.controller('horizon.dashboard.project.heat_dashboard.template_generator.LoadingController', [
'$scope', 'hotgenNotify',
'horizon.dashboard.project.heat_dashboard.template_generator.basePath',
function($scope, hotgenNotify, basePath){
@ -17,4 +17,4 @@
}])
})();
})();

View File

@ -0,0 +1,36 @@
(function() {
'use strict';
describe('LoadingController', function(){
beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator'));
var $controller, controller, $scope, $rootScope;
beforeEach(inject(function(_$controller_, $rootScope) {
$controller = _$controller_;
$scope = $rootScope.$new();
controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.LoadingController', { $scope: $scope,});
}));
beforeEach(inject(function(_$rootScope_) {
$rootScope = _$rootScope_;
}));
it('should exist', function(){
expect(controller).toBeDefined();
});
it('loading is false by default', function(){
expect($scope.loading).toEqual(true);
});
it('loading is true after message received', function(){
$rootScope.$broadcast('handle_resources_loaded');
expect($scope.loading).toEqual(false);
});
});
})();

View File

@ -4,13 +4,15 @@
angular
.module('horizon.dashboard.project.heat_dashboard.template_generator')
.controller('horizon.dashboard.project.heat_dashboard.template_generator.DraftMenuCtrl', ['$scope',
'$mdDialog', 'hotgenStates', 'hotgenNotify', 'hotgenMessage',
.controller('horizon.dashboard.project.heat_dashboard.template_generator.DraftMenuController', ['$scope',
'$mdDialog', 'hotgenStates', 'hotgenGlobals', 'hotgenNotify', 'hotgenMessage',
'horizon.dashboard.project.heat_dashboard.template_generator.basePath',
function($scope, $mdDialog, hotgenStates, hotgenNotify, hotgenMessage, basePath){
function($scope, $mdDialog, hotgenStates, hotgenGlobals, hotgenNotify, hotgenMessage, basePath){
$scope.basePath = basePath;
$scope.openMenu = function($mdOpenMenu, ev){
$mdOpenMenu(ev);
var originatorEv;
$scope.openMenu = function($mdMenu, ev){
originatorEv = ev;
$mdMenu.open(ev);
};
$scope.data = {
nodes: hotgenStates.get_nodes(),
@ -33,7 +35,8 @@
saved_depends_ons: hotgenStates.get_saved_dependsons(),
is_saved: hotgenStates.get_saved_flags(),
incremented_labels: hotgenStates.get_incremented_labels(),
counter: hotgenStates.get_counters()
counter: hotgenStates.get_counters(),
template_version: hotgenGlobals.get_template_version(),
}
var today = new Date();
@ -55,7 +58,7 @@
}]);
angular.module('horizon.dashboard.project.heat_dashboard.template_generator')
.controller('horizon.dashboard.project.heat_dashboard.template_generator.ClearCanvasCtrl', ['$scope',
.controller('horizon.dashboard.project.heat_dashboard.template_generator.ClearCanvasController', ['$scope',
'hotgenStates', 'hotgenNotify',
'horizon.dashboard.project.heat_dashboard.template_generator.basePath',
function($scope, hotgenStates, hotgenNotify, basePath){
@ -74,4 +77,4 @@
}]);
})();
})();

View File

@ -0,0 +1,135 @@
(function() {
'use strict';
describe('horizon.dashboard.project.heat_dashboard.template_generator.DraftMenuController', function(){
beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator'));
var $controller, controller, $scope, $rootScope, $mdMenu;
beforeEach(inject(function($injector){
$rootScope = $injector.get('$rootScope');
$mdMenu = $injector.get('$mdMenu');
spyOn($rootScope, '$broadcast');
$mdMenu.open = jasmine.createSpy().and.callFake(function() {
return function (callBack) {
callBack(true); //return the value to be assigned.
}
});
}));
beforeEach(inject(function(_$controller_, $rootScope) {
$controller = _$controller_;
$scope = $rootScope.$new();
controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.DraftMenuController', { $scope: $scope,});
}));
afterEach(function() {
localStorage.clear();
});
it('DraftMenuController should exist', function(){
expect(controller).toBeDefined();
});
it('DraftMenuController basePath', inject([ '$window', function($window){
expect($scope.basePath).toBe($window.STATIC_URL + 'dashboard/project/heat_dashboard/template_generator/');
}]));
it('scope.openMenu ', function(){
$scope.openMenu($mdMenu, {});
expect($mdMenu.open).toHaveBeenCalled();
});
it('DraftMenuController scope.data contains nodes and edges', function(){
expect($scope.data.nodes.length).toEqual(0);
expect($scope.data.edges.length).toEqual(0);
});
it('scope.save_draft stores in localStorage', function(){
expect(localStorage.length).toEqual(0);
$scope.save_draft();
expect(localStorage.length).toEqual(0);
$scope.data.nodes.add({'id': 'some-id'});
$scope.save_draft();
expect(localStorage.length).toEqual(2);
$scope.data.nodes.add({'id': 'some-id-2'});
$scope.save_draft();
expect(localStorage.length).toEqual(3);
});
it('scope.load_draft', function(){
$scope.load_draft();
expect($rootScope.$broadcast).toHaveBeenCalledWith('handle_load_draft');
});
it('scope.import_draft', function(){
$scope.import_draft();
});
it('scope.export_draft', function(){
$scope.export_draft();
});
});
describe('horizon.dashboard.project.heat_dashboard.template_generator.ClearCanvasController', function(){
beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator'));
var $controller, controller, $scope, $rootScope;
beforeEach(inject(function($injector){
$rootScope = $injector.get('$rootScope');
spyOn($rootScope, '$broadcast');
}));
beforeEach(inject(function(_$controller_, $rootScope) {
$controller = _$controller_;
$scope = $rootScope.$new();
controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.ClearCanvasController', { $scope: $scope,});
}));
afterEach(function() {
localStorage.clear();
});
it('ClearCanvasController should exist', function(){
expect(controller).toBeDefined();
});
it('ClearCanvasController basePath', inject([ '$window', function($window){
expect($scope.basePath).toBe($window.STATIC_URL + 'dashboard/project/heat_dashboard/template_generator/');
}]));
it('ClearCanvasController scope.data contains nodes and edges', function(){
expect($scope.data.nodes.length).toEqual(0);
expect($scope.data.edges.length).toEqual(0);
});
it('scope.clear_canvas should empty $scope.data', function(){
$scope.data.nodes.add({'id': 'some-node-id'});
$scope.data.edges.add({'id': 'some-edge-id'});
expect($scope.data.nodes.length).toEqual(1);
expect($scope.data.edges.length).toEqual(1);
$scope.clear_canvas();
expect($scope.data.nodes.length).toEqual(0);
expect($scope.data.edges.length).toEqual(0);
});
});