diff --git a/dashboard/src/app/dashboard/last-workspaces/last-workspaces.controller.spec.ts b/dashboard/src/app/dashboard/last-workspaces/last-workspaces.controller.spec.ts new file mode 100644 index 0000000000..c909594f09 --- /dev/null +++ b/dashboard/src/app/dashboard/last-workspaces/last-workspaces.controller.spec.ts @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +import { DashboardLastWorkspacesController } from "./last-workspaces.controller"; +import { CheWorkspace } from "../../../components/api/workspace/che-workspace.factory"; +import { CheNotification } from "../../../components/notification/che-notification.factory"; + +/** + * @author Lucia Jelinkova + */ +describe(`Last workspaces controller >`, () => { + + let controller: DashboardLastWorkspacesController; + let cheWorkspace: CheWorkspace; + let cheNotification: CheNotification; + + beforeEach(() => { + // tell angular to mock the module + angular.mock.module('userDashboard'); + + // retrieve all necessary services + inject(( + _$controller_: ng.IControllerService, + _cheWorkspace_: CheWorkspace, + _cheNotification_: CheNotification) => { + + // get the tested controller from ng.IControllerService + controller = _$controller_('DashboardLastWorkspacesController'); + cheWorkspace = _cheWorkspace_; + cheNotification = _cheNotification_ + }) + }); + + it('loadData - workspaces pre-loaded', async () => { + spyOn(cheWorkspace, 'getWorkspaces').and.returnValue([jasmine.createSpy('IWorkspace')]); + spyOn(cheWorkspace, 'fetchWorkspaces'); + spyOn(cheNotification, 'showError'); + + expect(controller.isLoading).toBeTruthy(); + + await controller.loadData(); + + expect(controller.isLoading).toBeFalsy(); + expect(cheWorkspace.getWorkspaces).toHaveBeenCalledTimes(1); + expect(cheWorkspace.fetchWorkspaces).not.toHaveBeenCalled(); + expect(cheNotification.showError).not.toHaveBeenCalled(); + expect(controller.workspaces.length).toBe(1); + }); + + it('loadData - fetch workspaces - no workspaces', async () => { + spyOn(cheWorkspace, 'getWorkspaces').and.returnValue([]); + spyOn(cheWorkspace, 'fetchWorkspaces').and.returnValue(Promise.resolve([])); + spyOn(cheNotification, 'showError'); + + expect(controller.isLoading).toBeTruthy(); + + await controller.loadData(); + + expect(controller.isLoading).toBeFalsy(); + expect(cheWorkspace.getWorkspaces).toHaveBeenCalledTimes(1); + expect(cheWorkspace.fetchWorkspaces).toHaveBeenCalledTimes(1); + expect(cheNotification.showError).not.toHaveBeenCalled(); + expect(controller.workspaces.length).toBe(0); + }); + + it('loadData - fetch workspaces', async () => { + spyOn(cheWorkspace, 'getWorkspaces').and.returnValue([]); + spyOn(cheWorkspace, 'fetchWorkspaces').and.returnValue(Promise.resolve([jasmine.createSpy('IWorkspace')])); + spyOn(cheNotification, 'showError'); + + expect(controller.isLoading).toBeTruthy(); + + await controller.loadData(); + + expect(controller.isLoading).toBeFalsy(); + expect(cheWorkspace.getWorkspaces).toHaveBeenCalledTimes(1); + expect(cheWorkspace.fetchWorkspaces).toHaveBeenCalledTimes(1); + expect(cheNotification.showError).not.toHaveBeenCalled(); + expect(controller.workspaces.length).toBe(1); + }); + + it('loadData - general error handling', async () => { + spyOn(cheWorkspace, 'getWorkspaces').and.returnValue([]); + spyOn(cheWorkspace, 'fetchWorkspaces').and.returnValue(createGeneralError()); + spyOn(cheNotification, 'showError').and.callFake((args) => { + expect(args).toBe('Update workspaces failed.'); + }); + + expect(controller.isLoading).toBeTruthy(); + + await controller.loadData(); + + expect(controller.isLoading).toBeFalsy(); + expect(cheWorkspace.getWorkspaces).toHaveBeenCalledTimes(1); + expect(cheWorkspace.fetchWorkspaces).toHaveBeenCalledTimes(1); + expect(cheNotification.showError).toHaveBeenCalledTimes(1); + }); + + it('loadData - http error handling', async () => { + spyOn(cheWorkspace, 'getWorkspaces').and.returnValue([]); + spyOn(cheWorkspace, 'fetchWorkspaces').and.returnValue(createHTTPError('Error message')); + spyOn(cheNotification, 'showError').and.callFake((args) => { + expect(args).toBe('Error message'); + }); + expect(controller.isLoading).toBeTruthy(); + + await controller.loadData(); + + expect(controller.isLoading).toBeFalsy(); + expect(cheWorkspace.getWorkspaces).toHaveBeenCalledTimes(1); + expect(cheWorkspace.fetchWorkspaces).toHaveBeenCalledTimes(1); + expect(cheNotification.showError).toHaveBeenCalledTimes(1); + }); + + function createGeneralError(): Promise { + return Promise.reject("This is some error"); + } + + function createHTTPError(message: string): Promise { + var error = { + 'status': status, + 'data': { + 'message': message + } + } + return Promise.reject(error); + } +}); + diff --git a/dashboard/src/app/dashboard/last-workspaces/last-workspaces.controller.ts b/dashboard/src/app/dashboard/last-workspaces/last-workspaces.controller.ts index 204c5afe45..048a2bd96d 100644 --- a/dashboard/src/app/dashboard/last-workspaces/last-workspaces.controller.ts +++ b/dashboard/src/app/dashboard/last-workspaces/last-workspaces.controller.ts @@ -25,8 +25,8 @@ export class DashboardLastWorkspacesController { cheWorkspace: CheWorkspace; cheNotification: CheNotification; - workspaces: Array; - isLoading: boolean; + workspaces: Array = []; + isLoading: boolean = true; /** * Default constructor @@ -35,28 +35,28 @@ export class DashboardLastWorkspacesController { this.cheWorkspace = cheWorkspace; this.cheNotification = cheNotification; - this.workspaces = cheWorkspace.getWorkspaces(); - - if (this.workspaces.length === 0) { - this.updateData(); - } + this.loadData(); } /** - * Update workspaces + * Load workspaces */ - updateData(): void { - this.isLoading = true; + loadData(): void { + this.workspaces = this.cheWorkspace.getWorkspaces(); + + if (this.workspaces.length > 0) { + this.isLoading = false; + return; + } + let promise = this.cheWorkspace.fetchWorkspaces(); - promise.then(() => { + promise.then((result) => { + this.workspaces = result; this.isLoading = false; }, (error: any) => { this.isLoading = false; - if (error.status === 304) { - return; - } - this.cheNotification.showError(error.data.message !== null ? error.data.message : 'Update workspaces failed.'); + this.cheNotification.showError(error.data && error.data.message ? error.data.message : 'Update workspaces failed.'); }); } diff --git a/dashboard/src/app/dashboard/last-workspaces/last-workspaces.directive.spec.ts b/dashboard/src/app/dashboard/last-workspaces/last-workspaces.directive.spec.ts new file mode 100644 index 0000000000..1823b8495f --- /dev/null +++ b/dashboard/src/app/dashboard/last-workspaces/last-workspaces.directive.spec.ts @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2015-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +import { IAugmentedJQuery, ITemplateCacheService, ICompileService, IRootScopeService, ICompileProvider } from "angular"; +import { CheHttpBackend } from "../../../components/api/test/che-http-backend"; + +/** + * @author Lucia Jelinkova + */ +describe(`Last workspaces directive >`, () => { + + let $compile: ICompileService; + let $scope: any; + let directiveElement: IAugmentedJQuery; + + beforeAll(() => { + // this call replaces the inner directive with mocked value. + // the reason is that we want to test only itself and not + // underlying directives. Those should be tested separately. + // NOTE: it is possible that if another test mocks the same directive, it will fail. In that + // case the whole call needs to be extracted and executed before all .spec files. + angular.module('userDashboard').config(function ($compileProvider: ICompileProvider) { + $compileProvider.directive('cheWorkspaceItem', function () { + var def = { + // directive with the highest priority is executed first + priority: 100, + // if set to false also directives with lower priorities would be executed + terminal: true, + // the same as original directive + restrict: 'E', + // mocked output + template: '
Mocked workspace
', + }; + return def; + }); + }); + }); + + beforeEach(() => { + angular.mock.module('userDashboard'); + + inject(( + _$compile_: ng.ICompileService, + _$rootScope_: IRootScopeService, + _cheHttpBackend_: CheHttpBackend) => { + + $compile = _$compile_; + $scope = _$rootScope_.$new(); + + let $httpBackend = _cheHttpBackend_.getHttpBackend(); + $httpBackend.whenGET(/.*/).respond(200, ''); + $httpBackend.when('OPTIONS', '/api/').respond({}); + }) + }); + + beforeEach(() => { + directiveElement = $compile(" ")($scope); + $scope.$digest(); + }); + + it('no workspaces', async () => { + noWorkspacesDirectiveTest(); + }); + + it('one workspace', async () => { + moreWorkspacesDirectiveTest(1); + }); + + it('5 workspaces', async () => { + moreWorkspacesDirectiveTest(5); + }); + + it('6 workspaces', async () => { + moreWorkspacesDirectiveTest(6, 5); + }); + + it('progress bar - loading', async () => { + $scope.dashboardLastWorkspacesController.isLoading = true; + $scope.$digest(); + + let progressBar = directiveElement.find('md-progress-linear'); + let mainDiv = directiveElement.find('#last-workspaces'); + + expect(progressBar.length).toBe(1); + expect(progressBar.attr('class')).not.toContain('ng-hide'); + expect(mainDiv.length).toBe(1); + expect(mainDiv.attr('class')).toContain('ng-hide'); + }); + + it('progress bar - not loading', async () => { + $scope.dashboardLastWorkspacesController.isLoading = false; + $scope.$digest(); + + let progressBar = directiveElement.find('md-progress-linear'); + let mainDiv = directiveElement.find('#last-workspaces'); + + expect(progressBar.length).toBe(1); + expect(progressBar.attr('class')).toContain('ng-hide'); + expect(mainDiv.length).toBe(1); + expect(mainDiv.attr('class')).not.toContain('ng-hide'); + }); + + function noWorkspacesDirectiveTest() { + $scope.dashboardLastWorkspacesController.workspaces = []; + $scope.$digest(); + + let emptyLabel = directiveElement.find('.last-workspaces-empty-label'); + let workspaceList = directiveElement.find('#last-workspaces-list'); + let workspaceItems = directiveElement.find('.workspace-mock'); + + expect(emptyLabel.length).toBe(1); + expect(emptyLabel.attr('class')).not.toContain('ng-hide'); + expect(workspaceList.length).toBe(1); + expect(workspaceList.attr('class')).toContain('ng-hide'); + expect(workspaceItems.length).toBe(0); + } + + function moreWorkspacesDirectiveTest(workspacesCount: number, workspacesDisplayedCount: number = workspacesCount) { + $scope.dashboardLastWorkspacesController.workspaces = + Array.from(new Array(workspacesCount)).map((x, i) => {return {} }); + $scope.$digest(); + + let emptyLabel = directiveElement.find('.last-workspaces-empty-label'); + let workspaceList = directiveElement.find('#last-workspaces-list'); + let workspaceItems = directiveElement.find('.workspace-mock'); + + expect(emptyLabel.length).toBe(1); + expect(emptyLabel.attr('class')).toContain('ng-hide'); + expect(workspaceList.length).toBe(1); + expect(workspaceList.attr('class')).not.toContain('ng-hide'); + expect(workspaceItems.length).toBe(workspacesDisplayedCount); + } +}); + diff --git a/dashboard/src/app/dashboard/last-workspaces/last-workspaces.html b/dashboard/src/app/dashboard/last-workspaces/last-workspaces.html index d91ea260c3..3edc84760f 100644 --- a/dashboard/src/app/dashboard/last-workspaces/last-workspaces.html +++ b/dashboard/src/app/dashboard/last-workspaces/last-workspaces.html @@ -1,14 +1,14 @@ -
+
No workspaces found - +