diff --git a/src/app/store/effects/upload.effects.spec.ts b/src/app/store/effects/upload.effects.spec.ts index 8a4992f9e..5b5a3912b 100644 --- a/src/app/store/effects/upload.effects.spec.ts +++ b/src/app/store/effects/upload.effects.spec.ts @@ -34,13 +34,34 @@ import { FileUploadCompleteEvent, FileModel } from '@alfresco/adf-core'; -import { UnlockWriteAction } from '@alfresco/aca-shared/store'; +import { + UnlockWriteAction, + SnackbarErrorAction +} from '@alfresco/aca-shared/store'; +import { ContentManagementService } from '../../services/content-management.service'; +import { of, throwError } from 'rxjs'; + +function createFileList(fileName, type = 'text/plain') { + const data = new Blob([''], { type }); + const arrayOfBlob = new Array(); + arrayOfBlob.push(data); + const file = new File(arrayOfBlob, fileName); + const files = [file]; + + const reducer = (dataTransfer, currentFile) => { + dataTransfer.items.add(currentFile); + return dataTransfer; + }; + return files.reduce(reducer, new DataTransfer()).files; +} describe('UploadEffects', () => { let store: Store; let uploadService: UploadService; let effects: UploadEffects; let zone: NgZone; + let contentManagementService: ContentManagementService; + let uploadVersionInput: HTMLInputElement; beforeEach(() => { TestBed.configureTestingModule({ @@ -52,121 +73,165 @@ describe('UploadEffects', () => { return fn(); }); + contentManagementService = TestBed.get(ContentManagementService); store = TestBed.get(Store); uploadService = TestBed.get(UploadService); effects = TestBed.get(UploadEffects); }); - it('should work', () => { - expect(store).toBeDefined(); - expect(uploadService).toBeDefined(); - expect(effects).toBeDefined(); + beforeEach(() => { + uploadVersionInput = document.querySelector('#app-upload-file-version'); }); - it('should not upload and unlock file if param not provided', () => { - effects.uploadAndUnlock(null); - expect(zone.run).not.toHaveBeenCalled(); + afterEach(() => { + uploadVersionInput.remove(); }); - it('should upload the file before unlocking', () => { - const file: any = {}; + describe('uploadAndUnlock()', () => { + it('should not upload and unlock file if param not provided', () => { + effects.uploadAndUnlock(null); + expect(zone.run).not.toHaveBeenCalled(); + }); - spyOn(uploadService, 'addToQueue').and.stub(); - spyOn(uploadService, 'uploadFilesInTheQueue').and.stub(); + it('should upload the file before unlocking', () => { + const file: any = {}; - effects.uploadAndUnlock(file); + spyOn(uploadService, 'addToQueue').and.stub(); + spyOn(uploadService, 'uploadFilesInTheQueue').and.stub(); - expect(uploadService.addToQueue).toHaveBeenCalled(); - expect(uploadService.uploadFilesInTheQueue).toHaveBeenCalled(); - }); + effects.uploadAndUnlock(file); - it('should dispatch the unlock write action for a locked file', () => { - const file: FileModel = new FileModel( - { name: 'file1.png', size: 10 }, - null, - 'file1' - ); + expect(uploadService.addToQueue).toHaveBeenCalled(); + expect(uploadService.uploadFilesInTheQueue).toHaveBeenCalled(); + }); - file.data = { - entry: { - id: 'file1', - properties: { - 'cm:lockType': 'WRITE_LOCK' + it('should dispatch the unlock write action for a locked file', () => { + const file: FileModel = new FileModel( + { name: 'file1.png', size: 10 }, + null, + 'file1' + ); + + file.data = { + entry: { + id: 'file1', + properties: { + 'cm:lockType': 'WRITE_LOCK' + } } - } - }; + }; - spyOn(uploadService, 'addToQueue').and.stub(); - spyOn(uploadService, 'uploadFilesInTheQueue').and.stub(); - spyOn(store, 'dispatch').and.stub(); + spyOn(uploadService, 'addToQueue').and.stub(); + spyOn(uploadService, 'uploadFilesInTheQueue').and.stub(); + spyOn(store, 'dispatch').and.stub(); - effects.uploadAndUnlock(file); - uploadService.fileUploadComplete.next( - new FileUploadCompleteEvent(file, 100, file.data) - ); + effects.uploadAndUnlock(file); + uploadService.fileUploadComplete.next( + new FileUploadCompleteEvent(file, 100, file.data) + ); - expect(store.dispatch).toHaveBeenCalledWith( - new UnlockWriteAction(file.data) - ); - }); + expect(store.dispatch).toHaveBeenCalledWith( + new UnlockWriteAction(file.data) + ); + }); - it('should dispatch only one unlock action for a locked file', () => { - const file: FileModel = new FileModel( - { name: 'file1.png', size: 10 }, - null, - 'file1' - ); + it('should dispatch only one unlock action for a locked file', () => { + const file: FileModel = new FileModel( + { name: 'file1.png', size: 10 }, + null, + 'file1' + ); - file.data = { - entry: { - id: 'file1', - properties: { - 'cm:lockType': 'WRITE_LOCK' + file.data = { + entry: { + id: 'file1', + properties: { + 'cm:lockType': 'WRITE_LOCK' + } } - } - }; + }; - spyOn(uploadService, 'addToQueue').and.stub(); - spyOn(uploadService, 'uploadFilesInTheQueue').and.stub(); - spyOn(store, 'dispatch').and.stub(); + spyOn(uploadService, 'addToQueue').and.stub(); + spyOn(uploadService, 'uploadFilesInTheQueue').and.stub(); + spyOn(store, 'dispatch').and.stub(); - effects.uploadAndUnlock(file); + effects.uploadAndUnlock(file); - const completeEvent = new FileUploadCompleteEvent(file, 100, file.data); - uploadService.fileUploadComplete.next(completeEvent); - uploadService.fileUploadComplete.next(completeEvent); - uploadService.fileUploadComplete.next(completeEvent); + const completeEvent = new FileUploadCompleteEvent(file, 100, file.data); + uploadService.fileUploadComplete.next(completeEvent); + uploadService.fileUploadComplete.next(completeEvent); + uploadService.fileUploadComplete.next(completeEvent); - expect(store.dispatch).toHaveBeenCalledWith( - new UnlockWriteAction(file.data) - ); + expect(store.dispatch).toHaveBeenCalledWith( + new UnlockWriteAction(file.data) + ); - expect(store.dispatch).toHaveBeenCalledTimes(1); + expect(store.dispatch).toHaveBeenCalledTimes(1); + }); + + it('should dispatch no actions if file is not locked', () => { + const file: FileModel = new FileModel( + { name: 'file1.png', size: 10 }, + null, + 'file1' + ); + + file.data = { + entry: { + id: 'file1', + properties: {} + } + }; + + spyOn(uploadService, 'addToQueue').and.stub(); + spyOn(uploadService, 'uploadFilesInTheQueue').and.stub(); + spyOn(store, 'dispatch').and.stub(); + + effects.uploadAndUnlock(file); + uploadService.fileUploadComplete.next( + new FileUploadCompleteEvent(file, 100, file.data) + ); + + expect(store.dispatch).not.toHaveBeenCalled(); + }); }); - it('should dispatch no actions if file is not locked', () => { - const file: FileModel = new FileModel( - { name: 'file1.png', size: 10 }, - null, - 'file1' - ); + describe('upload file version', () => { + beforeEach(() => { + const dialog = { afterClosed: () => of({}) }; + spyOn(contentManagementService, 'versionUploadDialog').and.returnValue( + dialog + ); + spyOn(effects, 'uploadAndUnlock').and.stub(); + }); - file.data = { - entry: { - id: 'file1', - properties: {} - } - }; + it('should upload file', () => { + spyOn(contentManagementService, 'getNodeInfo').and.returnValue( + of({ + entry: { + id: 'file1', + properties: {} + } + }) + ); - spyOn(uploadService, 'addToQueue').and.stub(); - spyOn(uploadService, 'uploadFilesInTheQueue').and.stub(); - spyOn(store, 'dispatch').and.stub(); + uploadVersionInput.files = createFileList('bogus.txt'); + uploadVersionInput.dispatchEvent(new CustomEvent('change')); + expect(effects.uploadAndUnlock).toHaveBeenCalled(); + }); - effects.uploadAndUnlock(file); - uploadService.fileUploadComplete.next( - new FileUploadCompleteEvent(file, 100, file.data) - ); + it('should raise error when getNodeInfo fails', () => { + spyOn(store, 'dispatch').and.stub(); + spyOn(contentManagementService, 'getNodeInfo').and.returnValue( + throwError('error') + ); - expect(store.dispatch).not.toHaveBeenCalled(); + uploadVersionInput.files = createFileList('bogus.txt'); + uploadVersionInput.dispatchEvent(new CustomEvent('change')); + expect(store.dispatch).toHaveBeenCalledWith( + new SnackbarErrorAction('VERSION.ERROR.GENERIC') + ); + expect(effects.uploadAndUnlock).not.toHaveBeenCalled(); + }); }); }); diff --git a/src/app/store/effects/upload.effects.ts b/src/app/store/effects/upload.effects.ts index e53e8a471..ce9bf61df 100644 --- a/src/app/store/effects/upload.effects.ts +++ b/src/app/store/effects/upload.effects.ts @@ -37,17 +37,8 @@ import { FileModel, FileUtils, UploadService } from '@alfresco/adf-core'; import { Injectable, NgZone, RendererFactory2 } from '@angular/core'; import { Actions, Effect, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; -import { forkJoin, fromEvent, of } from 'rxjs'; -import { - catchError, - distinctUntilChanged, - filter, - flatMap, - map, - switchMap, - take, - tap -} from 'rxjs/operators'; +import { forkJoin, of } from 'rxjs'; +import { tap, filter, catchError, flatMap, map, take } from 'rxjs/operators'; import { ContentManagementService } from '../../services/content-management.service'; @Injectable() @@ -78,7 +69,9 @@ export class UploadEffects { this.fileVersionInput.id = 'app-upload-file-version'; this.fileVersionInput.type = 'file'; this.fileVersionInput.style.display = 'none'; - this.fileVersionInput.addEventListener('change', event => event); + this.fileVersionInput.addEventListener('change', () => + this.uploadVersion() + ); renderer.appendChild(document.body, this.fileVersionInput); this.folderInput = renderer.createElement('input') as HTMLInputElement; @@ -110,19 +103,38 @@ export class UploadEffects { @Effect({ dispatch: false }) uploadVersion$ = this.actions$.pipe( ofType(UploadActionTypes.UploadFileVersion), - switchMap(() => { + map(() => { this.fileVersionInput.click(); - return fromEvent(this.fileVersionInput, 'change').pipe( - distinctUntilChanged(), - flatMap(() => this.contentService.versionUploadDialog().afterClosed()), + }) + ); + + private uploadVersion() { + this.contentService + .versionUploadDialog() + .afterClosed() + .pipe( tap(form => { if (!form) { this.fileVersionInput.value = ''; } }), filter(form => !!form), - flatMap(form => forkJoin(of(form), this.contentService.getNodeInfo())), - map(([form, node]) => { + flatMap(form => + forkJoin( + of(form), + this.contentService.getNodeInfo().pipe( + catchError(_ => { + this.store.dispatch( + new SnackbarErrorAction('VERSION.ERROR.GENERIC') + ); + return of(null); + }) + ) + ) + ) + ) + .subscribe(([form, node]) => { + if (form && node) { const file = this.fileVersionInput.files[0]; const fileModel = new FileModel( file, @@ -139,17 +151,12 @@ export class UploadEffects { }, node.id ); - - this.fileVersionInput.value = ''; this.uploadAndUnlock(fileModel); - }), - catchError(_ => { - this.fileVersionInput.value = ''; - return of(new SnackbarErrorAction('VERSION.ERROR.GENERIC')); - }) - ); - }) - ); + } + + this.fileVersionInput.value = ''; + }); + } private upload(event: any): void { this.store