Merge "Add results and test report page"

This commit is contained in:
Jenkins 2015-04-29 16:05:19 +00:00 committed by Gerrit Code Review
commit c4a5f8e69c
14 changed files with 576 additions and 11 deletions

View File

@ -7,3 +7,4 @@ dist
node_modules
npm-debug.log
app/assets/lib
app/config.json

View File

@ -7,6 +7,10 @@ User interface for interacting with the Refstack API.
Setup
=====
Create a config.json file and specify your API endpoint inside this file:
:code:`cp app/config.json.sample app/config.json`
You can start a development server by doing the following:
Install NodeJS and NPM:

View File

@ -3,8 +3,11 @@
/* App Module */
var refstackApp = angular.module('refstackApp', [
'ui.router', 'ui.bootstrap']);
'ui.router', 'ui.bootstrap', 'cgBusy']);
/*
* Handle application routing.
*/
refstackApp.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
@ -24,7 +27,33 @@ refstackApp.config(['$stateProvider', '$urlRouterProvider',
}).
state('results', {
url: '/results',
templateUrl: '/components/results/results.html'
templateUrl: '/components/results/results.html',
controller: 'resultsController'
}).
state('resultsDetail', {
url: '/results/:testID',
templateUrl: '/components/results-report/resultsReport.html',
controller: 'resultsReportController'
})
}]);
}
]);
/*
* Load Config and start up the angular application.
*/
angular.element(document).ready(function () {
var $http = angular.injector(['ng']).get('$http');
function startApp(config) {
// Add config options as constants.
for (var key in config) {
angular.module('refstackApp').constant(key, config[key]);
}
angular.bootstrap(document, ['refstackApp']);
}
$http.get('config.json').success(function(data) {
startApp(data);
}).error(function(error) {
startApp({});
});
});

View File

@ -100,11 +100,6 @@ h1, h2, h3, h4, h5, h6 {
content: '\00BB';
}
.flagged:before {
color: #E6A100;
content: '\2691';
}
.program-about {
font-size: .8em;
}
@ -128,3 +123,10 @@ h1, h2, h3, h4, h5, h6 {
width: 70%;
height: 70%;
}
.result-filters {
padding-bottom: 10px;
border-top: 2px solid #C9C9C9;
border-bottom: 2px solid #C9C9C9;
margin-bottom: 15px;
}

View File

@ -49,7 +49,8 @@
<a ng-click="hideTests = !hideTests">Tests ({{capability.tests.length}})</a>
<ul collapse="hideTests">
<li ng-repeat="test in capability.tests">
<span ng-class="{'flagged': capability.flagged.indexOf(test) > -1}"> {{test}}</span>
<span ng-class="{'glyphicon glyphicon-flag text-warning': capability.flagged.indexOf(test) > -1}"></span>
{{test}}
</li>
</ul>
</li>

View File

