mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-09-17 14:21:14 +00:00
1164 lines
49 KiB
TypeScript
1164 lines
49 KiB
TypeScript
import { TestBed, async } from '@angular/core/testing';
|
|
import { MatDialog } from '@angular/material';
|
|
import { OverlayModule } from '@angular/cdk/overlay';
|
|
import { Observable } from 'rxjs/Rx';
|
|
import { CoreModule, AlfrescoApiService, NodesApiService } from 'ng2-alfresco-core';
|
|
import { DocumentListService, NodeMinimal, NodeMinimalEntry } from 'ng2-alfresco-documentlist';
|
|
import { NodeActionsService } from './node-actions.service';
|
|
|
|
class TestNode extends NodeMinimalEntry {
|
|
constructor(id?: string, isFile?: boolean, name?: string, permission?: string[]) {
|
|
super();
|
|
this.entry = new NodeMinimal();
|
|
this.entry.id = id || 'node-id';
|
|
this.entry.isFile = isFile;
|
|
this.entry.isFolder = !isFile;
|
|
this.entry.nodeType = isFile ? 'content' : 'folder';
|
|
this.entry.name = name;
|
|
if (permission) {
|
|
this.entry['allowableOperations'] = permission;
|
|
}
|
|
}
|
|
}
|
|
|
|
describe('NodeActionsService', () => {
|
|
const actionIsForbidden = true;
|
|
const isFile = true;
|
|
const folderDestinationId = 'folder-destination-id';
|
|
const fileId = 'file-to-be-copied-id';
|
|
const conflictError = new Error(JSON.stringify({error: {statusCode: 409}}));
|
|
const permissionError = new Error(JSON.stringify({error: {statusCode: 403}}));
|
|
const badRequestError = new Error(JSON.stringify({error: {statusCode: 400}}));
|
|
const emptyChildrenList = {list: {entries: []}};
|
|
let service: NodeActionsService;
|
|
let apiService: AlfrescoApiService;
|
|
let nodesApiService: NodesApiService;
|
|
let nodesApi;
|
|
const spyOnSuccess = jasmine.createSpy('spyOnSuccess');
|
|
const spyOnError = jasmine.createSpy('spyOnError');
|
|
|
|
const helper = {
|
|
fakeCopyNode: (isForbidden: boolean = false, nameExistingOnDestination?: string) => {
|
|
return (entryId, options) => {
|
|
return new Promise((resolve, reject) => {
|
|
|
|
if (isForbidden) {
|
|
reject(permissionError);
|
|
|
|
} else if (nameExistingOnDestination && options && options.name === nameExistingOnDestination) {
|
|
|
|
reject(conflictError);
|
|
|
|
} else {
|
|
resolve();
|
|
}
|
|
});
|
|
};
|
|
},
|
|
fakeGetNodeChildren: (familyNodes: { parentNodeId: string, nodeChildren: any[] }[], isForbidden: boolean = false) => {
|
|
return (parentId, options) => {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
if (isForbidden) {
|
|
reject(permissionError);
|
|
|
|
} else {
|
|
const node = familyNodes.filter(familyNode => familyNode.parentNodeId === parentId);
|
|
resolve({list: {entries: node[0].nodeChildren}} || emptyChildrenList);
|
|
}
|
|
});
|
|
|
|
};
|
|
}
|
|
};
|
|
|
|
beforeEach(() => {
|
|
TestBed.configureTestingModule({
|
|
imports: [
|
|
CoreModule,
|
|
OverlayModule
|
|
],
|
|
providers: [
|
|
MatDialog,
|
|
DocumentListService,
|
|
AlfrescoApiService,
|
|
NodesApiService,
|
|
NodeActionsService]
|
|
});
|
|
|
|
service = TestBed.get(NodeActionsService);
|
|
apiService = TestBed.get(AlfrescoApiService);
|
|
nodesApiService = TestBed.get(NodesApiService);
|
|
nodesApi = apiService.getInstance().nodes;
|
|
});
|
|
|
|
describe('doBatchOperation', () => {
|
|
beforeEach(() => {
|
|
spyOnSuccess.calls.reset();
|
|
spyOnError.calls.reset();
|
|
});
|
|
|
|
it('should throw error if \'contentEntities\' required parameter is missing', async(() => {
|
|
const contentEntities = undefined;
|
|
const doCopyBatchOperation = service.copyNodes(contentEntities).asObservable();
|
|
|
|
doCopyBatchOperation.toPromise().then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
(error) => {
|
|
spyOnError(error);
|
|
})
|
|
.then(() => {
|
|
expect(spyOnSuccess).not.toHaveBeenCalled();
|
|
expect(spyOnError).toHaveBeenCalled();
|
|
}
|
|
);
|
|
}));
|
|
|
|
it('should throw error if \'contentEntities\' is not an array of entry entities', async(() => {
|
|
const contentEntities = [ new TestNode(), {} ];
|
|
const doCopyBatchOperation = service.copyNodes(contentEntities).asObservable();
|
|
|
|
doCopyBatchOperation.toPromise().then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
(error) => {
|
|
spyOnError(error);
|
|
})
|
|
.then(() => {
|
|
expect(spyOnSuccess).not.toHaveBeenCalled();
|
|
expect(spyOnError).toHaveBeenCalledWith(badRequestError);
|
|
}
|
|
);
|
|
}));
|
|
|
|
it('should throw error if an entry in \'contentEntities\' does not have id nor nodeId property', async(() => {
|
|
const contentEntities = [ new TestNode(), {entry: {}} ];
|
|
const doCopyBatchOperation = service.copyNodes(contentEntities).asObservable();
|
|
|
|
doCopyBatchOperation.toPromise().then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
(error) => {
|
|
spyOnError(error);
|
|
})
|
|
.then(() => {
|
|
expect(spyOnSuccess).not.toHaveBeenCalled();
|
|
expect(spyOnError).toHaveBeenCalledWith(badRequestError);
|
|
}
|
|
);
|
|
}));
|
|
|
|
it('should not throw error if entry in \'contentEntities\' does not have id, but has nodeId property', async(() => {
|
|
const contentEntities = [ new TestNode(), {entry: {nodeId: '1234'}} ];
|
|
|
|
spyOn(service, 'getContentNodeSelection').and.returnValue(Observable.of([new TestNode().entry]));
|
|
spyOn(service, 'copyNodeAction').and.returnValue(Observable.of({}));
|
|
|
|
const doCopyBatchOperation = service.copyNodes(contentEntities).asObservable();
|
|
|
|
doCopyBatchOperation.toPromise().then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
(error) => {
|
|
spyOnError(error);
|
|
})
|
|
.then(() => {
|
|
expect(spyOnSuccess).toHaveBeenCalled();
|
|
expect(spyOnError).not.toHaveBeenCalledWith(badRequestError);
|
|
}
|
|
);
|
|
|
|
}));
|
|
});
|
|
|
|
describe('getFirstParentId', () => {
|
|
it('should give the parentId, if that exists on the node entry', () => {
|
|
const parentID = 'parent-id';
|
|
const contentEntities = [ {entry: {nodeId: '1234', parentId: parentID}} ];
|
|
|
|
expect(service.getFirstParentId(contentEntities)).toBe(parentID);
|
|
});
|
|
|
|
it('should give the last element in path property, if parentId is missing and path exists on the node entry', () => {
|
|
const firstParentId = 'parent-0-id';
|
|
const contentEntities = [ {entry: {nodeId: '1234', path: {elements: [ {id: 'parent-1-id'}, { id: firstParentId} ]} }} ];
|
|
|
|
expect(service.getFirstParentId(contentEntities)).toBe(firstParentId);
|
|
});
|
|
|
|
it('should give the id of the first node entry, if none of nodes has either parentId, or path properties', () => {
|
|
const nodeID = '1234';
|
|
const contentEntities = [ {entry: {id: nodeID}}, {entry: {id: `${nodeID}-2`}} ];
|
|
|
|
expect(service.getFirstParentId(contentEntities)).toBe(nodeID);
|
|
});
|
|
|
|
it('should give the nodeId of the first node entry, if none of nodes has either parentId, or path properties', () => {
|
|
const nodeID = '1234';
|
|
const contentEntities = [ {entry: {nodeId: nodeID}}, {entry: {id: `${nodeID}-2`}} ];
|
|
|
|
expect(service.getFirstParentId(contentEntities)).toBe(nodeID);
|
|
});
|
|
});
|
|
|
|
describe('getEntryParentId', () => {
|
|
it('should return the parentId, if that exists on the node entry', () => {
|
|
const parentID = 'parent-id';
|
|
const entry = {nodeId: '1234', parentId: parentID};
|
|
|
|
expect(service.getEntryParentId(entry)).toBe(parentID);
|
|
});
|
|
|
|
it('should give the last element in path property, if parentId is missing and path exists on the node entry', () => {
|
|
const firstParentId = 'parent-0-id';
|
|
const entry = {nodeId: '1234', path: {elements: [ {id: 'parent-1-id'}, { id: firstParentId} ]} };
|
|
|
|
expect(service.getEntryParentId(entry)).toBe(firstParentId);
|
|
});
|
|
});
|
|
|
|
describe('copyNodes', () => {
|
|
let fileToCopy;
|
|
let folderToCopy;
|
|
let destinationFolder;
|
|
|
|
beforeEach(() => {
|
|
fileToCopy = new TestNode(fileId, isFile, 'file-name');
|
|
folderToCopy = new TestNode();
|
|
destinationFolder = new TestNode(folderDestinationId);
|
|
|
|
});
|
|
|
|
it('should be called', () => {
|
|
const spyOnBatchOperation = spyOn(service, 'doBatchOperation').and.callThrough();
|
|
spyOn(service, 'getContentNodeSelection').and.returnValue(Observable.of([destinationFolder.entry]));
|
|
spyOn(service, 'copyNodeAction').and.returnValue(Observable.of({}));
|
|
|
|
service.copyNodes([fileToCopy, folderToCopy]);
|
|
expect(spyOnBatchOperation.calls.count()).toEqual(1);
|
|
expect(spyOnBatchOperation).toHaveBeenCalledWith('copy', [fileToCopy, folderToCopy], undefined);
|
|
});
|
|
|
|
it('should use the custom data object with custom rowFilter & imageResolver & title with destination picker', () => {
|
|
const spyOnBatchOperation = spyOn(service, 'doBatchOperation').and.callThrough();
|
|
const spyOnDestinationPicker = spyOn(service, 'getContentNodeSelection').and.callThrough();
|
|
spyOn(service, 'getFirstParentId').and.returnValue('parent-id');
|
|
|
|
let testContentNodeSelectorComponentData;
|
|
const dialog = TestBed.get(MatDialog);
|
|
const spyOnDialog = spyOn(dialog, 'open').and.callFake((contentNodeSelectorComponent: any, data: any) => {
|
|
testContentNodeSelectorComponentData = data;
|
|
return {};
|
|
});
|
|
|
|
service.copyNodes([fileToCopy, folderToCopy]);
|
|
|
|
expect(spyOnBatchOperation).toHaveBeenCalledWith('copy', [fileToCopy, folderToCopy], undefined);
|
|
expect(spyOnDestinationPicker.calls.count()).toEqual(1);
|
|
expect(spyOnDialog.calls.count()).toEqual(1);
|
|
|
|
expect(testContentNodeSelectorComponentData).toBeDefined();
|
|
expect(testContentNodeSelectorComponentData.data.rowFilter({node: destinationFolder})).toBeDefined();
|
|
expect(testContentNodeSelectorComponentData.data.imageResolver({node: destinationFolder})).toBeDefined();
|
|
expect(testContentNodeSelectorComponentData.data.title).toBe('copy to ...');
|
|
|
|
destinationFolder.entry['allowableOperations'] = ['update'];
|
|
expect(testContentNodeSelectorComponentData.data.imageResolver({node: destinationFolder})).toBeDefined();
|
|
});
|
|
|
|
it('should use the ContentNodeSelectorComponentData object with file name in title', () => {
|
|
const spyOnBatchOperation = spyOn(service, 'doBatchOperation').and.callThrough();
|
|
spyOn(service, 'getContentNodeSelection').and.callThrough();
|
|
spyOn(service, 'getFirstParentId').and.returnValue('parent-id');
|
|
|
|
let testContentNodeSelectorComponentData;
|
|
const dialog = TestBed.get(MatDialog);
|
|
spyOn(dialog, 'open').and.callFake((contentNodeSelectorComponent: any, data: any) => {
|
|
testContentNodeSelectorComponentData = data;
|
|
return {};
|
|
});
|
|
|
|
service.copyNodes([{entry: {id: 'entry-id', name: 'entry-name'}}]);
|
|
|
|
expect(spyOnBatchOperation).toHaveBeenCalled();
|
|
expect(testContentNodeSelectorComponentData).toBeDefined();
|
|
expect(testContentNodeSelectorComponentData.data.title).toBe('copy entry-name to ...');
|
|
});
|
|
|
|
it('should use the ContentNodeSelectorComponentData object without file name in title, if no name exists', () => {
|
|
const spyOnBatchOperation = spyOn(service, 'doBatchOperation').and.callThrough();
|
|
spyOn(service, 'getContentNodeSelection').and.callThrough();
|
|
spyOn(service, 'getFirstParentId').and.returnValue('parent-id');
|
|
|
|
let testContentNodeSelectorComponentData;
|
|
const dialog = TestBed.get(MatDialog);
|
|
spyOn(dialog, 'open').and.callFake((contentNodeSelectorComponent: any, data: any) => {
|
|
testContentNodeSelectorComponentData = data;
|
|
return {};
|
|
});
|
|
|
|
service.copyNodes([{entry: {id: 'entry-id'}}]);
|
|
|
|
expect(spyOnBatchOperation).toHaveBeenCalled();
|
|
expect(testContentNodeSelectorComponentData).toBeDefined();
|
|
expect(testContentNodeSelectorComponentData.data.title).toBe('copy to ...');
|
|
});
|
|
|
|
});
|
|
|
|
describe('copyNodeAction', () => {
|
|
|
|
it('should copy one folder node to destination', () => {
|
|
spyOn(nodesApi, 'copyNode').and.callFake(helper.fakeCopyNode());
|
|
|
|
const folderToCopy = new TestNode();
|
|
const folderDestination = new TestNode(folderDestinationId);
|
|
service.copyNodeAction(folderToCopy.entry, folderDestination.entry.id);
|
|
|
|
expect(nodesApi.copyNode).toHaveBeenCalledWith(
|
|
folderToCopy.entry.id,
|
|
{ targetParentId: folderDestination.entry.id, name: undefined }
|
|
);
|
|
});
|
|
|
|
it('should copy one file node to destination', () => {
|
|
spyOn(nodesApi, 'copyNode').and.callFake(helper.fakeCopyNode());
|
|
|
|
const fileToCopy = new TestNode(fileId, isFile, 'file-name');
|
|
const folderDestination = new TestNode(folderDestinationId);
|
|
service.copyNodeAction(fileToCopy.entry, folderDestination.entry.id);
|
|
|
|
expect(nodesApi.copyNode).toHaveBeenCalledWith(
|
|
fileToCopy.entry.id,
|
|
{ targetParentId: folderDestination.entry.id, name: 'file-name' }
|
|
);
|
|
});
|
|
|
|
it('should fail to copy folder node if action is forbidden', async(() => {
|
|
spyOn(nodesApi, 'copyNode').and.callFake(helper.fakeCopyNode(actionIsForbidden));
|
|
|
|
const folderToCopy = new TestNode();
|
|
const folderDestination = new TestNode(folderDestinationId);
|
|
|
|
const spyContentAction = spyOn(service, 'copyContentAction').and.callThrough();
|
|
const spyFolderAction = spyOn(service, 'copyFolderAction').and.callThrough();
|
|
const copyObservable = service.copyNodeAction(folderToCopy.entry, folderDestination.entry.id);
|
|
|
|
spyOnSuccess.calls.reset();
|
|
spyOnError.calls.reset();
|
|
copyObservable.toPromise().then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
() => {
|
|
spyOnError();
|
|
|
|
expect(spyContentAction.calls.count()).toEqual(0);
|
|
expect(spyFolderAction.calls.count()).toEqual(1);
|
|
expect(nodesApi.copyNode).toHaveBeenCalledWith(
|
|
folderToCopy.entry.id,
|
|
{ targetParentId: folderDestination.entry.id, name: undefined }
|
|
);
|
|
}).then(() => {
|
|
expect(spyOnSuccess.calls.count()).toEqual(0);
|
|
expect(spyOnError.calls.count()).toEqual(1);
|
|
});
|
|
}));
|
|
|
|
it('should fail to copy file node if action is forbidden', async(() => {
|
|
spyOn(nodesApi, 'copyNode').and.callFake(helper.fakeCopyNode(actionIsForbidden));
|
|
|
|
const spyContentAction = spyOn(service, 'copyContentAction').and.callThrough();
|
|
const spyFolderAction = spyOn(service, 'copyFolderAction').and.callThrough();
|
|
|
|
const fileToCopy = new TestNode(fileId, isFile, 'test-name');
|
|
const folderDestination = new TestNode(folderDestinationId);
|
|
const copyObservable = service.copyNodeAction(fileToCopy.entry, folderDestination.entry.id);
|
|
|
|
spyOnSuccess.calls.reset();
|
|
spyOnError.calls.reset();
|
|
copyObservable.toPromise()
|
|
.then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
() => {
|
|
spyOnError();
|
|
})
|
|
.then(
|
|
() => {
|
|
expect(spyOnSuccess).not.toHaveBeenCalled();
|
|
expect(spyOnError).toHaveBeenCalled();
|
|
|
|
expect(spyContentAction).toHaveBeenCalled();
|
|
expect(spyFolderAction).not.toHaveBeenCalled();
|
|
expect(nodesApi.copyNode).toHaveBeenCalledWith(
|
|
fileToCopy.entry.id,
|
|
{targetParentId: folderDestination.entry.id, name: 'test-name'}
|
|
);
|
|
});
|
|
}));
|
|
|
|
it('should copy one file node to same destination and autoRename it', async(() => {
|
|
const alreadyExistingName = 'file-name';
|
|
spyOn(nodesApi, 'copyNode').and.callFake(helper.fakeCopyNode(!actionIsForbidden, alreadyExistingName));
|
|
|
|
const spyContentAction = spyOn(service, 'copyContentAction').and.callThrough();
|
|
|
|
const fileToCopy = new TestNode(fileId, isFile, 'file-name');
|
|
const folderDestination = new TestNode(folderDestinationId);
|
|
const copyObservable = service.copyNodeAction(fileToCopy.entry, folderDestination.entry.id);
|
|
|
|
spyOnSuccess.calls.reset();
|
|
spyOnError.calls.reset();
|
|
copyObservable.toPromise()
|
|
.then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
() => {
|
|
spyOnError();
|
|
|
|
})
|
|
.then(() => {
|
|
expect(spyOnSuccess).toHaveBeenCalled();
|
|
expect(spyOnError).not.toHaveBeenCalled();
|
|
|
|
expect(spyContentAction.calls.count()).toEqual(2);
|
|
expect(nodesApi.copyNode).toHaveBeenCalledWith(
|
|
fileToCopy.entry.id,
|
|
{targetParentId: folderDestination.entry.id, name: 'file-name-1'}
|
|
);
|
|
});
|
|
}));
|
|
|
|
describe('should copy content of folder-to-copy to folder with same name from destination folder', () => {
|
|
let folderToCopy;
|
|
let fileChildOfFolderToCopy;
|
|
let folderParentAndDestination;
|
|
let existingFolder;
|
|
let spy;
|
|
let spyOnContentAction;
|
|
let spyOnFolderAction;
|
|
let copyObservable;
|
|
|
|
beforeEach(() => {
|
|
folderToCopy = new TestNode('folder-to-copy-id', !isFile, 'conflicting-name');
|
|
fileChildOfFolderToCopy = new TestNode(fileId, isFile, 'file-name');
|
|
|
|
folderParentAndDestination = new TestNode(folderDestinationId);
|
|
existingFolder = new TestNode('existing-folder-id', !isFile, 'conflicting-name');
|
|
|
|
spy = spyOn(nodesApi, 'copyNode').and.callFake(helper.fakeCopyNode(!actionIsForbidden, 'conflicting-name'));
|
|
|
|
spyOnContentAction = spyOn(service, 'copyContentAction').and.callThrough();
|
|
spyOnFolderAction = spyOn(service, 'copyFolderAction').and.callThrough();
|
|
|
|
copyObservable = service.copyNodeAction(folderToCopy.entry, folderParentAndDestination.entry.id);
|
|
spyOnSuccess.calls.reset();
|
|
spyOnError.calls.reset();
|
|
});
|
|
|
|
it('when folder to copy has a file as content', async(() => {
|
|
const testFamilyNodes = [
|
|
{
|
|
parentNodeId: folderToCopy.entry.id,
|
|
nodeChildren: [fileChildOfFolderToCopy]
|
|
}, {
|
|
parentNodeId: folderParentAndDestination.entry.id,
|
|
nodeChildren: [existingFolder]
|
|
}
|
|
];
|
|
spyOn(nodesApi, 'getNodeChildren').and.callFake(helper.fakeGetNodeChildren(testFamilyNodes));
|
|
spyOn(service, 'getChildByName').and.returnValue(Observable.of(existingFolder));
|
|
|
|
copyObservable.toPromise()
|
|
.then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
() => {
|
|
spyOnError();
|
|
})
|
|
.then(
|
|
() => {
|
|
expect(spyOnSuccess).toHaveBeenCalled();
|
|
expect(spyOnError).not.toHaveBeenCalled();
|
|
|
|
expect(spyOnContentAction).toHaveBeenCalled();
|
|
expect(spyOnFolderAction).toHaveBeenCalled();
|
|
expect(spy.calls.allArgs()).toEqual([
|
|
[folderToCopy.entry.id, {
|
|
targetParentId: folderParentAndDestination.entry.id,
|
|
name: 'conflicting-name'
|
|
}],
|
|
[fileChildOfFolderToCopy.entry.id, {
|
|
targetParentId: existingFolder.entry.id,
|
|
name: 'file-name'
|
|
}]
|
|
]);
|
|
});
|
|
}));
|
|
|
|
it('when folder to copy is empty', async(() => {
|
|
const testFamilyNodes = [
|
|
{
|
|
parentNodeId: folderToCopy.entry.id,
|
|
nodeChildren: []
|
|
}, {
|
|
parentNodeId: folderParentAndDestination.entry.id,
|
|
nodeChildren: [existingFolder]
|
|
}
|
|
];
|
|
spyOn(nodesApi, 'getNodeChildren').and.callFake(helper.fakeGetNodeChildren(testFamilyNodes));
|
|
spyOn(service, 'getChildByName').and.returnValue(Observable.of(existingFolder));
|
|
|
|
copyObservable.toPromise()
|
|
.then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
() => {
|
|
spyOnError();
|
|
|
|
})
|
|
.then(
|
|
() => {
|
|
expect(spyOnSuccess).toHaveBeenCalled();
|
|
expect(spyOnError).not.toHaveBeenCalled();
|
|
|
|
expect(spyOnContentAction).not.toHaveBeenCalled();
|
|
expect(spyOnFolderAction).toHaveBeenCalled();
|
|
expect(spy.calls.allArgs()).toEqual([
|
|
[folderToCopy.entry.id, {
|
|
targetParentId: folderParentAndDestination.entry.id,
|
|
name: 'conflicting-name'
|
|
}]
|
|
]);
|
|
});
|
|
}));
|
|
|
|
it('when folder to copy has another folder as child', async(() => {
|
|
const folderChild = new TestNode('folder-child-id');
|
|
const testFamilyNodes = [
|
|
{
|
|
parentNodeId: folderToCopy.entry.id,
|
|
nodeChildren: [folderChild]
|
|
}, {
|
|
parentNodeId: folderParentAndDestination.entry.id,
|
|
nodeChildren: [existingFolder]
|
|
}
|
|
];
|
|
spyOn(nodesApi, 'getNodeChildren').and.callFake(helper.fakeGetNodeChildren(testFamilyNodes));
|
|
spyOn(service, 'getChildByName').and.returnValue(Observable.of(existingFolder));
|
|
|
|
copyObservable.toPromise()
|
|
.then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
() => {
|
|
spyOnError();
|
|
})
|
|
.then(
|
|
() => {
|
|
expect(spyOnSuccess).toHaveBeenCalled();
|
|
expect(spyOnError).not.toHaveBeenCalled();
|
|
|
|
expect(spyOnContentAction).not.toHaveBeenCalled();
|
|
expect(spyOnFolderAction.calls.count()).toEqual(2);
|
|
expect(spy.calls.allArgs()).toEqual([
|
|
[folderToCopy.entry.id, {
|
|
targetParentId: folderParentAndDestination.entry.id,
|
|
name: 'conflicting-name'
|
|
}],
|
|
[folderChild.entry.id, {
|
|
targetParentId: existingFolder.entry.id,
|
|
name: undefined
|
|
}]
|
|
]);
|
|
}
|
|
);
|
|
}));
|
|
});
|
|
|
|
});
|
|
|
|
describe('moveNodes', () => {
|
|
const permissionToMove = 'delete';
|
|
let fileToMove;
|
|
let folderToMove;
|
|
let destinationFolder;
|
|
let spyOnBatchOperation;
|
|
let spyOnDocumentListServiceAction;
|
|
let documentListService;
|
|
|
|
beforeEach(() => {
|
|
fileToMove = new TestNode('file-to-be-moved', isFile, 'file-name');
|
|
folderToMove = new TestNode('fid', !isFile, 'folder-name');
|
|
destinationFolder = new TestNode(folderDestinationId);
|
|
|
|
documentListService = TestBed.get(DocumentListService);
|
|
spyOnBatchOperation = spyOn(service, 'doBatchOperation').and.callThrough();
|
|
});
|
|
|
|
it('should allow to select destination for nodes that have permission to be moved', () => {
|
|
const spyOnDestinationPicker =
|
|
spyOn(service, 'getContentNodeSelection')
|
|
.and.returnValue(Observable.of([destinationFolder.entry]));
|
|
spyOn(service, 'moveContentAction').and.returnValue(Observable.of({}));
|
|
spyOn(service, 'moveFolderAction').and.returnValue(Observable.of({}));
|
|
|
|
fileToMove.entry['allowableOperations'] = [permissionToMove];
|
|
folderToMove.entry['allowableOperations'] = [permissionToMove];
|
|
|
|
service.moveNodes([fileToMove, folderToMove], permissionToMove);
|
|
expect(spyOnBatchOperation).toHaveBeenCalledWith('move', [fileToMove, folderToMove], permissionToMove);
|
|
expect(spyOnDestinationPicker).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should not allow to select destination for nodes that do not have permission to be moved', () => {
|
|
const spyOnDestinationPicker =
|
|
spyOn(service, 'getContentNodeSelection')
|
|
.and.returnValue(Observable.of([destinationFolder.entry]));
|
|
|
|
fileToMove.entry['allowableOperations'] = [];
|
|
folderToMove.entry['allowableOperations'] = [];
|
|
|
|
service.moveNodes([fileToMove, folderToMove], permissionToMove);
|
|
expect(spyOnBatchOperation).toHaveBeenCalledWith('move', [fileToMove, folderToMove], permissionToMove);
|
|
expect(spyOnDestinationPicker).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call the documentListService moveNode directly for moving a file that has permission to be moved', () => {
|
|
const spyOnDestinationPicker =
|
|
spyOn(service, 'getContentNodeSelection')
|
|
.and.returnValue(Observable.of([destinationFolder.entry]));
|
|
fileToMove.entry['allowableOperations'] = [permissionToMove];
|
|
spyOnDocumentListServiceAction = spyOn(documentListService, 'moveNode').and.returnValue(Observable.of([fileToMove]));
|
|
spyOn(service, 'moveNodeAction');
|
|
|
|
service.moveNodes([fileToMove], permissionToMove);
|
|
expect(service.moveNodeAction).not.toHaveBeenCalled();
|
|
expect(spyOnDocumentListServiceAction).toHaveBeenCalled();
|
|
});
|
|
|
|
describe('moveContentAction', () => {
|
|
|
|
beforeEach(() => {
|
|
spyOnSuccess.calls.reset();
|
|
spyOnError.calls.reset();
|
|
});
|
|
|
|
it('should not throw error on conflict, to be able to show message in case of partial move of files', async(() => {
|
|
spyOnDocumentListServiceAction = spyOn(documentListService, 'moveNode').and
|
|
.returnValue(Observable.throw(conflictError));
|
|
|
|
const moveContentActionObservable = service.moveContentAction(fileToMove.entry, folderDestinationId);
|
|
moveContentActionObservable.toPromise()
|
|
.then(
|
|
(value) => {
|
|
spyOnSuccess(value);
|
|
},
|
|
(error) => {
|
|
spyOnError(error);
|
|
|
|
})
|
|
.then(() => {
|
|
expect(spyOnDocumentListServiceAction).toHaveBeenCalled();
|
|
|
|
expect(spyOnSuccess).toHaveBeenCalledWith(conflictError);
|
|
expect(spyOnError).not.toHaveBeenCalledWith(conflictError);
|
|
});
|
|
}));
|
|
|
|
it('should throw permission error in case it occurs', async(() => {
|
|
spyOnDocumentListServiceAction = spyOn(documentListService, 'moveNode').and
|
|
.returnValue(Observable.throw(permissionError));
|
|
|
|
const moveContentActionObservable = service.moveContentAction(fileToMove.entry, folderDestinationId);
|
|
moveContentActionObservable.toPromise()
|
|
.then(
|
|
(value) => {
|
|
spyOnSuccess(value);
|
|
},
|
|
(error) => {
|
|
spyOnError(error);
|
|
|
|
})
|
|
.then(() => {
|
|
expect(spyOnDocumentListServiceAction).toHaveBeenCalled();
|
|
|
|
expect(spyOnSuccess).not.toHaveBeenCalledWith(permissionError);
|
|
expect(spyOnError).toHaveBeenCalledWith(permissionError);
|
|
});
|
|
}));
|
|
|
|
it('in case of success, should return also the initial parent id of the moved node', async(() => {
|
|
const parentID = 'parent-id';
|
|
fileToMove.entry['parentId'] = parentID;
|
|
fileToMove.entry['allowableOperations'] = [permissionToMove];
|
|
spyOnDocumentListServiceAction = spyOn(documentListService, 'moveNode').and
|
|
.returnValue(Observable.of(fileToMove));
|
|
|
|
const moveContentActionObservable = service.moveContentAction(fileToMove.entry, folderDestinationId);
|
|
moveContentActionObservable.toPromise()
|
|
.then(
|
|
(value) => {
|
|
spyOnSuccess(value);
|
|
},
|
|
(error) => {
|
|
spyOnError(error);
|
|
|
|
})
|
|
.then(() => {
|
|
expect(spyOnDocumentListServiceAction).toHaveBeenCalled();
|
|
|
|
expect(spyOnSuccess).toHaveBeenCalledWith({itemMoved: fileToMove, initialParentId: parentID});
|
|
expect(spyOnError).not.toHaveBeenCalledWith(permissionError);
|
|
});
|
|
}));
|
|
|
|
});
|
|
|
|
describe('moveFolderAction', () => {
|
|
|
|
beforeEach(() => {
|
|
spyOnSuccess.calls.reset();
|
|
spyOnError.calls.reset();
|
|
});
|
|
|
|
it('should throw permission error in case it occurs on folder move', async(() => {
|
|
spyOnDocumentListServiceAction = spyOn(documentListService, 'moveNode').and
|
|
.returnValue(Observable.throw(permissionError));
|
|
|
|
const moveFolderActionObservable = service.moveFolderAction(folderToMove.entry, folderDestinationId);
|
|
moveFolderActionObservable.toPromise()
|
|
.then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
(error) => {
|
|
spyOnError(error);
|
|
})
|
|
.then(() => {
|
|
expect(spyOnDocumentListServiceAction).toHaveBeenCalled();
|
|
|
|
expect(spyOnSuccess).not.toHaveBeenCalled();
|
|
expect(spyOnError).toHaveBeenCalledWith(permissionError);
|
|
});
|
|
}));
|
|
|
|
it('should not throw error on conflict in case it occurs on folder move', async(() => {
|
|
spyOnDocumentListServiceAction = spyOn(documentListService, 'moveNode').and
|
|
.returnValue(Observable.throw(conflictError));
|
|
|
|
const newDestination = new TestNode('new-destination', !isFile, folderToMove.entry.name);
|
|
spyOn(service, 'getChildByName').and.returnValue(Observable.of(newDestination));
|
|
spyOn(service, 'getNodeChildren').and.returnValue(Observable.of(emptyChildrenList));
|
|
|
|
const moveFolderActionObservable = service.moveFolderAction(folderToMove.entry, folderDestinationId);
|
|
moveFolderActionObservable.toPromise()
|
|
.then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
(error) => {
|
|
spyOnError(error);
|
|
})
|
|
.then(() => {
|
|
expect(spyOnDocumentListServiceAction).toHaveBeenCalled();
|
|
|
|
expect(spyOnSuccess).toHaveBeenCalled();
|
|
expect(spyOnError).not.toHaveBeenCalledWith(conflictError);
|
|
});
|
|
}));
|
|
|
|
it('should try to move children nodes of a folder to already existing folder with same name', async(() => {
|
|
const parentFolderToMove = new TestNode('parent-folder', !isFile, 'conflicting-name');
|
|
spyOnDocumentListServiceAction = spyOn(documentListService, 'moveNode').and.callFake(
|
|
(contentEntryId, selectionId) => {
|
|
if (contentEntryId === parentFolderToMove.entry.id) {
|
|
return Observable.throw(conflictError);
|
|
|
|
}
|
|
return Observable.of({});
|
|
});
|
|
spyOn(service, 'moveContentAction').and.returnValue(Observable.of({}));
|
|
|
|
const newDestination = new TestNode('new-destination', !isFile, 'conflicting-name');
|
|
spyOn(service, 'getChildByName').and.returnValue(Observable.of(newDestination));
|
|
const childrenNodes = [ fileToMove, folderToMove ];
|
|
spyOn(service, 'getNodeChildren').and.returnValue(Observable.of( {list: {entries: childrenNodes}} ));
|
|
|
|
const moveFolderActionObservable = service.moveFolderAction(parentFolderToMove.entry, folderDestinationId);
|
|
moveFolderActionObservable.toPromise()
|
|
.then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
(error) => {
|
|
spyOnError(error);
|
|
})
|
|
.then(() => {
|
|
expect(spyOnDocumentListServiceAction).toHaveBeenCalled();
|
|
|
|
expect(spyOnSuccess).toHaveBeenCalled();
|
|
expect(spyOnError).not.toHaveBeenCalledWith(conflictError);
|
|
});
|
|
}));
|
|
|
|
});
|
|
|
|
describe('moveNodeAction', () => {
|
|
describe('on moving folder to a destination where a folder with the same name exists', () => {
|
|
let parentFolderToMove;
|
|
let moveNodeActionPromise;
|
|
let spyOnDelete;
|
|
|
|
beforeEach(() => {
|
|
parentFolderToMove = new TestNode('parent-folder', !isFile, 'conflicting-name');
|
|
spyOnDelete = spyOn(nodesApiService, 'deleteNode').and.returnValue(Observable.of(null));
|
|
});
|
|
|
|
afterEach(() => {
|
|
spyOnDelete.calls.reset();
|
|
spyOnSuccess.calls.reset();
|
|
spyOnError.calls.reset();
|
|
});
|
|
|
|
it('should take no extra delete action, if folder was moved to the same location', async(() => {
|
|
spyOn(service, 'moveFolderAction').and.returnValue(Observable.of(null));
|
|
|
|
parentFolderToMove.entry.parentId = folderDestinationId;
|
|
moveNodeActionPromise = service.moveNodeAction(parentFolderToMove.entry, folderDestinationId).toPromise();
|
|
moveNodeActionPromise
|
|
.then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
(error) => {
|
|
spyOnError(error);
|
|
})
|
|
.then(() => {
|
|
expect(spyOnDelete).not.toHaveBeenCalled();
|
|
|
|
expect(spyOnSuccess).toHaveBeenCalled();
|
|
expect(spyOnError).not.toHaveBeenCalled();
|
|
});
|
|
}));
|
|
|
|
it('should take no extra delete action, if its children were partially moved', async(() => {
|
|
const movedChildrenNodes = [ fileToMove, folderToMove ];
|
|
spyOn(service, 'moveFolderAction').and.returnValue(Observable.of(movedChildrenNodes));
|
|
spyOn(service, 'processResponse').and.returnValue({
|
|
succeeded: [ fileToMove ],
|
|
failed: [ folderToMove ],
|
|
partiallySucceeded: []
|
|
});
|
|
|
|
parentFolderToMove.entry.parentId = `not-${folderDestinationId}`;
|
|
moveNodeActionPromise = service.moveNodeAction(parentFolderToMove.entry, folderDestinationId).toPromise();
|
|
moveNodeActionPromise
|
|
.then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
(error) => {
|
|
spyOnError(error);
|
|
})
|
|
.then(() => {
|
|
expect(spyOnDelete).not.toHaveBeenCalled();
|
|
|
|
expect(spyOnSuccess).toHaveBeenCalled();
|
|
expect(spyOnError).not.toHaveBeenCalled();
|
|
});
|
|
}));
|
|
|
|
it('should take extra delete action, if children successfully moved and folder is still on location', async(() => {
|
|
const movedChildrenNodes = [ fileToMove, folderToMove ];
|
|
spyOn(service, 'moveFolderAction').and.returnValue(Observable.of(movedChildrenNodes));
|
|
spyOn(service, 'processResponse').and.returnValue({
|
|
succeeded: [ movedChildrenNodes ],
|
|
failed: [],
|
|
partiallySucceeded: []
|
|
});
|
|
const folderOnLocation = parentFolderToMove;
|
|
spyOn(service, 'getChildByName').and.returnValue(Observable.of(folderOnLocation));
|
|
|
|
parentFolderToMove.entry.parentId = `not-${folderDestinationId}`;
|
|
moveNodeActionPromise = service.moveNodeAction(parentFolderToMove.entry, folderDestinationId).toPromise();
|
|
moveNodeActionPromise
|
|
.then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
(error) => {
|
|
spyOnError(error);
|
|
})
|
|
.then(() => {
|
|
expect(spyOnDelete).toHaveBeenCalled();
|
|
|
|
expect(spyOnSuccess).toHaveBeenCalled();
|
|
expect(spyOnError).not.toHaveBeenCalled();
|
|
});
|
|
}));
|
|
|
|
it('should take no extra delete action, if folder is no longer on location', async(() => {
|
|
const movedChildrenNodes = [ fileToMove, folderToMove ];
|
|
spyOn(service, 'moveFolderAction').and.returnValue(Observable.of(movedChildrenNodes));
|
|
spyOn(service, 'processResponse').and.returnValue({
|
|
succeeded: [ movedChildrenNodes ],
|
|
failed: [],
|
|
partiallySucceeded: []
|
|
});
|
|
spyOn(service, 'getChildByName').and.returnValue(Observable.of(null));
|
|
|
|
parentFolderToMove.entry.parentId = `not-${folderDestinationId}`;
|
|
moveNodeActionPromise = service.moveNodeAction(parentFolderToMove.entry, folderDestinationId).toPromise();
|
|
moveNodeActionPromise
|
|
.then(
|
|
() => {
|
|
spyOnSuccess();
|
|
},
|
|
(error) => {
|
|
spyOnError(error);
|
|
})
|
|
.then(() => {
|
|
expect(spyOnDelete).not.toHaveBeenCalled();
|
|
|
|
expect(spyOnSuccess).toHaveBeenCalled();
|
|
expect(spyOnError).not.toHaveBeenCalled();
|
|
});
|
|
|
|
}));
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe('getChildByName', () => {
|
|
let testFamilyNodes;
|
|
let notChildNode;
|
|
let childNode;
|
|
|
|
beforeEach(() => {
|
|
childNode = new TestNode(fileId, isFile, 'child-name');
|
|
const parentNode = new TestNode();
|
|
|
|
notChildNode = new TestNode('not-child-id', !isFile, 'not-child-name');
|
|
testFamilyNodes = [
|
|
{
|
|
parentNodeId: parentNode.entry.id,
|
|
nodeChildren: [childNode]
|
|
}, {
|
|
parentNodeId: notChildNode.entry.id,
|
|
nodeChildren: []
|
|
}
|
|
];
|
|
});
|
|
|
|
it('emits child node with specified name, when it exists in folder', () => {
|
|
spyOn(nodesApi, 'getNodeChildren').and.callFake(helper.fakeGetNodeChildren(testFamilyNodes));
|
|
|
|
service.getChildByName(testFamilyNodes[0].parentNodeId, childNode.entry.name)
|
|
.subscribe(
|
|
(value) => {
|
|
expect(value).toEqual(childNode);
|
|
}
|
|
);
|
|
});
|
|
|
|
it('emits null value when child with specified name is not found in folder', async(() => {
|
|
spyOn(nodesApi, 'getNodeChildren').and.callFake(helper.fakeGetNodeChildren(testFamilyNodes));
|
|
|
|
service.getChildByName(testFamilyNodes[0].parentNodeId, notChildNode.entry.name)
|
|
.subscribe(
|
|
(value) => {
|
|
expect(value).toEqual(null);
|
|
}
|
|
);
|
|
}));
|
|
|
|
it('emits error when permission error occurs', async(() => {
|
|
spyOn(nodesApi, 'getNodeChildren').and.callFake(helper.fakeGetNodeChildren(testFamilyNodes, actionIsForbidden));
|
|
|
|
service.getChildByName(testFamilyNodes[0].parentNodeId, notChildNode.entry.name)
|
|
.subscribe(
|
|
(value) => {
|
|
expect(value).toEqual(null);
|
|
}
|
|
);
|
|
}));
|
|
});
|
|
|
|
describe('getNewNameFrom', () => {
|
|
const testData = [
|
|
{
|
|
name: 'noExtension',
|
|
baseName: 'noExtension',
|
|
expected: 'noExtension-1'
|
|
}, {
|
|
name: 'withExtension.txt',
|
|
baseName: 'withExtension.txt',
|
|
expected: 'withExtension-1.txt'
|
|
}, {
|
|
name: 'with-lineStringSufix.txt',
|
|
baseName: 'with-lineStringSufix.txt',
|
|
expected: 'with-lineStringSufix-1.txt'
|
|
}, {
|
|
name: 'noExtension-1',
|
|
baseName: 'noExtension-1',
|
|
expected: 'noExtension-1-1'
|
|
}, {
|
|
name: 'with-lineNumberSufix-1.txt',
|
|
baseName: 'with-lineNumberSufix-1.txt',
|
|
expected: 'with-lineNumberSufix-1-1.txt'
|
|
}, {
|
|
name: 'with-lineNumberSufix.txt',
|
|
baseName: undefined,
|
|
expected: 'with-lineNumberSufix-1.txt'
|
|
}, {
|
|
name: 'noExtension-1',
|
|
baseName: 'noExtension',
|
|
expected: 'noExtension-2'
|
|
}, {
|
|
name: 'noExtension-7',
|
|
baseName: undefined,
|
|
expected: 'noExtension-8'
|
|
}, {
|
|
name: 'noExtension-007',
|
|
baseName: undefined,
|
|
expected: 'noExtension-007-1'
|
|
}
|
|
];
|
|
testData.forEach((data) => {
|
|
it(`new name should be \'${data.expected}\' for given name: \'${data.name}\', and baseName: \'${data.baseName}\'`, () => {
|
|
const result = service.getNewNameFrom(data.name, data.baseName);
|
|
expect(result).toBe(data.expected);
|
|
});
|
|
|
|
});
|
|
});
|
|
|
|
describe('flatten', () => {
|
|
const testNode1 = new TestNode('node1-id', isFile, 'node1-name');
|
|
const testNode2 = new TestNode('node2-id', !isFile, 'node2-name');
|
|
|
|
const testData = [
|
|
{
|
|
nDimArray: [ testNode1 ],
|
|
expected: [ testNode1 ]
|
|
},
|
|
{
|
|
nDimArray: [ [ testNode1 ], [ testNode2 ] ],
|
|
expected: [ testNode1, testNode2 ]
|
|
},
|
|
{
|
|
nDimArray: [ [ [ [ testNode1 ] ], testNode2 ] ],
|
|
expected: [ testNode2, testNode1 ]
|
|
}
|
|
];
|
|
|
|
testData.forEach((data) => {
|
|
it(`flattened array should be \'${data.expected}\' for given data: \'${data.nDimArray}\'`, () => {
|
|
const result = service.flatten(data.nDimArray);
|
|
|
|
expect(result.length).toBe(data.expected.length);
|
|
expect(JSON.stringify(result)).toEqual(JSON.stringify(data.expected));
|
|
});
|
|
|
|
});
|
|
});
|
|
|
|
describe('processResponse', () => {
|
|
const testNode1 = new TestNode('node1-id', isFile, 'node1-name');
|
|
const testNode2 = new TestNode('node2-id', !isFile, 'node2-name');
|
|
|
|
const parentID = 'patent-1-id';
|
|
testNode1.entry['parentId'] = parentID;
|
|
|
|
const testData = [
|
|
{
|
|
data: [ testNode1 ],
|
|
expected: {
|
|
succeeded: [ testNode1 ],
|
|
failed: [],
|
|
partiallySucceeded: []
|
|
}
|
|
}, {
|
|
data: [ [ {itemMoved: testNode1, initialParentId: parentID} ] ],
|
|
expected: {
|
|
succeeded: [ [ {itemMoved: testNode1, initialParentId: parentID} ] ],
|
|
failed: [],
|
|
partiallySucceeded: []
|
|
}
|
|
}, {
|
|
data: [ conflictError ],
|
|
expected: {
|
|
succeeded: [],
|
|
failed: [ conflictError ],
|
|
partiallySucceeded: []
|
|
}
|
|
}, {
|
|
data: [ conflictError, testNode2 ],
|
|
expected: {
|
|
succeeded: [ testNode2 ],
|
|
failed: [ conflictError ],
|
|
partiallySucceeded: []
|
|
}
|
|
}, {
|
|
data: [ conflictError, [ testNode2, conflictError] ],
|
|
expected: {
|
|
succeeded: [],
|
|
failed: [ conflictError ],
|
|
partiallySucceeded: [ [ testNode2, conflictError ] ]
|
|
}
|
|
}, {
|
|
data: [ conflictError, [ {}, conflictError] ],
|
|
expected: {
|
|
succeeded: [],
|
|
failed: [ conflictError, [ {}, conflictError ] ],
|
|
partiallySucceeded: []
|
|
}
|
|
}, {
|
|
data: {},
|
|
expected: {
|
|
succeeded: [],
|
|
failed: [ {} ],
|
|
partiallySucceeded: []
|
|
}
|
|
}, {
|
|
data: testNode1,
|
|
expected: {
|
|
succeeded: [ testNode1 ],
|
|
failed: [],
|
|
partiallySucceeded: []
|
|
}
|
|
}, {
|
|
data: {itemMoved: testNode1, initialParentId: parentID},
|
|
expected: {
|
|
succeeded: [ {itemMoved: testNode1, initialParentId: parentID} ],
|
|
failed: [],
|
|
partiallySucceeded: []
|
|
}
|
|
}
|
|
];
|
|
|
|
testData.forEach((response) => {
|
|
it(`processed response should be \'${response.expected}\' for given input: \'${response.data}\'`, () => {
|
|
const result = service.processResponse(response.data);
|
|
|
|
expect(JSON.stringify(result)).toEqual(JSON.stringify(response.expected));
|
|
});
|
|
|
|
});
|
|
});
|
|
|
|
});
|