External source import completed with tests

This commit is contained in:
Matteo Perelli
2020-06-24 10:16:30 +02:00
parent c2c650fa1a
commit 43f5e08530
21 changed files with 681 additions and 54 deletions

View File

@@ -1,4 +1,4 @@
import { Component, Injector, OnInit } from '@angular/core';
import { Component } from '@angular/core';
/**
* Component representing the external import page of the submission.

View File

@@ -4,8 +4,6 @@ import { NgModule } from '@angular/core';
import { SharedModule } from '../shared/shared.module';
import { CoreModule } from '../core/core.module';
import { ImportExternalRoutingModule } from './import-external-routing.module';
import { SubmissionImportExternalComponent } from '../submission/import-external/submission-import-external.component';
import { SubmissionImportExternalSearchbarComponent } from '../submission/import-external/import-external-searchbar/submission-import-external-searchbar.component';
import { SubmissionModule } from '../submission/submission.module';
@NgModule({

View File

@@ -24,7 +24,7 @@ interface CollectionListEntryItem {
/**
* An interface to represent an entry in the collection list
*/
interface CollectionListEntry {
export interface CollectionListEntry {
communities: CollectionListEntryItem[],
collection: CollectionListEntryItem
}

View File

@@ -1,12 +1,59 @@
// import { ExternalSourceService } from '../../core/data/external-source.service';
import { ExternalSourceService } from '../../core/data/external-source.service';
import { ExternalSource } from '../../core/shared/external-source.model';
import { ResourceType } from '../../core/shared/resource-type';
export const externalSourceOrcid: ExternalSource = {
type: new ResourceType('externalsource'),
id: 'orcid',
name: 'orcid',
hierarchical: false,
_links: {
entries: {
href: "https://dspace7.4science.cloud/server/api/integration/externalsources/orcid/entries"
},
self: {
href: "https://dspace7.4science.cloud/server/api/integration/externalsources/orcid"
}
}
};
export const externalSourceCiencia: ExternalSource = {
type: new ResourceType('externalsource'),
id: 'ciencia',
name: 'ciencia',
hierarchical: false,
_links: {
entries: {
href: "https://dspace7.4science.cloud/server/api/integration/externalsources/ciencia/entries"
},
self: {
href: "https://dspace7.4science.cloud/server/api/integration/externalsources/ciencia"
}
}
};
export const externalSourceMyStaffDb: ExternalSource = {
type: new ResourceType('externalsource'),
id: 'my_staff_db',
name: 'my_staff_db',
hierarchical: false,
_links: {
entries: {
href: "https://dspace7.4science.cloud/server/api/integration/externalsources/my_staff_db/entries"
},
self: {
href: "https://dspace7.4science.cloud/server/api/integration/externalsources/my_staff_db"
}
}
};
/**
* Mock for [[ExternalSourceService]]
*/
/*export function getMockExternalSourceService():
export function getMockExternalSourceService():
ExternalSourceService {
return jasmine.createSpyObj('ExternalSourceService', {
getAllExternalSources: jasmine.createSpy('getAllExternalSources'),
getExternalSourceEntries: jasmine.createSpy('getExternalSourceEntries'),
});
}*/
}

View File