@ -0,0 +1,179 @@
<h3>Test Run Results</h3>
<div cg-busy="{promise:resultsRequest,message:'Loading'}"></div>
<div ng-show="resultsData" class="test-report">
<strong>Test ID:</strong> {{testId}} <br />
<strong>Upload Date:</strong> {{resultsData.created_at}} UTC<br />
<strong>Duration:</strong> {{resultsData.duration_seconds}} seconds<br />
<strong>Total Number of Passed Tests:</strong> {{resultsData.results.length}} <br />
<hr>
<p>See how these results stack up against DefCore capabilities and OpenStack
<a target="_blank" href="http://www.openstack.org/brand/interop/">target marketing programs.</a>
</p>
<div class="row">
<div class="col-md-3">
<strong>Capabilities Version:</strong>
<select ng-model="version" ng-change="updateCapabilities()" class="form-control">
<option value="2015.03">2015.03</option>
</select>
</div>
<div class="col-md-4">
<strong>Target Program:</strong>
<select ng-model="target" class="form-control" ng-change="buildCapabilityObject()">
<option value="platform">OpenStack Powered Platform</option>
<option value="compute">OpenStack Powered Compute</option>
<option value="object">OpenStack Powered Object Storage</option>
</select>
</div>
</div>
</div>
<br />
<div ng-show="capabilityData && resultsData">
<strong>Status:</strong>
<div class="progress">
<div class="progress-bar"
role="progressbar"
aria-valuenow="{{caps.required.passedCount*100/caps.required.count | number:1}}"
aria-valuemin="0"
aria-valuemax="100"
style="min-width: 3em; width: {{caps.required.passedCount*100/caps.required.count}}%;">
{{caps.required.passedCount*100/caps.required.count | number:1}}%
</div>
</div>
<p>This cloud passes <strong>{{caps.required.passedCount*100/caps.required.count | number:1}}% </strong>({{caps.required.passedCount}}/{{caps.required.count}})
of the <strong>{{version}}</strong> capability tests required by the <strong>{{targetMappings[target]}}</strong> program.</p>
<h4>Capability Overview</h4>
<accordion close-others=false>
<accordion-group heading="Required" is-open="requiredOpen" is-disabled="caps.required.caps.length == 0">
<accordion-heading>
Required <small>({{caps.required.caps.length}} capabilities)</small>
<i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': requiredOpen, 'glyphicon-chevron-right': !requiredOpen}"></i>
</accordion-heading>
<ol class="capabilities">
<li ng-repeat="capability in caps.required.caps">
<a ng-click="hideTests = !hideTests">{{capability.id}} </a>
<span ng-class="{'text-success': (capability.passedTests.length > 0 && capability.notPassedTests.length == 0),
'text-danger': (capability.passedTests.length == 0 && capability.notPassedTests.length > 0),
'text-warning': (capability.passedTests.length > 0 && capability.notPassedTests.length > 0)}">
[{{capability.passedTests.length}}/{{capability.passedTests.length + capability.notPassedTests.length}}]
</span>
<ul class="list-unstyled" collapse="hideTests">
<li ng-repeat="test in capability.passedTests">
<span class="glyphicon glyphicon-ok text-success" aria-hidden="true"></span>
<span ng-class="{'glyphicon glyphicon-flag text-warning': capabilityData.capabilities[capability.id].flagged.indexOf(test) > -1}"></span>
{{test}}
</li>
<li ng-repeat="test in capability.notPassedTests">
<span class="glyphicon glyphicon-remove text-danger" aria-hidden="true"></span>
<span ng-class="{'glyphicon glyphicon-flag text-warning': capabilityData.capabilities[capability.id].flagged.indexOf(test) > -1}"></span>
{{test}}
</li>
</ul>
</li>
</ol>
</accordion-group>
<accordion-group heading="Advisory" is-open="advisoryOpen" is-disabled="caps.advisory.caps.length == 0">
<accordion-heading>
Advisory <small>({{caps.advisory.caps.length}} capabilities)</small>
<i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': advisoryOpen, 'glyphicon-chevron-right': !advisoryOpen}"></i>
</accordion-heading>
<ol class="capabilities">
<li ng-repeat="capability in caps.advisory.caps">
<a ng-click="hideTests = !hideTests">{{capability.id}} </a>
<span ng-class="{'text-success': (capability.passedTests.length > 0 && capability.notPassedTests.length == 0),
'text-danger': (capability.passedTests.length == 0 && capability.notPassedTests.length > 0),
'text-warning': (capability.passedTests.length > 0 && capability.notPassedTests.length > 0)}">
[{{capability.passedTests.length}}/{{capability.passedTests.length + capability.notPassedTests.length}}]
</span>
<ul class="list-unstyled" collapse="hideTests">
<li ng-repeat="test in capability.passedTests">
<span class="glyphicon glyphicon-ok text-success" aria-hidden="true"></span>
<span ng-class="{'glyphicon glyphicon-flag text-warning': capabilityData.capabilities[capability.id].flagged.indexOf(test) > -1}"></span>
{{test}}
</li>
<li ng-repeat="test in capability.notPassedTests">
<span class="glyphicon glyphicon-remove text-danger" aria-hidden="true"></span>
<span ng-class="{'glyphicon glyphicon-flag text-warning': capabilityData.capabilities[capability.id].flagged.indexOf(test) > -1}"></span>
{{test}}
</li>
</ul>
</li>
</ol>
</accordion-group>
<accordion-group heading="Deprecated" is-open="deprecatedOpen" is-disabled="caps.deprecated.caps.length == 0">
<accordion-heading>
Deprecated <small>({{caps.deprecated.caps.length}} capabilities)</small>
<i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': deprecatedOpen, 'glyphicon-chevron-right': !deprecatedOpen}"></i>
</accordion-heading>
<ol class="capabilities">
<li ng-repeat="capability in caps.deprecated.caps">
<a ng-click="hideTests = !hideTests">{{capability.id}} </a>
<span ng-class="{'text-success': (capability.passedTests.length > 0 && capability.notPassedTests.length == 0),
'text-danger': (capability.passedTests.length == 0 && capability.notPassedTests.length > 0),
'text-warning': (capability.passedTests.length > 0 && capability.notPassedTests.length > 0)}">
[{{capability.passedTests.length}}/{{capability.passedTests.length + capability.notPassedTests.length}}]
</span>
<ul class="list-unstyled" collapse="hideTests">
<li ng-repeat="test in capability.passedTests">
<span class="glyphicon glyphicon-ok text-success" aria-hidden="true"></span>
<span ng-class="{'glyphicon glyphicon-flag text-warning': capabilityData.capabilities[capability.id].flagged.indexOf(test) > -1}"></span>
{{test}}
</li>
<li ng-repeat="test in capability.notPassedTests">
<span class="glyphicon glyphicon-remove text-danger" aria-hidden="true"></span>
<span ng-class="{'glyphicon glyphicon-flag text-warning': capabilityData.capabilities[capability.id].flagged.indexOf(test) > -1}"></span>
{{test}}
</li>
</ul>
</li>
</ol>
</accordion-group>
<accordion-group is-open="removedOpen" is-disabled="caps.removed.caps.length == 0">
<accordion-heading>
Removed <small>({{caps.removed.caps.length}} capabilities)</small>
<i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': removedOpen, 'glyphicon-chevron-right': !removedOpen}"></i>
</accordion-heading>
<ol class="capabilities">
<li ng-repeat="capability in caps.removed.caps">
<a ng-click="hideTests = !hideTests">{{capability.id}} </a>
<span ng-class="{'text-success': (capability.passedTests.length > 0 && capability.notPassedTests.length == 0),
'text-danger': (capability.passedTests.length == 0 && capability.notPassedTests.length > 0),
'text-warning': (capability.passedTests.length > 0 && capability.notPassedTests.length > 0)}">
[{{capability.passedTests.length}}/{{capability.passedTests.length + capability.notPassedTests.length}}]
</span>
<ul class="list-unstyled" collapse="hideTests">
<li ng-repeat="test in capability.passedTests">
<span class="glyphicon glyphicon-ok text-success" aria-hidden="true"></span>
<span ng-class="{'glyphicon glyphicon-flag text-warning': capabilityData.capabilities[capability.id].flagged.indexOf(test) > -1}"></span>
{{test}}
</li>
<li ng-repeat="test in capability.notPassedTests">
<span class="glyphicon glyphicon-remove text-danger" aria-hidden="true"></span>
<span ng-class="{'glyphicon glyphicon-flag text-warning': capabilityData.capabilities[capability.id].flagged.indexOf(test) > -1}"></span>
{{test}}
</li>
</ul>
</li>
</ol>
</accordion-group>
</accordion>
</div>
<div ng-show="showError" class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<span class="sr-only">Error:</span>
{{error}}
</div>

