From 64f1efe961faf8c48de21960ff19a807b908c908 Mon Sep 17 00:00:00 2001 From: Paul Van Eck Date: Mon, 29 Feb 2016 08:58:23 -0800 Subject: [PATCH] Add option to view/download test lists On the guideline page when viewing DefCore capabilities, users might want to get the test list containing only required or advisory tests. This patch provides a way for a user to get that test list to use with RefStack client. The phantomjs version was updated to allow testing with Blobs. Change-Id: I9243f5781cb8a688ca3e64645302db5bc4527c37 --- package.json | 2 +- refstack-ui/app/assets/css/style.css | 8 ++ .../components/capabilities/capabilities.html | 6 + .../capabilities/capabilitiesController.js | 118 +++++++++++++++++- .../partials/capabilityDetails.html | 2 +- .../capabilities/partials/testListModal.html | 24 ++++ refstack-ui/tests/unit/ControllerSpec.js | 104 +++++++++++++++ 7 files changed, 260 insertions(+), 4 deletions(-) create mode 100644 refstack-ui/app/components/capabilities/partials/testListModal.html diff --git a/package.json b/package.json index d2e9bb28..90f0e7c7 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "karma-firefox-launcher": "^0.1.3", "karma-jasmine": "^0.2.2", "karma-phantomjs-launcher": "0.2.0", - "phantomjs": "1.9.17", + "phantomjs": "2.1.1", "protractor": "~1.0.0" }, "scripts": { diff --git a/refstack-ui/app/assets/css/style.css b/refstack-ui/app/assets/css/style.css index a9d41230..51bbfdcd 100644 --- a/refstack-ui/app/assets/css/style.css +++ b/refstack-ui/app/assets/css/style.css @@ -192,3 +192,11 @@ h1, h2, h3, h4, h5, h6 { a.glyphicon { text-decoration: none; } + +.test-list-dl { + word-spacing: normal; +} + +.test-list-dl:hover { + text-decoration: none; +} diff --git a/refstack-ui/app/components/capabilities/capabilities.html b/refstack-ui/app/components/capabilities/capabilities.html index a9375843..aff6a8ef 100644 --- a/refstack-ui/app/components/capabilities/capabilities.html +++ b/refstack-ui/app/components/capabilities/capabilities.html @@ -53,6 +53,12 @@ Removed + + + Test List + diff --git a/refstack-ui/app/components/capabilities/capabilitiesController.js b/refstack-ui/app/components/capabilities/capabilitiesController.js index ff0d9143..1c978f3e 100644 --- a/refstack-ui/app/components/capabilities/capabilitiesController.js +++ b/refstack-ui/app/components/capabilities/capabilitiesController.js @@ -19,14 +19,14 @@ .module('refstackApp') .controller('CapabilitiesController', CapabilitiesController); - CapabilitiesController.$inject = ['$http', 'refstackApiUrl']; + CapabilitiesController.$inject = ['$http', '$uibModal', 'refstackApiUrl']; /** * RefStack Capabilities Controller * This controller is for the '/capabilities' page where a user can browse * through tests belonging to DefCore-defined capabilities. */ - function CapabilitiesController($http, refstackApiUrl) { + function CapabilitiesController($http, $uibModal, refstackApiUrl) { var ctrl = this; ctrl.getVersionList = getVersionList; @@ -34,6 +34,8 @@ ctrl.updateTargetCapabilities = updateTargetCapabilities; ctrl.filterStatus = filterStatus; ctrl.getObjectLength = getObjectLength; + ctrl.getTestList = getTestList; + ctrl.openTestListModal = openTestListModal; /** The target OpenStack marketing program to show capabilities for. */ ctrl.target = 'platform'; @@ -182,6 +184,118 @@ return Object.keys(object).length; } + /** + * This will give a list of tests belonging to capabilities with + * the selected status(es). + */ + function getTestList() { + var caps = ctrl.capabilities.capabilities; + var tests = []; + angular.forEach(ctrl.targetCapabilities, + function (status, cap) { + if (ctrl.status[status]) { + if (ctrl.capabilities.schema === '1.2') { + tests.push.apply(tests, caps[cap].tests); + } + else { + angular.forEach(caps[cap].tests, + function(info, test) { + tests.push(test); + }); + } + } + }); + return tests; + } + + /** + * This will open the modal that will show a list of all tests + * belonging to capabilities with the selected status(es). + */ + function openTestListModal() { + $uibModal.open({ + templateUrl: '/components/capabilities/partials' + + '/testListModal.html', + backdrop: true, + windowClass: 'modal', + animation: true, + controller: 'TestListModalController as modal', + size: 'lg', + resolve: { + tests: function () { + return ctrl.getTestList(); + }, + version: function () { + return ctrl.version.slice(0, -5); + }, + status: function () { + return ctrl.status; + } + } + }); + } + ctrl.getVersionList(); } + + angular + .module('refstackApp') + .controller('TestListModalController', TestListModalController); + + TestListModalController.$inject = [ + '$uibModalInstance', '$window', 'tests', 'version', 'status' + ]; + + /** + * Test List Modal Controller + * This controller is for the modal that appears if a user wants to see the + * ftest list corresponding to DefCore capabilities with the selected + * statuses. + */ + function TestListModalController($uibModalInstance, $window, tests, + version, status) { + + var ctrl = this; + + ctrl.tests = tests; + ctrl.version = version; + ctrl.status = status; + ctrl.close = close; + ctrl.getTestListString = getTestListString; + ctrl.downloadTestList = downloadTestList; + + /** + * This function will close/dismiss the modal. + */ + function close() { + $uibModalInstance.dismiss('exit'); + } + + /** + * This function will return a string representing the sorted + * tests list separated by newlines. + */ + function getTestListString() { + return ctrl.tests.sort().join('\n'); + } + + /** + * Serve the test list as a downloadable file. + */ + function downloadTestList() { + var blob = new Blob([ctrl.getTestListString()], {type: 'text/csv'}); + var filename = ctrl.version + '-test-list.txt'; + if ($window.navigator.msSaveOrOpenBlob) { + $window.navigator.msSaveBlob(blob, filename); + } + else { + var a = $window.document.createElement('a'); + a.href = $window.URL.createObjectURL(blob); + a.download = filename; + $window.document.body.appendChild(a); + a.click(); + $window.document.body.removeChild(a); + } + } + } })(); diff --git a/refstack-ui/app/components/capabilities/partials/capabilityDetails.html b/refstack-ui/app/components/capabilities/partials/capabilityDetails.html index ef38c4e7..9cf49ae0 100644 --- a/refstack-ui/app/components/capabilities/partials/capabilityDetails.html +++ b/refstack-ui/app/components/capabilities/partials/capabilityDetails.html @@ -10,7 +10,7 @@ variable 'capabilities'. {{capability.description}}
Status: {{ctrl.targetCapabilities[capability.id]}}
Project: {{capability.project | capitalize}}
- Achievements ({{capability.achievements.length}})
+ Achievements ({{capability.achievements.length}})
  1. {{achievement}} diff --git a/refstack-ui/app/components/capabilities/partials/testListModal.html b/refstack-ui/app/components/capabilities/partials/testListModal.html new file mode 100644 index 00000000..0705d16f --- /dev/null +++ b/refstack-ui/app/components/capabilities/partials/testListModal.html @@ -0,0 +1,24 @@ + diff --git a/refstack-ui/tests/unit/ControllerSpec.js b/refstack-ui/tests/unit/ControllerSpec.js index 2004ed1c..bbc31da4 100644 --- a/refstack-ui/tests/unit/ControllerSpec.js +++ b/refstack-ui/tests/unit/ControllerSpec.js @@ -152,6 +152,110 @@ describe('Refstack controllers', function () { }; expect(ctrl.getObjectLength(testObject)).toBe(2); }); + + it('should have a function to get a list of tests belonging to ' + + 'capabilities with the selected statuses', + function () { + ctrl.targetCapabilities = {'cap-1': 'required', + 'cap-2': 'advisory'}; + ctrl.capabilities = { + 'schema': 1.4, + 'capabilities' : { + 'cap-1': { + 'tests': { + 'test_1': {'idempotent_id': 'id-1234'}, + 'test_2': {'idempotent_id': 'id-5678'} + } + }, + 'cap-2': { + 'tests': { + 'test_3': {'idempotent_id': 'id-1233'} + } + } + } + }; + expect(ctrl.getTestList()).toEqual(['test_1', 'test_2']); + ctrl.capabilities = { + 'schema': 1.2, + 'capabilities' : { + 'cap-1': { + 'tests': ['test_1', 'test_2'] + }, + 'cap-2': { + 'tests': ['test_3'] + } + } + }; + }); + + it('should have a method to open a modal for the relevant test list', + function () { + var modal; + inject(function ($uibModal) { + modal = $uibModal; + }); + spyOn(modal, 'open'); + ctrl.openTestListModal(); + expect(modal.open).toHaveBeenCalled(); + }); + }); + + describe('TestListModalController', function () { + var modalInstance, ctrl, $window; + + beforeEach(inject(function ($controller, _$window_) { + modalInstance = { + dismiss: jasmine.createSpy('modalInstance.dismiss') + }; + $window = _$window_; + ctrl = $controller('TestListModalController', + {$uibModalInstance: modalInstance, + tests: ['t1', 't2'], + version: '2016.01', + status: {required: true, advisory: false}} + ); + })); + + it('should assign inputs to variables', function () { + expect(ctrl.tests).toEqual(['t1', 't2']); + expect(ctrl.version).toEqual('2016.01'); + expect(ctrl.status).toEqual({required: true, advisory: false}); + }); + + it('should have a method to close the modal', + function () { + ctrl.close(); + expect(modalInstance.dismiss).toHaveBeenCalledWith('exit'); + }); + + it('should have a method to convert the tests to a string', + function () { + ctrl.tests = ['t2', 't1', 't3']; + var expectedString = 't1\nt2\nt3'; + expect(ctrl.getTestListString()).toEqual(expectedString); + }); + + it('should have a method to download a test list', + function () { + var fakeElement = $window.document.createElement('a'); + spyOn($window.document, 'createElement').and.callFake( + function() { + return fakeElement; + }); + spyOn($window.document.body, 'appendChild').and.callFake( + function() { + return true; + }); + spyOn($window.document.body, 'removeChild').and.callFake( + function() { + return true; + }); + ctrl.downloadTestList(); + var doc = $window.document; + expect(doc.createElement).toHaveBeenCalledWith('a'); + expect(doc.body.appendChild).toHaveBeenCalled(); + expect(doc.body.removeChild).toHaveBeenCalled(); + }); }); describe('resultsController', function () {