Fix karma tests

* Exit karma with the given exit code after tests have run

* Fix NotificationBox directive test

* Set karma singleRun to true

* Refactor loadingIndicator service

* Fix apiV3 service tests

* Fix HalLink service tests

* Fix HalResource tests

* Reformat WP list controller test code

* Fix WP list controller tests

* Refactor wpContextMenu and fix its tests
pull/4296/head
Alex Dik 9 years ago committed by Oliver Günther
parent 6cf73f80d0
commit 32d229bdab
  1. 1
      frontend/app/components/api/api-v3/api-v3.service.test.ts
  2. 6
      frontend/app/components/api/api-v3/hal-link/hal-link.service.test.ts
  3. 8
      frontend/app/components/api/api-v3/hal-resources/hal-resource.service.test.ts
  4. 14
      frontend/app/components/common/loading-indicator/loading-indicator.service.ts
  5. 11
      frontend/app/components/context-menus/wp-context-menu/wp-context-menu.controller.ts
  6. 0
      frontend/app/components/context-menus/wp-context-menu/wp-context-menu.service.html
  7. 124
      frontend/app/components/context-menus/wp-context-menu/wp-context-menu.service.test.ts
  8. 39
      frontend/app/components/context-menus/wp-context-menu/wp-context-menu.service.ts
  9. 249
      frontend/app/components/routing/wp-list/wp-list.controller.test.ts
  10. 3
      frontend/app/openproject-app.js
  11. 23
      frontend/app/work_packages/controllers/menus/index.js
  12. 33
      frontend/gulpfile.js
  13. 11
      frontend/tests/unit/tests/directives/components/notification-box-directive-test.js