View File

@ -0,0 +1,91 @@
'use strict';
/* Refstack Results Report Controller */
var refstackApp = angular.module('refstackApp');
refstackApp.controller('resultsReportController', ['$scope', '$http', '$stateParams', 'refstackApiUrl',
function($scope, $http, $stateParams, refstackApiUrl) {
$scope.testId = $stateParams.testID
$scope.version = '2015.03';
$scope.hideTests = true;
$scope.target = 'platform';
$scope.requiredOpen = true;
$scope.targetMappings = {
'platform': 'Openstack Powered Platform',
'compute': 'OpenStack Powered Compute',
'object': 'OpenStack Powered Object Storage'
}
var content_url = refstackApiUrl +'/results/' + $scope.testId;
$scope.resultsRequest = $http.get(content_url).success(function(data) {
$scope.resultsData = data;
$scope.updateCapabilities();
}).error(function(error) {
$scope.showError = true;
$scope.resultsData = null;
$scope.error = "Error retrieving results from server: " + JSON.stringify(error);
});
$scope.updateCapabilities = function() {
$scope.showError = false;
var content_url = 'assets/capabilities/'.concat($scope.version, '.json');
$http.get(content_url).success(function(data) {
$scope.capabilityData = data;
$scope.buildCapabilityObject($scope.capabilityData, $scope.resultsData.results);
}).error(function(error) {
$scope.showError = true;
$scope.capabilityData = null;
$scope.error = 'Error retrieving capabilities: ' + JSON.stringify(error);
});
}
$scope.buildCapabilityObject = function() {
var capabilities = $scope.capabilityData.capabilities;
var caps = {'required': {'caps': [], 'count': 0, 'passedCount': 0},
'advisory': {'caps': [], 'count': 0, 'passedCount': 0},
'deprecated': {'caps': [], 'count': 0, 'passedCount': 0},
'removed': {'caps': [], 'count': 0, 'passedCount': 0}};
var components = $scope.capabilityData.components;
var cap_array = [];
// First determine which capabilities are relevant to the target.
if ($scope.target === 'platform') {
var platform_components = $scope.capabilityData.platform.required;
// For each component required for the platform program.
angular.forEach(platform_components, function(component) {
// Get each capability belonging to each status.
angular.forEach(components[component], function(capabilities) {
cap_array = cap_array.concat(capabilities);
});
});
}
else {
angular.forEach(components[$scope.target], function(capabilities) {
cap_array = cap_array.concat(capabilities);
});
}
angular.forEach(capabilities, function(value, key) {
if (cap_array.indexOf(key) > -1) {
var cap = { "id": key,
"passedTests": [],
"notPassedTests": []};
caps[value.status].count += value.tests.length;
angular.forEach(value.tests, function(test_id) {
if ($scope.resultsData.results.indexOf(test_id) > -1) {
cap.passedTests.push(test_id);
}
else {
cap.notPassedTests.push(test_id);
}
});
caps[value.status].passedCount += cap.passedTests.length;
caps[value.status].caps.push(cap);
}
});
$scope.caps = caps;
}
}
]);

