diff --git a/ng2-components/ng2-alfresco-documentlist/src/assets/alfresco.service.mock.ts b/ng2-components/ng2-alfresco-documentlist/src/assets/alfresco.service.mock.ts index 179c919e81..96419bfdcd 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/assets/alfresco.service.mock.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/assets/alfresco.service.mock.ts @@ -41,4 +41,11 @@ export class AlfrescoServiceMock extends AlfrescoService { observer.complete(); }); } + + deleteNode(nodeId: string) { + return Observable.create(observer => { + observer.next(); + observer.complete(); + }); + } } diff --git a/ng2-components/ng2-alfresco-documentlist/src/assets/document-library.model.mock.ts b/ng2-components/ng2-alfresco-documentlist/src/assets/document-library.model.mock.ts index a167d60b65..37c454366a 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/assets/document-library.model.mock.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/assets/document-library.model.mock.ts @@ -33,6 +33,7 @@ export class FileNode extends MinimalNodeEntity { constructor(name?: string) { super(); this.entry = new MinimalNodeEntryEntity(); + this.entry.id = 'file-id'; this.entry.isFile = true; this.entry.isFolder = false; this.entry.name = name; @@ -45,6 +46,7 @@ export class FolderNode extends MinimalNodeEntity { constructor(name?: string) { super(); this.entry = new MinimalNodeEntryEntity(); + this.entry.id = 'folder-id'; this.entry.isFile = false; this.entry.isFolder = true; this.entry.name = name; diff --git a/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.spec.ts b/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.spec.ts index 5c4d0da547..6a00dd19ae 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.spec.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.spec.ts @@ -21,17 +21,26 @@ import { expect, beforeEach } from '@angular/core/testing'; -import {ContentActionHandler} from '../models/content-action.model'; -import {DocumentActionsService} from './document-actions.service'; -import {AlfrescoServiceMock} from '../assets/alfresco.service.mock'; +import { AlfrescoContentService } from 'ng2-alfresco-core'; +import { ContentActionHandler } from '../models/content-action.model'; +import { DocumentActionsService } from './document-actions.service'; +import { AlfrescoServiceMock } from '../assets/alfresco.service.mock'; +import { AlfrescoService } from './alfresco.service'; +import { + FileNode, + FolderNode +} from '../assets/document-library.model.mock'; describe('DocumentActionsService', () => { let service: DocumentActionsService; + let alfrescoService: AlfrescoService; + let contentService: AlfrescoContentService; beforeEach(() => { - let alfrescoServiceMock = new AlfrescoServiceMock(); - service = new DocumentActionsService(alfrescoServiceMock); + alfrescoService = new AlfrescoServiceMock(); + contentService = new AlfrescoContentService(null, null); + service = new DocumentActionsService(alfrescoService, contentService); }); it('should register default download action', () => { @@ -52,6 +61,142 @@ describe('DocumentActionsService', () => { let handler: ContentActionHandler = function (obj: any) {}; service.setHandler('', handler); expect(service.getHandler('')).toBe(handler); + }); + it('should not find handler with invalid key', () => { + expect(service.getHandler(null)).toBeNull(); + expect(service.getHandler('')).toBeNull(); + }); + + it('should allow action execution only when service available', () => { + let file = new FileNode(); + expect(service.canExecuteAction(file)).toBeTruthy(); + + service = new DocumentActionsService(null); + expect(service.canExecuteAction(file)).toBeFalsy(); + }); + + it('should allow action execution only for file nodes', () => { + expect(service.canExecuteAction(null)).toBeFalsy(); + expect(service.canExecuteAction(new FileNode())).toBeTruthy(); + expect(service.canExecuteAction(new FolderNode())).toBeFalsy(); + }); + + it('should set new handler only by key', () => { + let handler: ContentActionHandler = function (obj: any) {}; + expect(service.setHandler(null, handler)).toBeFalsy(); + expect(service.setHandler('', handler)).toBeFalsy(); + expect(service.setHandler('my-handler', handler)).toBeTruthy(); + }); + + // TODO: to be removed once demo handlers are removed + it('should execute demo actions', () => { + spyOn(window, 'alert').and.stub(); + + service.getHandler('system1')(null); + expect(window.alert).toHaveBeenCalledWith('standard document action 1'); + + service.getHandler('system2')(null); + expect(window.alert).toHaveBeenCalledWith('standard document action 2'); + }); + + // TODO: to be removed once demo handlers are removed + it('should register demo handlers', () => { + expect(service.getHandler('system1')).toBeDefined(); + expect(service.getHandler('system2')).toBeDefined(); + }); + + it('should register delete action', () => { + expect(service.getHandler('delete')).toBeDefined(); + }); + + it('should register download action', () => { + expect(service.getHandler('download')).toBeDefined(); + }); + + it('should execute download action and cleanup', () => { + let file = new FileNode(); + let url = 'http://
'; + + spyOn(contentService, 'getContentUrl').and.returnValue(url); + + let link = jasmine.createSpyObj('a', [ + 'setAttribute', + 'click' + ]); + + spyOn(document, 'createElement').and.returnValue(link); + spyOn(document.body, 'appendChild').and.stub(); + spyOn(document.body, 'removeChild').and.stub(); + + service.getHandler('download')(file); + + expect(contentService.getContentUrl).toHaveBeenCalledWith(file); + expect(document.createElement).toHaveBeenCalledWith('a'); + expect(link.setAttribute).toHaveBeenCalledWith('download', 'download'); + expect(document.body.appendChild).toHaveBeenCalledWith(link); + expect(link.click).toHaveBeenCalled(); + expect(document.body.removeChild).toHaveBeenCalledWith(link); + }); + + it('should require internal service for download action', () => { + let actionService = new DocumentActionsService(null, contentService); + let file = new FileNode(); + let result = actionService.getHandler('download')(file); + expect(result).toBeFalsy(); + }); + + it('should require content service for download action', () => { + let actionService = new DocumentActionsService(alfrescoService, null); + let file = new FileNode(); + let result = actionService.getHandler('download')(file); + expect(result).toBeFalsy(); + }); + + it('should require file node for download action', () => { + let folder = new FolderNode(); + expect(service.getHandler('download')(folder)).toBeFalsy(); + }); + + it('should delete file node', () => { + spyOn(alfrescoService, 'deleteNode').and.callThrough(); + + let file = new FileNode(); + service.getHandler('delete')(file); + + expect(alfrescoService.deleteNode).toHaveBeenCalledWith(file.entry.id); + }); + + it('should support deletion only file node', () => { + spyOn(alfrescoService, 'deleteNode').and.callThrough(); + + let folder = new FolderNode(); + service.getHandler('delete')(folder); + expect(alfrescoService.deleteNode).not.toHaveBeenCalled(); + + let file = new FileNode(); + service.getHandler('delete')(file); + expect(alfrescoService.deleteNode).toHaveBeenCalled(); + }); + + it('should require node id to delete', () => { + spyOn(alfrescoService, 'deleteNode').and.callThrough(); + + let file = new FileNode(); + file.entry.id = null; + service.getHandler('delete')(file); + + expect(alfrescoService.deleteNode).not.toHaveBeenCalled(); + }); + + it('should reload target upon node deletion', () => { + spyOn(alfrescoService, 'deleteNode').and.callThrough(); + + let target = jasmine.createSpyObj('obj', ['reload']); + let file = new FileNode(); + service.getHandler('delete')(file, target); + + expect(alfrescoService.deleteNode).toHaveBeenCalled(); + expect(target.reload).toHaveBeenCalled(); }); }); diff --git a/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.ts b/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.ts index eb30d1bd69..6699dd90dc 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.ts @@ -18,17 +18,15 @@ import {Injectable} from '@angular/core'; import {ContentActionHandler} from '../models/content-action.model'; import {AlfrescoService} from './alfresco.service'; -import { - AlfrescoContentService -} from 'ng2-alfresco-core'; +import { AlfrescoContentService } from 'ng2-alfresco-core'; @Injectable() export class DocumentActionsService { private handlers: { [id: string]: ContentActionHandler; } = {}; constructor( - private _alfrescoService?: AlfrescoService, - private _contentService?: AlfrescoContentService + private alfrescoService?: AlfrescoService, + private contentService?: AlfrescoContentService ) { this.setupActionHandlers(); } @@ -41,15 +39,17 @@ export class DocumentActionsService { return null; } - setHandler(key: string, handler: ContentActionHandler): void { + setHandler(key: string, handler: ContentActionHandler): boolean { if (key) { let lkey = key.toLowerCase(); this.handlers[lkey] = handler; + return true; } + return false; } canExecuteAction(obj: any): boolean { - return this._alfrescoService && obj && obj.entry.isFile === true; + return this.alfrescoService && obj && obj.entry.isFile === true; } private setupActionHandlers() { @@ -71,20 +71,22 @@ export class DocumentActionsService { window.alert('standard document action 2'); } - private download(obj: any) { - if (this.canExecuteAction(obj)) { + private download(obj: any): boolean { + if (this.canExecuteAction(obj) && this.contentService) { let link = document.createElement('a'); document.body.appendChild(link); link.setAttribute('download', 'download'); - link.href = this._contentService.getContentUrl(obj); + link.href = this.contentService.getContentUrl(obj); link.click(); document.body.removeChild(link); + return true; } + return false; } private deleteNode(obj: any, target?: any) { if (this.canExecuteAction(obj) && obj.entry && obj.entry.id) { - this._alfrescoService.deleteNode(obj.entry.id).subscribe(() => { + this.alfrescoService.deleteNode(obj.entry.id).subscribe(() => { if (target && typeof target.reload === 'function') { target.reload(); } diff --git a/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.spec.ts b/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.spec.ts index 51bc36246a..31716f1f46 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.spec.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.spec.ts @@ -23,13 +23,21 @@ import { } from '@angular/core/testing'; import {FolderActionsService} from './folder-actions.service'; import {ContentActionHandler} from '../models/content-action.model'; +import { + FileNode, + FolderNode +} from '../assets/document-library.model.mock'; +import { AlfrescoService } from './alfresco.service'; +import { AlfrescoServiceMock } from '../assets/alfresco.service.mock'; describe('FolderActionsService', () => { let service: FolderActionsService; + let alfrescoService: AlfrescoService; beforeEach(() => { - service = new FolderActionsService(); + alfrescoService = new AlfrescoServiceMock(); + service = new FolderActionsService(alfrescoService); }); it('should register custom action handler', () => { @@ -46,7 +54,96 @@ describe('FolderActionsService', () => { let handler: ContentActionHandler = function (obj: any) {}; service.setHandler('', handler); expect(service.getHandler('')).toBe(handler); + }); + it('should not find handler with invalid key', () => { + expect(service.getHandler(null)).toBeNull(); + expect(service.getHandler('')).toBeNull(); + }); + + it('should allow action execution only when service available', () => { + let folder = new FolderNode(); + expect(service.canExecuteAction(folder)).toBeTruthy(); + + service = new FolderActionsService(null); + expect(service.canExecuteAction(folder)).toBeFalsy(); + }); + + it('should allow action execution only for folder nodes', () => { + expect(service.canExecuteAction(null)).toBeFalsy(); + expect(service.canExecuteAction(new FileNode())).toBeFalsy(); + expect(service.canExecuteAction(new FolderNode())).toBeTruthy(); + }); + + it('should set new handler only by key', () => { + let handler: ContentActionHandler = function (obj: any) {}; + expect(service.setHandler(null, handler)).toBeFalsy(); + expect(service.setHandler('', handler)).toBeFalsy(); + expect(service.setHandler('my-handler', handler)).toBeTruthy(); + }); + + // TODO: to be removed once demo handlers are removed + it('should execute demo actions', () => { + spyOn(window, 'alert').and.stub(); + + service.getHandler('system1')(null); + expect(window.alert).toHaveBeenCalledWith('standard folder action 1'); + + service.getHandler('system2')(null); + expect(window.alert).toHaveBeenCalledWith('standard folder action 2'); + }); + + + // TODO: to be removed once demo handlers are removed + it('should register demo handlers', () => { + expect(service.getHandler('system1')).toBeDefined(); + expect(service.getHandler('system2')).toBeDefined(); + }); + + it('should register delete action', () => { + expect(service.getHandler('delete')).toBeDefined(); + }); + + it('should delete folder node', () => { + spyOn(alfrescoService, 'deleteNode').and.callThrough(); + + let folder = new FolderNode(); + service.getHandler('delete')(folder); + + expect(alfrescoService.deleteNode).toHaveBeenCalledWith(folder.entry.id); + }); + + it('should support deletion only folder node', () => { + spyOn(alfrescoService, 'deleteNode').and.callThrough(); + + let file = new FileNode(); + service.getHandler('delete')(file); + expect(alfrescoService.deleteNode).not.toHaveBeenCalled(); + + let folder = new FolderNode(); + service.getHandler('delete')(folder); + expect(alfrescoService.deleteNode).toHaveBeenCalled(); + }); + + it('should require node id to delete', () => { + spyOn(alfrescoService, 'deleteNode').and.callThrough(); + + let folder = new FolderNode(); + folder.entry.id = null; + service.getHandler('delete')(folder); + + expect(alfrescoService.deleteNode).not.toHaveBeenCalled(); + }); + + it('should reload target upon node deletion', () => { + spyOn(alfrescoService, 'deleteNode').and.callThrough(); + + let target = jasmine.createSpyObj('obj', ['reload']); + let folder = new FolderNode(); + service.getHandler('delete')(folder, target); + + expect(alfrescoService.deleteNode).toHaveBeenCalled(); + expect(target.reload).toHaveBeenCalled(); }); }); diff --git a/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.ts b/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.ts index fccc56109b..a0e6fa7567 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.ts @@ -35,11 +35,13 @@ export class FolderActionsService { return null; } - setHandler(key: string, handler: ContentActionHandler): void { + setHandler(key: string, handler: ContentActionHandler): boolean { if (key) { let lkey = key.toLowerCase(); this.handlers[lkey] = handler; + return true; } + return false; } canExecuteAction(obj: any): boolean {