@ -38,6 +38,7 @@ describe('apiV3 service', () => {
$httpBackend = _$httpBackend_;
apiV3.setBaseUrl('/base');
apiV3.setDefaultHttpFields({cache: false});
}));
it('should exist', () => {

@ -31,13 +31,13 @@ describe('HalLink service', () => {
var HalLink;
var apiV3;
beforeEach(angular.mock.module('openproject.api'));
beforeEach(angular.mock.module('openproject.services'));
beforeEach(angular.mock.module('openproject.api', 'openproject.services'));
beforeEach(angular.mock.inject((_apiV3_, _HalLink_, _$httpBackend_) => {
apiV3 = _apiV3_;
HalLink = _HalLink_;
$httpBackend = _$httpBackend_;
apiV3.setDefaultHttpFields({cache: false});
}));
it('should exist', () => {

@ -33,13 +33,13 @@ describe('HalResource service', () => {
var $httpBackend:ng.IHttpBackendService;
var NotificationsService;
beforeEach(angular.mock.module('openproject.api'));
beforeEach(angular.mock.module('openproject.services'));
beforeEach(angular.mock.inject((_HalResource_, _$httpBackend_, _NotificationsService_) => {
beforeEach(angular.mock.module('openproject.api', 'openproject.services'));
beforeEach(angular.mock.inject((_HalResource_, _$httpBackend_, _NotificationsService_, apiV3) => {
NotificationsService = _NotificationsService_;
HalResource = _HalResource_;
$httpBackend = _$httpBackend_;
apiV3.setDefaultHttpFields({cache: false});
}));
it('should exist', () => {

@ -27,19 +27,11 @@
// ++
/**
* @description An object holding promises for page load indication for cg-busy.
* An object holding promises for page load indication for cg-busy.
*
* @see https://github.com/cgross/angular-busy/
*/
// TODO: move interface definition to openproject-typings
export interface LoadingIndicator {
[name:string]: ng.IPromise<any>;
}
function loadingIndicator():LoadingIndicator {
return {};
}
angular
.module('openproject.workPackages.services')
.factory('loadingIndicator', loadingIndicator);
.value('loadingIndicator', {});

@ -1,4 +1,4 @@
//-- copyright
// -- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
//
@ -24,9 +24,9 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
//++
// ++
module.exports = function(
function wpContextMenuController(
$scope,
$state,
WorkPackagesTableHelper,
@ -111,5 +111,8 @@ module.exports = function(
return workPackagesfromSelectedRows;
}
}
}
};
angular
.module('openproject.workPackages')
.controller('WorkPackageContextMenuController', wpContextMenuController);

@ -1,4 +1,4 @@
//-- copyright
// -- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
//
@ -24,43 +24,46 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
//++
/*jshint expr: true*/
describe('workPackageContextMenu', function() {
var container, contextMenu, $rootScope, stateParams, ngContextMenu;
stateParams = {};
beforeEach(module('ng-context-menu',
'openproject.api',
'openproject.workPackages',
'openproject.models',
'openproject.layout',
'openproject.services',
'openproject.templates'));
beforeEach(module('openproject.templates', function($provide) {
var configurationService = {};
configurationService.isTimezoneSet = sinon.stub().returns(false);
configurationService.accessibilityModeEnabled = sinon.stub().returns(false);
// ++
var expect = chai.expect;
declare var Factory:any;
describe('workPackageContextMenu', () => {
var container;
var contextMenu;
var $rootScope;
var stateParams = {};
var ngContextMenu;
beforeEach(angular.mock.module('ng-context-menu',
'openproject.api',
'openproject.workPackages',
'openproject.models',
'openproject.layout',
'openproject.services',
'openproject.templates'));
beforeEach(angular.mock.module('openproject.templates', ($provide) => {
var configurationService = {
isTimezoneSet: sinon.stub().returns(false),
accessibilityModeEnabled: sinon.stub().returns(false)
};
$provide.constant('ConfigurationService', configurationService);
$provide.constant('$stateParams', stateParams);
}));
beforeEach(function() {
var html = '<div></div>';
container = angular.element(html);
beforeEach(() => {
container = angular.element('<div></div>');
});
beforeEach(inject(function(_$rootScope_, _ngContextMenu_, $templateCache) {
beforeEach(angular.mock.inject((_$rootScope_, _ngContextMenu_, $templateCache) => {
$rootScope = _$rootScope_;
ngContextMenu = _ngContextMenu_;
var template = $templateCache
.get('/templates/work_packages/menus/work_package_context_menu.html');
.get('/components/context-menus/wp-context-menu/wp-context-menu.service.html');
$templateCache.put('work_package_context_menu.html', [200, template, {}]);
contextMenu = ngContextMenu({
@ -73,27 +76,27 @@ describe('workPackageContextMenu', function() {
contextMenu.open({x: 0, y: 0});
}));
describe('when the context menu context contains one work package', function() {
describe('when the context menu context contains one work package', () => {
var I18n;
var actions = ['edit', 'move'],
actionLinks = {
update: '/work_packages/123/edit',
move: '/work_packages/move/new?ids%5B%5D=123',
},
workPackage = Factory.build('PlanningElement', {
$links: actionLinks
});
var actions = ['edit', 'move'];
var actionLinks = {
update: '/work_packages/123/edit',
move: '/work_packages/move/new?ids%5B%5D=123',
};
var workPackage = Factory.build('PlanningElement', {
$links: actionLinks
});
var directListElements;
beforeEach(inject(function(_I18n_) {
beforeEach(angular.mock.inject((_I18n_) => {
I18n = _I18n_;
sinon.stub(I18n, 't').withArgs('js.button_' + actions[0]).returns('anything');
}));
afterEach(inject(function() {
afterEach(angular.mock.inject(() => {
I18n.t.restore();
}));
beforeEach(function() {
beforeEach(() => {
$rootScope.rows = [];
$rootScope.row = {object: workPackage};
@ -102,52 +105,37 @@ describe('workPackageContextMenu', function() {
directListElements = container.find('.dropdown-menu > li:not(.folder)');
});
it('lists link tags for any permitted action', function(){
expect(directListElements.length).to.equal(3);
it('lists link tags for any permitted action', () =>{
expect(directListElements.length).to.equal(4);
});
it('assigns a css class named by the action', function(){
expect(directListElements[1].className).to.equal(actions[0]);
it('assigns a css class named by the action', () =>{
expect(directListElements[2].className).to.equal(actions[0]);
});
it('adds an icon from the icon fonts to each list container', function() {
it('adds an icon from the icon fonts to each list container', () => {
expect(container.find('.' + actions[0] +' a i').attr('class')).to.include('icon-' + actions[0]);
});
xit('translates the action name', function() {
expect(container.find('.' + actions[0] +' a i').contents()).to.equal('anything');
// TODO find out how to stub I18n.t inside directive
});
it('sets the checked property of the row within the context to true', function() {
it('sets the checked property of the row within the context to true', () => {
expect($rootScope.row.checked).to.be.true;
});
describe('when delete is permitted on a work package', function() {
var actions = ['delete'],
actionLinks = {
delete: '/work_packages/bulk',
},
workPackage = Factory.build('PlanningElement', {
$links: actionLinks
});
describe('when delete is permitted on a work package', () => {
var actionLinks = {
'delete': '/work_packages/bulk',
};
var workPackage = Factory.build('PlanningElement', {
$links: actionLinks
});
beforeEach(function() {
beforeEach(() => {
$rootScope.rows = [];
$rootScope.row = {object: workPackage};
$rootScope.$digest();
directListElements = container.find('.dropdown-menu > li:not(.folder)');
});
xit('displays a link triggering deleteWorkPackages within the scope', function() {
expect(directListElements.find('a:has(i.icon-delete)').attr('ng-click')).to.equal('deleteWorkPackages()');
});
});
});
xdescribe('when the context menu context contains multiple work packages', function() {
});
});

@ -0,0 +1,39 @@
// -- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
// Copyright (C) 2006-2013 Jean-Philippe Lang
// Copyright (C) 2010-2013 the ChiliProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
// ++
function wpContextMenuService(ngContextMenu) {
return ngContextMenu({
controller: 'WorkPackageContextMenuController',
controllerAs: 'contextMenu',
templateUrl: '/components/context-menus/wp-context-menu/wp-context-menu.service.html'
});
}
angular
.module('openproject.workPackages')
.factory('WorkPackageContextMenu', wpContextMenuService);

@ -26,9 +26,19 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
describe('WorkPackagesListController', function() {
var scope, ctrl, win, testProjectService, testWorkPackageService, testQueryService,
testPaginationService, testApiWorkPackages, testAuthorisationService;
var expect = chai.expect;
describe('WorkPackagesListController', () => {
var scope;
var ctrl;
var win;
var wpListServiceMock;
var testProjectService;
var testWorkPackageService;
var testQueryService;
var testPaginationService;
var testApiWorkPackages;
var testAuthorisationService;
var testQueries;
var buildController;
var stateParams = {};
@ -36,19 +46,18 @@ describe('WorkPackagesListController', function() {
beforeEach(angular.mock.module('openproject.api', 'openproject.workPackages.controllers',
'openproject.workPackages.services', 'ng-context-menu', 'btford.modal', 'openproject.layout',
'openproject.services', 'openproject.wpButtons'));
beforeEach(angular.mock.module('openproject.templates', function($provide) {
var configurationService = {};
configurationService.isTimezoneSet = sinon.stub().returns(false);
beforeEach(angular.mock.module('openproject.templates', ($provide) => {
var configurationService = {
isTimezoneSet: sinon.stub().returns(false)
};
$provide.constant('$stateParams', stateParams);
$provide.constant('ConfigurationService', configurationService);
}));
beforeEach(inject(function($rootScope, $controller, $timeout, $q) {
beforeEach(angular.mock.inject(($rootScope, $controller, $timeout, $q, $cacheFactory) => {
scope = $rootScope.$new();
win = {
location: { pathname: '' }
win = {
location: {pathname: ''}
};
var defaultWorkPackagesData = {
@ -63,63 +72,57 @@ describe('WorkPackagesListController', function() {
var workPackagesDataByQueryId = {
meta: {
query: {
props: { id: 1 },
props: {id: 1},
_links: []
},
sums: [null]
},
work_packages: []
};
var columnData = {
};
var availableQueryiesData = {
};
var columnData = {};
var availableQueryiesData = {};
var projectData = { embedded: { types: [] } };
var projectsData = [ projectData ];
var projectData = {embedded: {types: []}};
var projectsData = [projectData];
testQueries = {
'1': {
id: 1,
columns: ['type'],
getSortation: function() { return null; },
isNew: function() { return false; }
getSortation: () => null,
isNew: () => false
},
'2': {
id: 2,
columns: ['type'],
getSortation: function() { return null; },
isNew: function() { return false; }
getSortation: () => null,
isNew: () => false
}
};
testProjectService = {
getProject: function() {
return $timeout(function() {
return projectData;
}, 10);
getProject: () => {
return $timeout(() => projectData, 10);
},
getProjects: function() {
return $timeout(function() {
return projectsData;
}, 10);
getProjects: () => {
return $timeout(() => projectsData, 10);
}
};
var wpCache = $cacheFactory('workPackageCache');
testWorkPackageService = {
getWorkPackages: function () {
return $timeout(function () {
return defaultWorkPackagesData;
}, 10);
getWorkPackages: () => {
return $timeout(() => defaultWorkPackagesData, 10);
},
getWorkPackagesByQueryId: function () {
return $timeout(function () {
return workPackagesDataByQueryId;
}, 10);
getWorkPackagesByQueryId: () => {
return $timeout(() => workPackagesDataByQueryId, 10);
},
cache() {
return wpCache;
}
};
testApiWorkPackages = {
list: function() {
list: () => {
var deferred = $q.defer();
deferred.resolve({
"_type": "Collection",
@ -130,68 +133,79 @@ describe('WorkPackagesListController', function() {
};
testQueryService = {
getQuery: function () {
getQuery: () => {
return {
getQueryString: function () {
getQueryString: () => {
}
};
},
initQuery: function (id) {
initQuery: (id) => {
var queryId = id || 1;
return testQueries[queryId];
},
clearQuery: function() {},
loadAvailableColumns: function () {
return $timeout(function () {
return columnData;
}, 10);
clearQuery: () => {
},
loadAvailableGroupedQueries: function () {
return $timeout(function () {
return availableQueryiesData;
}, 10);
loadAvailableColumns: () => {
return $timeout(() => columnData, 10);
},
loadAvailableUnusedColumns: function() {
return $timeout(function () {
return columnData;
}, 10);
loadAvailableGroupedQueries: () => {
return $timeout(() => availableQueryiesData, 10);
},
getTotalEntries: function() {
loadAvailableUnusedColumns: () => {
return $timeout(() => columnData, 10);
},
setTotalEntries: function() {
return 10;
getTotalEntries: () => {
},
setTotalEntries: () => 10,
};
testPaginationService = {
setPerPageOptions: function () {
setPerPageOptions: () => {
},
setPerPage: function () {
setPerPage: () => {
},
setPage: function () {
setPage: () => {
}
};
testAuthorisationService = {
initModelAuth: function(model, links) {
initModelAuth: () => {
}
};
buildController = function(params, state, location) {
scope.projectIdentifier = 'test';
wpListServiceMock = {
fromQueryParams() {
return $q.when({
meta: {
query: {},
columns: {},
export_formats: {}
},
resource: {
total: 10
},
work_packages: [
{}
]
});
}
};
buildController = (params, state, location) => {
scope.projectIdentifier = 'test';
ctrl = $controller("WorkPackagesListController", {
$scope: scope,
$scope: scope,
$window: win,
QueryService: testQueryService,
PaginationService: testPaginationService,
ProjectService: testProjectService,
QueryService: testQueryService,
PaginationService: testPaginationService,
ProjectService: testProjectService,
WorkPackageService: testWorkPackageService,
apiWorkPackages: testApiWorkPackages,
$stateParams: params,
$state: state,
$location: location,
apiWorkPackages: testApiWorkPackages,
$stateParams: params,
$state: state,
$location: location,
wpListService: wpListServiceMock
});
$timeout.flush();
@ -199,124 +213,121 @@ describe('WorkPackagesListController', function() {
}));
describe('initialisation of default query', function() {
var testParams, testState, testLocation;
describe('initialisation of default query', () => {
var testParams;
var testState;
var testLocation;
beforeEach(function(){
testParams = { projectPath: '/projects/my-project' };
beforeEach(() => {
testParams = {projectPath: '/projects/my-project'};
testState = {
params: testParams,
href: function() { return ''; }
href: () => ''
};
testLocation = {
search: function() {
return {};
},
search: () => ({}),
url: angular.identity
};
buildController(testParams, testState, testLocation);
});
it('should initialise', function() {
expect(scope.settingUpPage).to.be.defined;
expect(scope.operatorsAndLabelsByFilterType).to.be.defined;
expect(scope.disableFilters).to.eq(false);
expect(scope.disableNewWorkPackage).to.eq(true);
it('should initialise', () => {
expect(scope.operatorsAndLabelsByFilterType).to.exist;
expect(scope.disableFilters).to.be.false;
expect(scope.disableNewWorkPackage).to.be.true;
expect(scope.query.id).to.eq(testQueries['1'].id);
expect(scope.showFiltersOptions).to.eq(false);
expect(scope.showFiltersOptions).to.be.false;
});
context('second initialisation', function() {
beforeEach(function() {
context('second initialisation', () => {
beforeEach(() => {
scope.toggleShowFilterOptions();
buildController(testParams, testState, testLocation);
});
it('should persist the showFiltersOptions value', function() {
expect(scope.showFiltersOptions).to.eq(true);
it('should persist the showFiltersOptions value', () => {
expect(scope.showFiltersOptions).to.be.true;
});
});
});
describe('initialisation of query by id', function() {
var testParams, testState, testLocation;
describe('initialisation of query by id', () => {
var testParams;
var testState;
var testLocation;
beforeEach(function(){
testParams = { projectPath: '/projects/my-project' };
beforeEach(() => {
testParams = {projectPath: '/projects/my-project'};
testState = {
params: {
query_id: testQueries['2'].id
},
href: function() { return ''; }
href: () => ''
};
testLocation = {
search: function() {
return {};
},
search: () => ({}),
url: angular.identity
};
buildController(testParams, testState, testLocation);
});
it('should initialise', function() {
it('should initialise', () => {
expect(scope.query.id).to.eq(testQueries['2'].id);
});
});
describe('getFilterCount', function() {
beforeEach(function(){
describe('getFilterCount', () => {
beforeEach(() => {
var testState = {
params: {
query_id: testQueries['2'].id
},
href: function() { return ''; }
href: () => ''
};
var testLocation = {
search: function() {
return {};
},
search: () => ({}),
url: angular.identity
};
buildController({projectPath: ''}, testState, testLocation);
});
it('returns 0 with no filters', function() {
it('returns 0 with no filters', () => {
expect(scope.getFilterCount()).to.eq(0);
});
it('returns the filter count with filters', function() {
it('returns the filter count with filters', () => {
scope.query.filters = [{}, {}];
expect(scope.getFilterCount()).to.eq(2);
});
it('returns the filter count with deactivated filters', function() {
scope.query.filters = [{}, { deactivated: true }, { deactivated: true }];
it('returns the filter count with deactivated filters', () => {
scope.query.filters = [{}, {deactivated: true}, {deactivated: true}];
expect(scope.getFilterCount()).to.eq(1);
});
});
describe('setting projectIdentifier', function() {
var testParams, testState, testLocation;
describe('setting projectIdentifier', () => {
var testParams;
var testState;
var testLocation;
beforeEach(function() {
testParams = { projectPath: 'my-project' };
beforeEach(() => {
testParams = {projectPath: 'my-project'};
testState = {
href: function() { return '' },
href: () => '',
params: testParams
};
testLocation = {
search: function() { return {} },
search: () => ({}),
url: angular.identity
};
buildController(testParams, testState, testLocation);
});
it('should set the projectIdentifier', function() {
it('should set the projectIdentifier', () => {
expect(scope.projectIdentifier).to.eq('my-project');
});
});

@ -63,7 +63,8 @@ require('mousetrap');
require('ngFileUpload');
// global
angular.module('openproject.uiComponents', ['ui.select', 'ngSanitize'])
angular.module('openproject.uiComponents',
['ui.select', 'ui.router', 'ngSanitize', 'openproject.workPackages.services'])
.run(['$rootScope', function($rootScope){
$rootScope.I18n = I18n;
}]);

@ -88,29 +88,6 @@ angular.module('openproject.workPackages')
link: 'delete'
}
])
.factory('WorkPackageContextMenu', [
'ngContextMenu',
function(ngContextMenu) {
return ngContextMenu({
controller: 'WorkPackageContextMenuController',
controllerAs: 'contextMenu',
templateUrl: '/templates/work_packages/menus/work_package_context_menu.html'
});
}
])
.controller('WorkPackageContextMenuController', [
'$scope',
'$state',
'WorkPackagesTableHelper',
'WorkPackageContextMenuHelper',
'WorkPackageService',
'WorkPackagesTableService',
'inplaceEditAll',
'I18n',
'$window',
'PERMITTED_CONTEXT_MENU_ACTIONS',
require('./work-package-context-menu-controller')
])
.factory('DetailsMoreDropdownMenu', [
'ngContextMenu',
function(ngContextMenu) {

@ -205,20 +205,23 @@ gulp.task('typescript-tests', function () {
});
gulp.task('tests:karma', ['typescript-tests'], function () {
karma.server.start({
configFile: __dirname + '/karma.conf.js'
}, function (exitCode) {
if(exitCode === 0) {
console.info('No tests have failed');
console.info('Files generated by tsc were deleted.');
deleteFolderRecursive(tsOutDir);
}
else {
console.warn('Tests have failed');
console.info('Files generated by tsc can be found in: ' + tsOutDir);
}
karma.server.start(
{
configFile: __dirname + '/karma.conf.js',
singleRun: true
},
function (exitCode) {
if(exitCode === 0) {
console.info('No tests have failed');
console.info('Files generated by tsc were deleted.');
deleteFolderRecursive(tsOutDir);
}
else {
console.warn('Tests have failed');
console.info('Files generated by tsc can be found in: ' + tsOutDir);
}
process.exit(0);
});
process.exit(exitCode);
}
);
});

@ -24,17 +24,15 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
/* jshint expr: true */
//++
describe('NotificationBoxDirective', function() {
'use strict';
var $compile, $rootScope;
var $compile;
var $rootScope;
beforeEach(module('openproject.uiComponents'));
beforeEach(module('openproject.templates')); // see karmaConfig
beforeEach(angular.mock.module('openproject.uiComponents', 'openproject.templates'));
beforeEach(inject(function(_$compile_, _$rootScope_) {
beforeEach(angular.mock.inject(function(_$compile_, _$rootScope_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
}));
@ -59,5 +57,4 @@ describe('NotificationBoxDirective', function() {
$rootScope.$digest();
expect(element.html()).to.contain('-error');
});
});

Loading…
Cancel
Save