View File

@ -1 +1,82 @@
<p>Community results list here.</p>
<h3>Community Results</h3>
<p>The most recently uploaded community test results are listed here. Currently, these results are anonymous.</p>
<div class="result-filters">
<h4>Filters</h4>
<div class="row">
<div class="col-md-3">
<label for="cpid">Start Date</label>
<p class="input-group">
<input type="text" class="form-control"
datepicker-popup="{{format}}"
ng-model="startDate" is-open="startOpen"
datepicker-options="dateOptions"
close-text="Close" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event, 'startOpen')">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</p>
</div>
<div class="col-md-3">
<label for="cpid">End Date</label>
<p class="input-group">
<input type="text" class="form-control"
datepicker-popup="{{format}}"
ng-model="endDate" is-open="endOpen"
datepicker-options="dateOptions"
close-text="Close" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event, 'endOpen')">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</p>
</div>
<div class="col-md-3"style="margin-top:24px;">
<button type="submit" class="btn btn-primary" ng-click="update()">Filter</button>
<button type="submit" class="btn btn-primary btn-danger" ng-click="clearFilters()">Clear</button>
</div>
</div>
</div>
<div cg-busy="{promise:resultsRequest,message:'Loading'}"></div>
<div ng-show="data" class="results-table">
<table ng-show="data" class="table table-striped table-hover">
<thead>
<tr>
<th>Upload Date</th>
<th>Test Run ID</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="result in data.results">
<td>{{result.created_at}}</td>
<td><a ui-sref="resultsDetail({testID: result.test_id})">{{result.test_id}}</a></td>
</tr>
</tbody>
</table>
<div class="pages">
<pagination
total-items="totalItems"
ng-model="currentPage"
items-per-page="itemsPerPage"
max-size="maxSize"
class="pagination-sm"
boundary-links="true"
rotate="false"
num-pages="numPages"
ng-change="update()">
</pagination>
</div>
</div>
<div ng-show="showError" class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<span class="sr-only">Error:</span>
{{error}}
</div>