@@ -461,7 +461,8 @@ const ENTRY_COMPONENTS = [
ClaimedTaskActionsApproveComponent,
ClaimedTaskActionsRejectComponent,
ClaimedTaskActionsReturnToPoolComponent,
ClaimedTaskActionsEditMetadataComponent
ClaimedTaskActionsEditMetadataComponent,
CollectionDropdownComponent
];
const SHARED_ITEM_PAGE_COMPONENTS = [

View File

@@ -2,6 +2,7 @@ export class SubmissionServiceStub {
changeSubmissionCollection = jasmine.createSpy('changeSubmissionCollection');
createSubmission = jasmine.createSpy('createSubmission');
createSubmissionFromExternalSource = jasmine.createSpy('createSubmissionFromExternalSource');
depositSubmission = jasmine.createSpy('depositSubmission');
discardSubmission = jasmine.createSpy('discardSubmission');
dispatchInit = jasmine.createSpy('dispatchInit');

View File

@@ -0,0 +1,11 @@
<div>
<div class="modal-header">{{'dso-selector.create.collection.head' | translate}}
<button type="button" class="close" (click)="closeCollectionModal()" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<ds-collection-dropdown (selectionChange)="selectObject($event)">
</ds-collection-dropdown>
</div>
</div>

View File

@@ -0,0 +1,3 @@
.close:focus {
outline: none !important;
}

View File

@@ -0,0 +1,89 @@
import { Component, NO_ERRORS_SCHEMA, EventEmitter } from '@angular/core';
import { async, TestBed, ComponentFixture, inject } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { createTestComponent } from '../../../shared/testing/utils.test';
import { SubmissionImportExternalCollectionComponent } from './submission-import-external-collection.component';
import { CollectionListEntry } from '../../../shared/collection-dropdown/collection-dropdown.component';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
describe('SubmissionImportExternalCollectionComponent test suite', () => {
let comp: SubmissionImportExternalCollectionComponent;
let compAsAny: any;
let fixture: ComponentFixture<SubmissionImportExternalCollectionComponent>;
beforeEach(async (() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
],
declarations: [
SubmissionImportExternalCollectionComponent,
TestComponent,
],
providers: [
NgbActiveModal,
SubmissionImportExternalCollectionComponent
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents().then();
}));
// First test to check the correct component creation
describe('', () => {
let testComp: TestComponent;
let testFixture: ComponentFixture<TestComponent>;
// synchronous beforeEach
beforeEach(() => {
const html = `
<ds-submission-import-external-collection></ds-submission-import-external-collection>`;
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
testComp = testFixture.componentInstance;
});
afterEach(() => {
testFixture.destroy();
});
it('should create SubmissionImportExternalCollectionComponent', inject([SubmissionImportExternalCollectionComponent], (app: SubmissionImportExternalCollectionComponent) => {
expect(app).toBeDefined();
}));
});
describe('', () => {
beforeEach(() => {
fixture = TestBed.createComponent(SubmissionImportExternalCollectionComponent);
comp = fixture.componentInstance;
compAsAny = comp;
});
afterEach(() => {
fixture.destroy();
comp = null;
compAsAny = null;
});
it('The variable \'selectedEvent\' should be assigned', () => {
const event = new EventEmitter<CollectionListEntry>();
comp.selectObject(event);
expect(comp.selectedEvent).toEqual(event);
});
it('The variable \'selectedEvent\' should be assigned', () => {
spyOn(compAsAny.activeModal, 'dismiss');
comp.closeCollectionModal();
expect(compAsAny.activeModal.dismiss).toHaveBeenCalled();
});
});
});
// declare a test component
@Component({
selector: 'ds-test-cmp',
template: ``
})
class TestComponent {
}

View File

@@ -0,0 +1,40 @@
import { Component, Output, EventEmitter } from '@angular/core';
import { CollectionListEntry } from '../../../shared/collection-dropdown/collection-dropdown.component';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
/**
* Wrap component for 'ds-collection-dropdown'.
*/
@Component({
selector: 'ds-submission-import-external-collection',
styleUrls: ['./submission-import-external-collection.component.scss'],
templateUrl: './submission-import-external-collection.component.html'
})
export class SubmissionImportExternalCollectionComponent {
/**
* The event passed by 'ds-collection-dropdown'.
*/
@Output() public selectedEvent = new EventEmitter<CollectionListEntry>();
/**
* Initialize the component variables.
* @param {NgbActiveModal} activeModal
*/
constructor(
private activeModal: NgbActiveModal
) { }
/**
* This method populates the 'selectedEvent' variable.
*/
public selectObject(event): void {
this.selectedEvent.emit(event);
}
/**
* This method closes the modal.
*/
public closeCollectionModal(): void {
this.activeModal.dismiss(false);
}
}

View File

@@ -30,9 +30,9 @@
</div>
<div class="row">
<div class="col-md-12 text-right">
<a class="btn btn-success" (click)="import()" role="button">
<button class="btn btn-success" (click)="import()" role="button">
<i class="fa fa-file-import" aria-hidden="true"></i> {{'submission.import-external.preview.button.import' | translate}}
</a>
</button>
</div>
</div>
</div>

View File

@@ -0,0 +1,153 @@
import { Component, NO_ERRORS_SCHEMA } from '@angular/core';
import { async, TestBed, ComponentFixture, inject } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { Router } from '@angular/router';
import { NgbModal, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { of as observableOf, of } from 'rxjs/internal/observable/of';
import { SubmissionImportExternalPreviewComponent } from './submission-import-external-preview.component';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { RouterStub } from '../../../shared/testing/router.stub';
import { SubmissionService } from '../../submission.service';
import { createTestComponent } from '../../../shared/testing/utils.test';
import { SubmissionServiceStub } from '../../../shared/testing/submission-service.stub';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { ExternalSourceEntry } from '../../../core/shared/external-source-entry.model';
import { Metadata } from '../../../core/shared/metadata.utils';
import { SubmissionImportExternalCollectionComponent } from '../import-external-collection/submission-import-external-collection.component';
import { CollectionListEntry } from '../../../shared/collection-dropdown/collection-dropdown.component';
describe('SubmissionImportExternalPreviewComponent test suite', () => {
let comp: SubmissionImportExternalPreviewComponent;
let compAsAny: any;
let fixture: ComponentFixture<SubmissionImportExternalPreviewComponent>;
let submissionServiceStub: SubmissionServiceStub;
const externalEntry = Object.assign(new ExternalSourceEntry(), {
id: '0001-0001-0001-0001',
display: 'John Doe',
value: 'John, Doe',
metadata: {
'dc.identifier.uri': [
{
value: 'https://orcid.org/0001-0001-0001-0001'
}
]
},
_links: { self: { href: 'http://test-rest.com/server/api/integration/externalSources/orcidV2/entryValues/0000-0003-4851-8004' } }
});
beforeEach(async (() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot()
],
declarations: [
SubmissionImportExternalPreviewComponent,
TestComponent
],
providers: [
{ provide: Router, useValue: new RouterStub() },
{ provide: SubmissionService, useValue: new SubmissionServiceStub() },
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
NgbModal,
NgbActiveModal,
SubmissionImportExternalPreviewComponent
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents().then();
}));
// First test to check the correct component creation
describe('', () => {
let testComp: TestComponent;
let testFixture: ComponentFixture<TestComponent>;
// synchronous beforeEach
beforeEach(() => {
const html = `
<ds-submission-import-external-preview></ds-submission-import-external-preview>`;
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
testComp = testFixture.componentInstance;
});
afterEach(() => {
testFixture.destroy();
});
it('should create SubmissionImportExternalComponent', inject([SubmissionImportExternalPreviewComponent], (app: SubmissionImportExternalPreviewComponent) => {
expect(app).toBeDefined();
}));
});
describe('', () => {
beforeEach(() => {
fixture = TestBed.createComponent(SubmissionImportExternalPreviewComponent);
comp = fixture.componentInstance;
compAsAny = comp;
submissionServiceStub = TestBed.get(SubmissionService);
});
afterEach(() => {
fixture.destroy();
comp = null;
compAsAny = null;
});
it('Should init component properly', () => {
comp.externalSourceEntry = externalEntry;
const expected = [
{ key: 'dc.identifier.uri', value: Metadata.first(comp.externalSourceEntry.metadata, 'dc.identifier.uri') }
];
comp.ngOnInit();
fixture.detectChanges();
expect(comp.metadataList).toEqual(expected);
});
it('Should close the modal calling \'activeModal.dismiss\'', () => {
spyOn(compAsAny.activeModal, 'dismiss');
comp.closeMetadataModal();
expect(compAsAny.activeModal.dismiss).toHaveBeenCalled();
});
it('Should start the import process opening a modal', () => {
const emittedEvent: CollectionListEntry = {
communities: [
{
id: 'dummy',
uuid: 'dummy',
name: 'dummy',
}
],
collection: {
id: 'ce64f48e-2c9b-411a-ac36-ee429c0e6a88',
uuid: 'ce64f48e-2c9b-411a-ac36-ee429c0e6a88',
name: 'Collection 1',
}
};
const submissionObjects = [
{ id: 'jk11k13o-9v4z-632i-sr88-wq071n0h1d47' }
];
comp.externalSourceEntry = externalEntry;
spyOn(compAsAny.modalService, 'open').and.returnValue({componentInstance: { selectedEvent: observableOf(emittedEvent)}});
spyOn(comp, 'closeMetadataModal');
submissionServiceStub.createSubmissionFromExternalSource.and.returnValue(observableOf(submissionObjects));
spyOn(compAsAny.router, 'navigateByUrl');
comp.import();
expect(compAsAny.modalService.open).toHaveBeenCalledWith(SubmissionImportExternalCollectionComponent, { size: 'lg' });
expect(comp.closeMetadataModal).toHaveBeenCalled();
expect(compAsAny.submissionService.createSubmissionFromExternalSource).toHaveBeenCalledWith(externalEntry._links.self.href, emittedEvent.collection.id);
expect(compAsAny.router.navigateByUrl).toHaveBeenCalledWith('/workspaceitems/' + submissionObjects[0].id + '/edit');
});
});
});
// declare a test component
@Component({
selector: 'ds-test-cmp',
template: ``
})
class TestComponent {
}

View File

@@ -1,8 +1,15 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { NgbActiveModal, NgbModalRef, NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { ExternalSourceEntry } from '../../../core/shared/external-source-entry.model';
import { MetadataValue } from '../../../core/shared/metadata.models';
import { Metadata } from '../../../core/shared/metadata.utils';
import { CollectionListEntry } from '../../../shared/collection-dropdown/collection-dropdown.component';
import { mergeMap } from 'rxjs/operators';
import { SubmissionService } from '../../submission.service';
import { SubmissionObject } from '../../../core/submission/models/submission-object.model';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { SubmissionImportExternalCollectionComponent } from '../import-external-collection/submission-import-external-collection.component';
/**
* This component display a preview of an external source item.
@@ -29,10 +36,17 @@ export class SubmissionImportExternalPreviewComponent implements OnInit {
/**
* Initialize the component variables.
* @param {NgbActiveModal} activeModal
* @param {SubmissionService} submissionService
* @param {NgbModal} modalService
* @param {Router} router
* @param {NotificationsService} notificationService
*/
constructor(
private activeModal: NgbActiveModal,
private modalService: NgbModal
private submissionService: SubmissionService,
private modalService: NgbModal,
private router: Router,
private notificationService: NotificationsService
) { }
/**
@@ -57,14 +71,30 @@ export class SubmissionImportExternalPreviewComponent implements OnInit {
}
/**
* Start the import of an entry by opening up an import modal window.
* @param entry The entry to import
* Start the import of an entry by opening up a collection choice modal window.
*/
public import(entry): void {
this.modalRef = this.modalService.open(SubmissionImportExternalPreviewComponent, {
public import(): void {
this.modalRef = this.modalService.open(SubmissionImportExternalCollectionComponent, {
size: 'lg',
});
const modalComp = this.modalRef.componentInstance;
modalComp.externalSourceEntry = entry;
this.closeMetadataModal();
this.modalRef.componentInstance.selectedEvent.pipe(
mergeMap((collectionListEntry: CollectionListEntry) => {
return this.submissionService.createSubmissionFromExternalSource(this.externalSourceEntry._links.self.href, collectionListEntry.collection.id);
})
).subscribe((submissionObjects: SubmissionObject[]) => {
let isValid = false
if (submissionObjects.length === 1) {
if (submissionObjects[0] !== null) {
isValid = true;
this.router.navigateByUrl('/workspaceitems/' + submissionObjects[0].id + '/edit');
}
}
if (!isValid) {
this.notificationService.error('submission.import-external.preview.error.import.title', 'submission.import-external.preview.error.import.body');
}
this.modalRef.close();
});
}
}

View File

@@ -1,13 +1,18 @@
// import { Component, NO_ERRORS_SCHEMA, ChangeDetectorRef } from '@angular/core';
// import { async, TestBed, ComponentFixture, inject } from '@angular/core/testing';
// import { TranslateModule } from '@ngx-translate/core';
// import { SubmissionImportExternalSearchbarComponent } from './submission-import-external-searchbar.component';
// import { ExternalSourceService } from '../../../core/data/external-source.service';
// import { createTestComponent } from '../../../shared/testing/utils.test';
// import { getMockExternalSourceService } from '../../../shared/mocks/external-source.service.mock';
// import { SubmissionModule } from '../../submission.module';
import { Component, NO_ERRORS_SCHEMA, ChangeDetectorRef } from '@angular/core';
import { async, TestBed, ComponentFixture, inject } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { of as observableOf } from 'rxjs';
import { SubmissionImportExternalSearchbarComponent, SourceElement } from './submission-import-external-searchbar.component';
import { ExternalSourceService } from '../../../core/data/external-source.service';
import { createTestComponent } from '../../../shared/testing/utils.test';
import { getMockExternalSourceService, externalSourceOrcid, externalSourceCiencia, externalSourceMyStaffDb } from '../../../shared/mocks/external-source.service.mock';
import { PageInfo } from '../../../core/shared/page-info.model';
import { PaginatedList } from '../../../core/data/paginated-list';
import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
import { ExternalSource } from '../../../core/shared/external-source.model';
import { FindListOptions } from '../../../core/data/request.models';
/*describe('SubmissionImportExternalSearchbarComponent test suite', () => {
describe('SubmissionImportExternalSearchbarComponent test suite', () => {
let comp: SubmissionImportExternalSearchbarComponent;
let compAsAny: any;
let fixture: ComponentFixture<SubmissionImportExternalSearchbarComponent>;
@@ -15,7 +20,6 @@
beforeEach(async (() => {
TestBed.configureTestingModule({
imports: [
SubmissionModule,
TranslateModule.forRoot(),
],
declarations: [
@@ -51,16 +55,25 @@
it('should create SubmissionImportExternalSearchbarComponent', inject([SubmissionImportExternalSearchbarComponent], (app: SubmissionImportExternalSearchbarComponent) => {
expect(app).toBeDefined();
}));
});*/
});
describe('', () => {
let sourceList: SourceElement[];
let paginatedList: PaginatedList<ExternalSource>;
/*describe('', () => {
beforeEach(() => {
fixture = TestBed.createComponent(SubmissionImportExternalSearchbarComponent);
comp = fixture.componentInstance;
compAsAny = comp;
// compAsAny.externalService.getAllExternalSources.and.returnValue(observableOf([
// ]));
const pageInfo = new PageInfo();
paginatedList = new PaginatedList(pageInfo, [externalSourceOrcid, externalSourceCiencia, externalSourceMyStaffDb]);
const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList);
compAsAny.externalService.getAllExternalSources.and.returnValue(observableOf(paginatedListRD));
sourceList = [
{id: 'orcid', name: 'orcid'},
{id: 'ciencia', name: 'ciencia'},
{id: 'my_staff_db', name: 'my_staff_db'},
];
});
afterEach(() => {
@@ -69,16 +82,61 @@
compAsAny = null;
});
it('Should init component properly', () => {
it('Should init component properly (without initExternalSourceData)', () => {
comp.initExternalSourceData = { sourceId: '', query: '' };
comp.ngOnInit();
fixture.detectChanges();
expect(comp.selectedElement)
expect(compAsAny.pageInfo)
expect(comp.sourceList)
expect(comp.selectedElement).toEqual(sourceList[0]);
expect(compAsAny.pageInfo).toEqual(paginatedList.pageInfo);
expect(comp.sourceList).toEqual(sourceList);
});
});*/
/*
it('Should init component properly (with initExternalSourceData populated)', () => {
comp.initExternalSourceData = { query: 'dummy', sourceId: 'ciencia' };
comp.ngOnInit();
fixture.detectChanges();
expect(comp.selectedElement).toEqual(sourceList[1]);
expect(compAsAny.pageInfo).toEqual(paginatedList.pageInfo);
expect(comp.sourceList).toEqual(sourceList);
});
it('Variable \'selectedElement\' should be assigned', () => {
const selectedElement = {id: 'orcid', name: 'orcid'};
comp.makeSourceSelection(selectedElement);
expect(comp.selectedElement).toEqual(selectedElement);
});
it('Should load additional external sources', () => {
comp.sourceListLoading = false;
compAsAny.pageInfo = new PageInfo({
elementsPerPage: 3,
totalElements: 6,
totalPages: 2,
currentPage: 0
});
compAsAny.findListOptions = Object.assign({}, new FindListOptions(), {
elementsPerPage: 3,
currentPage: 0,
});
comp.sourceList = sourceList;
const expected = sourceList.concat(sourceList);
comp.onScroll();
expect(comp.sourceList).toEqual(expected);
});
it('The \'search\' method should call \'emit\'', () => {
comp.selectedElement = { id: 'orcidV2', name: 'orcidV2' };
comp.searchString = 'dummy';
const expected = { sourceId: comp.selectedElement.id, query: comp.searchString };
spyOn(comp.externalSourceData, 'emit');
comp.search();
expect(comp.externalSourceData.emit).toHaveBeenCalledWith(expected);
});
});
});
// declare a test component
@@ -88,4 +146,4 @@
})
class TestComponent {
}*/
}

View File

@@ -10,13 +10,12 @@ import { RemoteData } from '../../../core/data/remote-data';
import { PageInfo } from '../../../core/shared/page-info.model';
import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
import { FindListOptions } from '../../../core/data/request.models';
import { isEmpty } from '../../../shared/empty.util';
import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators';
/**
* Interface for the selected external source element.
*/
interface SourceElement {
export interface SourceElement {
id: string;
name: string;
}
@@ -124,14 +123,14 @@ export class SubmissionImportExternalSearchbarComponent implements OnInit {
/**
* Set the selected external source.
*/
makeSourceSelection(source) {
public makeSourceSelection(source): void {
this.selectedElement = source;
}
/**
* Load the next pages of external sources.
*/
onScroll() {
public onScroll(): void {
if (!this.sourceListLoading && this.pageInfo.currentPage <= this.pageInfo.totalPages) {
this.sourceListLoading = true;
this.findListOptions = Object.assign({}, new FindListOptions(), {
@@ -145,21 +144,21 @@ export class SubmissionImportExternalSearchbarComponent implements OnInit {
const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList);
return observableOf(paginatedListRD);
}),
tap(() => this.sourceListLoading = false))
.subscribe((externalSource: RemoteData<PaginatedList<ExternalSource>>) => {
externalSource.payload.page.forEach((element) => {
this.sourceList.push({ id: element.id, name: element.name });
})
this.pageInfo = externalSource.payload.pageInfo;
this.cdr.detectChanges();
tap(() => this.sourceListLoading = false)
).subscribe((externalSource: RemoteData<PaginatedList<ExternalSource>>) => {
externalSource.payload.page.forEach((element) => {
this.sourceList.push({ id: element.id, name: element.name });
})
this.pageInfo = externalSource.payload.pageInfo;
this.cdr.detectChanges();
})
}
}
/**
* Passes the search parameters to the parent component.
*/
public search() {
public search(): void {
this.externalSourceData.emit({ sourceId: this.selectedElement.id, query: this.searchString });
}
}

View File

@@ -0,0 +1,159 @@
import { Component, NO_ERRORS_SCHEMA } from '@angular/core';
import { async, TestBed, ComponentFixture, inject } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { Router } from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { of as observableOf, of } from 'rxjs/internal/observable/of';
import { SubmissionImportExternalComponent } from './submission-import-external.component';
import { ExternalSourceService } from '../../core/data/external-source.service';
import { getMockExternalSourceService } from '../../shared/mocks/external-source.service.mock';
import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service';
import { RouteService } from '../../core/services/route.service';
import { createTestComponent, createPaginatedList } from '../../shared/testing/utils.test';
import { RouterStub } from '../../shared/testing/router.stub';
import { VarDirective } from '../../shared/utils/var.directive';
import { routeServiceStub } from '../../shared/testing/route-service.stub';
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils';
import { ExternalSourceEntry } from '../../core/shared/external-source-entry.model';
import { SubmissionImportExternalPreviewComponent } from './import-external-preview/submission-import-external-preview.component';
describe('SubmissionImportExternalComponent test suite', () => {
let comp: SubmissionImportExternalComponent;
let compAsAny: any;
let fixture: ComponentFixture<SubmissionImportExternalComponent>;
const mockSearchOptions = of(new PaginatedSearchOptions({
pagination: Object.assign(new PaginationComponentOptions(), {
pageSize: 10,
currentPage: 0
})
}));
const searchConfigServiceStub = {
paginatedSearchOptions: mockSearchOptions
};
beforeEach(async (() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot()
],
declarations: [
SubmissionImportExternalComponent,
TestComponent,
VarDirective
],
providers: [
{ provide: ExternalSourceService, useClass: getMockExternalSourceService },
{ provide: SearchConfigurationService, useValue: searchConfigServiceStub },
{ provide: RouteService, useValue: routeServiceStub },
{ provide: Router, useValue: new RouterStub() },
NgbModal,
SubmissionImportExternalComponent
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents().then();
}));
// First test to check the correct component creation
describe('', () => {
let testComp: TestComponent;
let testFixture: ComponentFixture<TestComponent>;
// synchronous beforeEach
beforeEach(() => {
const html = `
<ds-submission-import-external></ds-submission-import-external>`;
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
testComp = testFixture.componentInstance;
});
afterEach(() => {
testFixture.destroy();
});
it('should create SubmissionImportExternalComponent', inject([SubmissionImportExternalComponent], (app: SubmissionImportExternalComponent) => {
expect(app).toBeDefined();
}));
});
describe('', () => {
beforeEach(() => {
fixture = TestBed.createComponent(SubmissionImportExternalComponent);
comp = fixture.componentInstance;
compAsAny = comp;
});
afterEach(() => {
fixture.destroy();
comp = null;
compAsAny = null;
});
it('Should init component properly (without route data)', () => {
const expectedEntries = createSuccessfulRemoteDataObject(createPaginatedList([]));
spyOn(compAsAny.routeService, 'getQueryParameterValue').and.returnValue(observableOf(''));
comp.ngOnInit();
fixture.detectChanges();
expect(comp.routeData).toEqual({ sourceId: '', query: '' });
expect(comp.isLoading$.value).toBe(false);
expect(comp.entriesRD$.value).toEqual(expectedEntries);
});
it('Should init component properly (with route data)', () => {
const expectedEntries = createSuccessfulRemoteDataObject(createPaginatedList([]));
const searchOptions = new PaginatedSearchOptions({
pagination: Object.assign(new PaginationComponentOptions(), {
pageSize: 10,
currentPage: 0
})
});
spyOn(compAsAny.routeService, 'getQueryParameterValue').and.returnValue(observableOf('dummy'));
comp.ngOnInit();
fixture.detectChanges();
expect(comp.routeData).toEqual({ sourceId: 'dummy', query: 'dummy' });
expect(comp.isLoading$.value).toBe(true);
expect(comp.entriesRD$.value).toEqual(expectedEntries);
expect(compAsAny.externalService.getExternalSourceEntries).toHaveBeenCalledWith('dummy', searchOptions);
});
it('Should call \'router.navigate\'', () => {
const event = { sourceId: 'orcidV2', query: 'dummy' };
comp.getExternalsourceData(event);
expect(compAsAny.router.navigate).toHaveBeenCalledWith([], { queryParams: { source: event.sourceId, query: event.query }, replaceUrl: true });
});
it('Entry should be passed to the component loaded inside the modal', () => {
const entry = Object.assign(new ExternalSourceEntry(), {
id: '0001-0001-0001-0001',
display: 'John Doe',
value: 'John, Doe',
metadata: {
'dc.identifier.uri': [
{
value: 'https://orcid.org/0001-0001-0001-0001'
}
]
}
});
spyOn(compAsAny.modalService, 'open').and.returnValue({componentInstance: { externalSourceEntry: null}});
comp.import(entry);
expect(compAsAny.modalService.open).toHaveBeenCalledWith(SubmissionImportExternalPreviewComponent, { size: 'lg' });
expect(comp.modalRef.componentInstance.externalSourceEntry).toEqual(entry);
});
});
});
// declare a test component
@Component({
selector: 'ds-test-cmp',
template: ``
})
class TestComponent {
}

View File

@@ -70,7 +70,7 @@ export class SubmissionImportExternalComponent implements OnInit {
/**
* The modal for the entry preview
*/
modalRef: NgbModalRef;
public modalRef: NgbModalRef;
/**
* Initialize the component variables.

View File

@@ -31,6 +31,7 @@ import { storeModuleConfig } from '../app.reducer';
import { SubmissionImportExternalComponent } from './import-external/submission-import-external.component';
import { SubmissionImportExternalSearchbarComponent } from './import-external/import-external-searchbar/submission-import-external-searchbar.component';
import { SubmissionImportExternalPreviewComponent } from './import-external/import-external-preview/submission-import-external-preview.component';
import { SubmissionImportExternalCollectionComponent } from './import-external/import-external-collection/submission-import-external-collection.component';
@NgModule({
imports: [
@@ -60,14 +61,16 @@ import { SubmissionImportExternalPreviewComponent } from './import-external/impo
SubmissionSectionUploadFileViewComponent,
SubmissionImportExternalComponent,
SubmissionImportExternalSearchbarComponent,
SubmissionImportExternalPreviewComponent
SubmissionImportExternalPreviewComponent,
SubmissionImportExternalCollectionComponent
],
entryComponents: [
SubmissionSectionUploadComponent,
SubmissionSectionformComponent,
SubmissionSectionLicenseComponent,
SubmissionSectionContainerComponent,
SubmissionImportExternalPreviewComponent
SubmissionImportExternalPreviewComponent,
SubmissionImportExternalCollectionComponent
],
exports: [
SubmissionEditComponent,

View File

@@ -410,6 +410,19 @@ describe('SubmissionService test suite', () => {
});
});
describe('createSubmissionFromExternalSource', () => {
it('should deposit submission', () => {
const options: HttpOptions = Object.create({});
let headers = new HttpHeaders();
headers = headers.append('Content-Type', 'text/uri-list');
options.headers = headers;
service.createSubmissionFromExternalSource(selfUrl, collectionId);
expect((service as any).restService.postToEndpoint).toHaveBeenCalledWith('workspaceitems', selfUrl, null, options, collectionId);
});
});
describe('depositSubmission', () => {
it('should deposit submission', () => {
const options: HttpOptions = Object.create({});

View File

@@ -113,6 +113,24 @@ export class SubmissionService {
catchError(() => observableOf({} as SubmissionObject)))
}
/**
* Perform a REST call to deposit a workspaceitem and return response
*
* @param selfUrl
* The workspaceitem self url
* @param collectionId
* Optional collection id
* @return Observable<SubmissionObject>
* observable of SubmissionObject
*/
createSubmissionFromExternalSource(selfUrl: string, collectionId?: string): Observable<SubmissionObject[]> {
const options: HttpOptions = Object.create({});
let headers = new HttpHeaders();
headers = headers.append('Content-Type', 'text/uri-list');
options.headers = headers;
return this.restService.postToEndpoint(this.workspaceLinkPath, selfUrl, null, options, collectionId) as Observable<SubmissionObject[]>;
}
/**
* Perform a REST call to deposit a workspaceitem and return response
*

View File

@@ -2432,6 +2432,10 @@
"submission.import-external.preview.button.import": "Start submission",
"submission.import-external.preview.error.import.title": "Submission error",
"submission.import-external.preview.error.import.body": "An error occurs during the external source entry import process.",
"submission.sections.describe.relationship-lookup.close": "Close",