diff --git a/horizon/karma.conf.js b/horizon/karma.conf.js index d3598f9341..aaad05e9bb 100644 --- a/horizon/karma.conf.js +++ b/horizon/karma.conf.js @@ -150,9 +150,9 @@ module.exports = function (config) { // Coverage threshold values. thresholdReporter: { - statements: 86, // target 100 - branches: 68, // target 100 - functions: 87, // target 100 + statements: 90, // target 100 + branches: 77, // target 100 + functions: 89, // target 100 lines: 87 // target 100 } }); diff --git a/horizon/static/framework/widgets/metadata/tree/metadata-tree-item.controller.js b/horizon/static/framework/widgets/metadata/tree/metadata-tree-item.controller.js index 358073ee4a..1d0720f128 100644 --- a/horizon/static/framework/widgets/metadata/tree/metadata-tree-item.controller.js +++ b/horizon/static/framework/widgets/metadata/tree/metadata-tree-item.controller.js @@ -32,7 +32,7 @@ ctrl.formatErrorMessage = formatErrorMessage; ctrl.opened = false; - if (ctrl.item.leaf.type === 'array') { + if ('item' in ctrl && 'leaf' in ctrl.item && ctrl.item.leaf.type === 'array') { ctrl.values = ctrl.item.leaf.items.enum.filter(filter).sort(); if (!ctrl.item.leaf.readonly) { diff --git a/horizon/static/framework/widgets/metadata/tree/metadata-tree-item.controller.spec.js b/horizon/static/framework/widgets/metadata/tree/metadata-tree-item.controller.spec.js new file mode 100644 index 0000000000..d2706da75c --- /dev/null +++ b/horizon/static/framework/widgets/metadata/tree/metadata-tree-item.controller.spec.js @@ -0,0 +1,119 @@ +/* + * (c) Copyright 2015 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +(function() { + 'use strict'; + + describe('Metadata Tree Item Controller', function() { + var ctrl; + + beforeEach(module('horizon.framework.widgets.metadata.tree')); + beforeEach(inject(function ($controller, $injector) { + ctrl = $controller('MetadataTreeItemController'); + })); + + it('defines the controller', function() { + expect(ctrl).toBeDefined(); + }); + + it('defines formatErrorMessage', function() { + expect(ctrl.formatErrorMessage).toBeDefined(); + }); + + describe("formatErrorMessage", function() { + + it("returns minimum", function() { + var item = {leaf: {minimum: "-1"}}; + var error = {min: true}; + ctrl.text = {min: "texmin"}; + + expect(ctrl.formatErrorMessage(item, error)).toBe('texmin -1'); + }); + + it("returns maximum", function() { + var item = {leaf: {maximum: "200"}}; + var error = {max: true}; + ctrl.text = {max: "texmax"}; + + expect(ctrl.formatErrorMessage(item, error)).toBe('texmax 200'); + }); + + it("returns minimum length", function() { + var item = {leaf: {minLength: "5"}}; + var error = {minlength: true}; + ctrl.text = {minLength: "texminlen"}; + + expect(ctrl.formatErrorMessage(item, error)).toBe('texminlen 5'); + }); + + it("returns maximum length", function() { + var item = {leaf: {maxLength: "200"}}; + var error = {maxlength: true}; + ctrl.text = {maxLength: "texmaxlen"}; + + expect(ctrl.formatErrorMessage(item, error)).toBe('texmaxlen 200'); + }); + + it("returns pattern mismatch/integer", function() { + var item = {leaf: {type: "integer"}}; + var error = {pattern: true}; + ctrl.text = {integerRequired: "texint"}; + + expect(ctrl.formatErrorMessage(item, error)).toBe('texint'); + }); + + it("returns pattern mismatch/non-integer", function() { + var item = {leaf: {type: "other"}}; + var error = {pattern: true}; + ctrl.text = {patternMismatch: "texmismatch"}; + + expect(ctrl.formatErrorMessage(item, error)).toBe('texmismatch'); + }); + + it("returns number mismatch/integer", function() { + var item = {leaf: {type: "integer"}}; + var error = {number: true}; + ctrl.text = {integerRequired: "texint"}; + + expect(ctrl.formatErrorMessage(item, error)).toBe('texint'); + }); + + it("returns number mismatch/non-integer", function() { + var item = {leaf: {type: "other"}}; + var error = {number: true}; + ctrl.text = {decimalRequired: "texdec"}; + + expect(ctrl.formatErrorMessage(item, error)).toBe('texdec'); + }); + + it("returns required", function() { + var error = {required: true}; + ctrl.text = {required: "texreq"}; + + expect(ctrl.formatErrorMessage(undefined, error)).toBe('texreq'); + }); + + it("returns nothing when nothing for error", function() { + var error = {}; + + expect(ctrl.formatErrorMessage(undefined, error)).toBeUndefined(); + }); + + }); + + }); + +})(); diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/keypair/keypair.spec.js b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/keypair/keypair.spec.js index 0d41f413c5..c8595e4f22 100644 --- a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/keypair/keypair.spec.js +++ b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/keypair/keypair.spec.js @@ -20,9 +20,10 @@ describe('LaunchInstanceKeypairController', function() { var ctrl; + var $modal = { open: angular.noop }; beforeEach(module(function ($provide) { - $provide.value('$modal', {}); + $provide.value('$modal', $modal); })); beforeEach(module('horizon.dashboard.project')); @@ -63,15 +64,69 @@ expect(ctrl.tableLimits.maxAllocation).toBe(1); }); + it('allocateNewKeypair does nothing if some allocated', function() { + ctrl.tableData.allocated = ['something']; + spyOn(ctrl.tableData.allocated, 'push'); + ctrl.allocateNewKeyPair('do not use'); + expect(ctrl.tableData.allocated.length).toBe(1); + expect(ctrl.tableData.allocated.push).not.toHaveBeenCalled(); + }); + + it('allocateNewKeypair adds keypair if none allocated', function() { + ctrl.tableData.allocated = []; + ctrl.allocateNewKeyPair('new'); + expect(ctrl.tableData.allocated).toEqual(['new']); + }); + + it('createKeyPair opens a modal', function() { + spyOn($modal, 'open').and.returnValue({result: {then: angular.noop}}); + ctrl.createKeyPair(); + expect($modal.open).toHaveBeenCalled(); + }); + + it('createKeyPairCallback is called', function() { + var result = {result: {then: angular.noop}}; + spyOn(result.result, 'then'); + spyOn($modal, 'open').and.returnValue(result); + ctrl.createKeyPair(); + var callback = result.result.then.calls.argsFor(0)[0]; + + var callbackInput = {name: "June"}; + $modal.open.calls.reset(); + callback(callbackInput); + expect($modal.open).toHaveBeenCalled(); + expect(callbackInput.id).toBe("June"); + }); + + it('importKeyPair opens a modal', function() { + spyOn($modal, 'open').and.returnValue({result: {then: angular.noop}}); + ctrl.importKeyPair(); + expect($modal.open).toHaveBeenCalled(); + }); + + it('importKeyPairCallback is called', function() { + var result = {result: {then: angular.noop}}; + spyOn(result.result, 'then'); + spyOn($modal, 'open').and.returnValue(result); + ctrl.importKeyPair(); + var callback = result.result.then.calls.argsFor(0)[0]; + + var callbackInput = {name: "June"}; + $modal.open.calls.reset(); + callback(callbackInput); + expect(callbackInput.id).toBe("June"); + }); }); describe('LaunchInstanceCreateKeyPairController', function() { var ctrl; + var nova = { createKeypair: angular.noop }; + var $modalInstance = {close: angular.noop, dismiss: angular.noop}; beforeEach(module(function ($provide) { - $provide.value('$modalInstance', {}); - $provide.value('horizon.app.core.openstack-service-api.nova', {}); - $provide.value('horizon.framework.widgets.toast.service', {}); + $provide.value('$modalInstance', $modalInstance); + $provide.value('horizon.app.core.openstack-service-api.nova', nova); + $provide.value('horizon.framework.widgets.toast.service', {add: angular.noop}); })); beforeEach(module('horizon.dashboard.project')); @@ -89,16 +144,40 @@ expect(ctrl.submit).toBeDefined(); }); + it('submit calls nova with the proper arguments', function() { + spyOn(nova, 'createKeypair').and.returnValue({success: angular.noop}); + ctrl.submit(); + expect(nova.createKeypair).toHaveBeenCalledWith(ctrl.model); + }); + + it('successful submit calls the successCallback', function() { + var successFunc = {success: angular.noop}; + spyOn(nova, 'createKeypair').and.returnValue(successFunc); + spyOn(successFunc, 'success'); + ctrl.submit(); + var successCallback = successFunc.success.calls.argsFor(0)[0]; + var data = {}; + successCallback(data); + }); + it('defines a cancel function', function() { expect(ctrl.cancel).toBeDefined(); }); + + it('cancel dismisses the modal', function() { + spyOn(nova, 'createKeypair').and.returnValue({success: angular.noop}); + spyOn($modalInstance, 'dismiss'); + ctrl.cancel(); + expect($modalInstance.dismiss).toHaveBeenCalledWith(); + }); }); describe('LaunchInstanceNewKeyPairController', function() { var ctrl; + var $modalInstance = {close: angular.noop, dismiss: angular.noop}; beforeEach(module(function ($provide) { - $provide.value('$modalInstance', {}); + $provide.value('$modalInstance', $modalInstance); })); beforeEach(module('horizon.dashboard.project')); @@ -114,15 +193,23 @@ it('defines an OK function', function() { expect(ctrl.ok).toBeDefined(); }); + + it('ok dismisses the window', function() { + spyOn($modalInstance, 'dismiss'); + ctrl.ok(); + expect($modalInstance.dismiss).toHaveBeenCalledWith(); + }); }); describe('LaunchInstanceImportKeyPairController', function() { var ctrl; + var nova = { createKeypair: angular.noop }; + var $modalInstance = {close: angular.noop, dismiss: angular.noop}; beforeEach(module(function ($provide) { - $provide.value('$modalInstance', {}); - $provide.value('horizon.app.core.openstack-service-api.nova', {}); - $provide.value('horizon.framework.widgets.toast.service', {}); + $provide.value('$modalInstance', $modalInstance); + $provide.value('horizon.app.core.openstack-service-api.nova', nova); + $provide.value('horizon.framework.widgets.toast.service', {add: angular.noop}); })); beforeEach(module('horizon.dashboard.project')); @@ -141,9 +228,32 @@ expect(ctrl.submit).toBeDefined(); }); + it('submit calls nova with the proper arguments', function() { + spyOn(nova, 'createKeypair').and.returnValue({success: angular.noop}); + ctrl.submit(); + expect(nova.createKeypair).toHaveBeenCalledWith(ctrl.model); + }); + + it('successful submit calls the successCallback', function() { + var successFunc = {success: angular.noop}; + spyOn(nova, 'createKeypair').and.returnValue(successFunc); + spyOn(successFunc, 'success'); + ctrl.submit(); + var successCallback = successFunc.success.calls.argsFor(0)[0]; + var data = {}; + successCallback(data); + }); + it('defines a cancel function', function() { expect(ctrl.cancel).toBeDefined(); }); + + it('cancel dimisses the modal', function() { + spyOn(nova, 'createKeypair').and.returnValue({success: angular.noop}); + spyOn($modalInstance, 'dismiss'); + ctrl.cancel(); + expect($modalInstance.dismiss).toHaveBeenCalledWith(); + }); }); }); diff --git a/openstack_dashboard/karma.conf.js b/openstack_dashboard/karma.conf.js index d5e284d126..90342ed9ff 100644 --- a/openstack_dashboard/karma.conf.js +++ b/openstack_dashboard/karma.conf.js @@ -191,10 +191,10 @@ module.exports = function (config) { // Coverage threshold values. thresholdReporter: { - statements: 90, // target 100 + statements: 92, // target 100 branches: 89, // target 100 - functions: 89, // target 100 - lines: 90 // target 100 + functions: 92, // target 100 + lines: 92 // target 100 } }); };