View File

@ -0,0 +1,51 @@
'use strict';
/* Refstack Results Controller */
var refstackApp = angular.module('refstackApp');
refstackApp.controller('resultsController', ['$scope', '$http', '$filter', 'refstackApiUrl', function($scope, $http, $filter, refstackApiUrl) {
$scope.currentPage = 1;
$scope.itemsPerPage = 20;
$scope.maxSize = 5;
$scope.startDate = "";
$scope.endDate = "";
$scope.update = function() {
$scope.showError = false;
var content_url = refstackApiUrl + '/results?page=' + $scope.currentPage;
var start = $filter('date')($scope.startDate, "yyyy-MM-dd");
if (start) {
content_url = content_url + "&start_date=" + start + " 00:00:00";
}
var end = $filter('date')($scope.endDate, "yyyy-MM-dd");
if (end) {
content_url = content_url + "&end_date=" + end + " 23:59:59";
}
$scope.resultsRequest = $http.get(content_url).success(function(data) {
$scope.data = data;
$scope.totalItems = $scope.data.pagination.total_pages * $scope.itemsPerPage;
$scope.currentPage = $scope.data.pagination.current_page;
}).error(function(error) {
$scope.data = null;
$scope.totalItems = 0
$scope.showError = true
$scope.error = "Error retrieving results listing from server: " + JSON.stringify(error);
});
}
$scope.update();
// This is called when a date filter calendar is opened.
$scope.open = function($event, openVar) {
$event.preventDefault();
$event.stopPropagation();
$scope[openVar] = true;
};
$scope.clearFilters = function() {
$scope.startDate = null;
$scope.endDate = null;
$scope.update();
};
}]);

View File

@ -0,0 +1 @@
{"refstackApiUrl": "http://api.refstack.net/v1"}

View File

@ -14,7 +14,7 @@
License for the specific language governing permissions and limitations
under the License.
-->
<html ng-app="refstackApp">
<html id="ng-app">
<head>
<meta charset="utf-8">
<meta name="description" content="Refstack">
@ -24,17 +24,22 @@
<link rel="shorcut icon" href="favicon.ico">
<link rel="stylesheet" href="assets/lib/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/lib/angular-busy/dist/angular-busy.min.css">
<link rel="stylesheet" href="assets/css/style.css">
<script src="assets/lib/angular/angular.js"></script>
<script src="assets/lib/angular-ui-router/release/angular-ui-router.js"></script>
<script src="assets/lib/angular-bootstrap/ui-bootstrap.min.js"></script>
<script src="assets/lib/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
<script src="assets/lib/angular-busy/dist/angular-busy.min.js"></script>
<script src="app.js"></script>
<script src="assets/js/refstack.js"></script>
<!-- Controllers -->
<script src="shared/header/headerController.js"></script>
<script src="components/capabilities/capabilitiesController.js"></script>
<script src="components/results/resultsController.js"></script>
<script src="components/results-report/resultsReportController.js"></script>
<!-- Filters -->
<script src="shared/filters.js"></script>

View File

@ -7,6 +7,7 @@
"angular-ui-router": "0.2.13",
"angular-resource": "1.3.15",
"angular-bootstrap": "0.12.1",
"angular-busy": "4.1.3",
"bootstrap": "3.3.2"
},
"devDependencies": {

View File

@ -9,6 +9,8 @@ module.exports = function(config){
'app/assets/lib/angular-ui-router/release/angular-ui-router.js',
'app/assets/lib/angular-bootstrap/ui-bootstrap.min.js',
'app/assets/lib/angular-mocks/angular-mocks.js',
'app/assets/lib/angular-bootstrap/ui-bootstrap-tpls.min.js',
'app/assets/lib/angular-busy/dist/angular-busy.min.js',
// JS files.
'app/app.js',

View File

@ -91,4 +91,121 @@ describe('Refstack controllers', function() {
expect(scope.filterProgram({'id': 'cap_id_5'})).toBe(false);
});
});
describe('resultsController', function() {
var scope, ctrl, $httpBackend, refstackApiUrl;
var fakeResponse = {'pagination': {'current_page': 1, 'total_pages': 2},
'results': [{'created_at': '2015-03-09 01:23:45',
'test_id': 'some-id',
'cpid': 'some-cpid'}]};
beforeEach(function() {
module('refstackApp');
module(function($provide) {
$provide.constant('refstackApiUrl', 'http://foo.bar/v1');
});
});
beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) {
$httpBackend = _$httpBackend_;
scope = $rootScope.$new();
ctrl = $controller('resultsController', {$scope: scope});
}));
it('should fetch the first page of results with proper URL args', function() {
// Initial results should be page 1 of all results.
$httpBackend.expectGET('http://foo.bar/v1/results?page=1').respond(fakeResponse);
$httpBackend.flush();
expect(scope.data).toEqual(fakeResponse);
expect(scope.currentPage).toBe(1);
// Simulate the user adding date filters.
scope.startDate = new Date('2015-03-10T11:51:00');
scope.endDate = new Date('2015-04-10T11:51:00');
scope.update();
$httpBackend.expectGET('http://foo.bar/v1/results?page=1&start_date=2015-03-10 00:00:00&end_date=2015-04-10 23:59:59').respond(fakeResponse);
$httpBackend.flush();
expect(scope.data).toEqual(fakeResponse);
expect(scope.currentPage).toBe(1);
});
it('should set an error when results cannot be retrieved', function() {
$httpBackend.expectGET('http://foo.bar/v1/results?page=1').respond(404, {'detail': 'Not Found'});
$httpBackend.flush();
expect(scope.data).toBe(null);
expect(scope.error).toEqual('Error retrieving results listing from server: {"detail":"Not Found"}');
expect(scope.totalItems).toBe(0);
expect(scope.showError).toBe(true);
});
it('should have an function to clear filters and update the view', function() {
$httpBackend.expectGET('http://foo.bar/v1/results?page=1').respond(fakeResponse);
scope.startDate = "some date";
scope.endDate = "some other date";
scope.clearFilters();
expect(scope.startDate).toBe(null);
expect(scope.endDate).toBe(null);
$httpBackend.expectGET('http://foo.bar/v1/results?page=1').respond(fakeResponse);
$httpBackend.flush();
expect(scope.data).toEqual(fakeResponse);
});
});
describe('resultsReportController', function() {
var scope, ctrl, $httpBackend, refstackApiUrl, stateparams;
var fakeResultResponse = {'results': ['test_id_1']}
var fakeCapabilityResponse = {'platform': {'required': ['compute']},
'components': {
'compute': {
'required': ['cap_id_1'],
'advisory': [],
'deprecated': [],
'removed': []
}
},
'capabilities': {
'cap_id_1': {
'status': 'required',
'flagged': [],
'tests': ['test_id_1', 'test_id_2']
}
}
};
beforeEach(function() {
module('refstackApp');
module(function($provide) {
$provide.constant('refstackApiUrl', 'http://foo.bar/v1');
});
});
beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) {
$httpBackend = _$httpBackend_;
stateparams = {testID: 1234};
scope = $rootScope.$new();
ctrl = $controller('resultsReportController', {$scope: scope, $stateParams: stateparams});
}));
it('should get the results for a specific test ID and also the relevant capabilities', function() {
$httpBackend.expectGET('http://foo.bar/v1/results/1234').respond(fakeResultResponse);
$httpBackend.expectGET('assets/capabilities/2015.03.json').respond(fakeCapabilityResponse);
$httpBackend.flush();
expect(scope.resultsData).toEqual(fakeResultResponse);
expect(scope.capabilityData).toEqual(fakeCapabilityResponse);
});
it('should be able to sort the results into a capability object', function() {
scope.resultsData = fakeResultResponse;
scope.capabilityData = fakeCapabilityResponse;
scope.buildCapabilityObject();
var expectedCapsObject = {'required': {'caps': [{'id': 'cap_id_1',
'passedTests': ['test_id_1'],
'notPassedTests': ['test_id_2']}],
'count': 2, 'passedCount': 1},
'advisory': {'caps': [], 'count': 0, 'passedCount': 0},
'deprecated': {'caps': [], 'count': 0, 'passedCount': 0},
'removed': {'caps': [], 'count': 0, 'passedCount': 0}};
expect(scope.caps).toEqual(expectedCapsObject);
});
});
});