mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
83707: Implement tests
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { ContentSource } from '../../../../core/shared/content-source.model';
|
||||
import { Collection } from '../../../../core/shared/collection.model';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||
import { CollectionDataService } from '../../../../core/data/collection-data.service';
|
||||
import { RequestService } from '../../../../core/data/request.service';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { ProcessDataService } from '../../../../core/data/processes/process-data.service';
|
||||
import { ScriptDataService } from '../../../../core/data/processes/script-data.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
|
||||
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
|
||||
import { Process } from '../../../../process-page/processes/process.model';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { CollectionSourceControlsComponent } from './collection-source-controls.component';
|
||||
import { Bitstream } from '../../../../core/shared/bitstream.model';
|
||||
import { getTestScheduler } from 'jasmine-marbles';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { VarDirective } from '../../../../shared/utils/var.directive';
|
||||
|
||||
describe('CollectionSourceControlsComponent', () => {
|
||||
let comp: CollectionSourceControlsComponent;
|
||||
let fixture: ComponentFixture<CollectionSourceControlsComponent>;
|
||||
|
||||
const uuid = '29481ed7-ae6b-409a-8c51-34dd347a0ce4';
|
||||
let contentSource: ContentSource;
|
||||
let collection: Collection;
|
||||
let process: Process;
|
||||
let bitstream: Bitstream;
|
||||
|
||||
let scriptDataService: ScriptDataService;
|
||||
let processDataService: ProcessDataService;
|
||||
let requestService: RequestService;
|
||||
let notificationsService;
|
||||
let collectionService: CollectionDataService;
|
||||
let httpClient: HttpClient;
|
||||
let bitstreamService: BitstreamDataService;
|
||||
let scheduler: TestScheduler;
|
||||
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
scheduler = getTestScheduler();
|
||||
contentSource = Object.assign(new ContentSource(), {
|
||||
uuid: uuid,
|
||||
metadataConfigs: [
|
||||
{
|
||||
id: 'dc',
|
||||
label: 'Simple Dublin Core',
|
||||
nameSpace: 'http://www.openarchives.org/OAI/2.0/oai_dc/'
|
||||
},
|
||||
{
|
||||
id: 'qdc',
|
||||
label: 'Qualified Dublin Core',
|
||||
nameSpace: 'http://purl.org/dc/terms/'
|
||||
},
|
||||
{
|
||||
id: 'dim',
|
||||
label: 'DSpace Intermediate Metadata',
|
||||
nameSpace: 'http://www.dspace.org/xmlns/dspace/dim'
|
||||
}
|
||||
],
|
||||
oaiSource: 'oai-harvest-source',
|
||||
oaiSetId: 'oai-set-id',
|
||||
_links: {self: {href: 'contentsource-selflink'}}
|
||||
});
|
||||
process = Object.assign(new Process(), {
|
||||
processId: 'process-id', processStatus: 'COMPLETED',
|
||||
_links: {output: {href: 'output-href'}}
|
||||
});
|
||||
|
||||
bitstream = Object.assign(new Bitstream(), {_links: {content: {href: 'content-href'}}});
|
||||
|
||||
collection = Object.assign(new Collection(), {
|
||||
uuid: 'fake-collection-id',
|
||||
_links: {self: {href: 'collection-selflink'}}
|
||||
});
|
||||
notificationsService = new NotificationsServiceStub();
|
||||
collectionService = jasmine.createSpyObj('collectionService', {
|
||||
getContentSource: createSuccessfulRemoteDataObject$(contentSource),
|
||||
findByHref: createSuccessfulRemoteDataObject$(collection)
|
||||
});
|
||||
scriptDataService = jasmine.createSpyObj('scriptDataService', {
|
||||
invoke: createSuccessfulRemoteDataObject$(process),
|
||||
});
|
||||
processDataService = jasmine.createSpyObj('processDataService', {
|
||||
findById: createSuccessfulRemoteDataObject$(process),
|
||||
});
|
||||
bitstreamService = jasmine.createSpyObj('bitstreamService', {
|
||||
findByHref: createSuccessfulRemoteDataObject$(bitstream),
|
||||
});
|
||||
httpClient = jasmine.createSpyObj('httpClient', {
|
||||
get: observableOf('Script text'),
|
||||
});
|
||||
requestService = jasmine.createSpyObj('requestService', ['removeByHrefSubstring', 'setStaleByHrefSubstring']);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), RouterTestingModule],
|
||||
declarations: [CollectionSourceControlsComponent, VarDirective],
|
||||
providers: [
|
||||
{provide: ScriptDataService, useValue: scriptDataService},
|
||||
{provide: ProcessDataService, useValue: processDataService},
|
||||
{provide: RequestService, useValue: requestService},
|
||||
{provide: NotificationsService, useValue: notificationsService},
|
||||
{provide: CollectionDataService, useValue: collectionService},
|
||||
{provide: HttpClient, useValue: httpClient},
|
||||
{provide: BitstreamDataService, useValue: bitstreamService}
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
}));
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CollectionSourceControlsComponent);
|
||||
comp = fixture.componentInstance;
|
||||
comp.isEnabled = true;
|
||||
comp.collection = collection;
|
||||
comp.shouldShow = true;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
describe('init', () => {
|
||||
it('should', () => {
|
||||
expect(comp).toBeTruthy();
|
||||
});
|
||||
});
|
||||
describe('testConfiguration', () => {
|
||||
it('should invoke a script and ping the resulting process until completed and show the resulting info', () => {
|
||||
comp.testConfiguration(contentSource);
|
||||
scheduler.flush();
|
||||
|
||||
expect(scriptDataService.invoke).toHaveBeenCalledWith('harvest', [
|
||||
{name: '-g', value: null},
|
||||
{name: '-a', value: contentSource.oaiSource},
|
||||
{name: '-i', value: contentSource.oaiSetId},
|
||||
], []);
|
||||
|
||||
expect(processDataService.findById).toHaveBeenCalledWith(process.processId, false);
|
||||
expect(bitstreamService.findByHref).toHaveBeenCalledWith(process._links.output.href);
|
||||
expect(notificationsService.info).toHaveBeenCalledWith(jasmine.anything() as any, 'Script text');
|
||||
});
|
||||
});
|
||||
describe('importNow', () => {
|
||||
it('should invoke a script that will start the harvest', () => {
|
||||
comp.importNow();
|
||||
scheduler.flush();
|
||||
|
||||
expect(scriptDataService.invoke).toHaveBeenCalledWith('harvest', [
|
||||
{name: '-r', value: null},
|
||||
{name: '-e', value: 'dspacedemo+admin@gmail.com'},
|
||||
{name: '-c', value: collection.uuid},
|
||||
], []);
|
||||
expect(processDataService.findById).toHaveBeenCalledWith(process.processId, false);
|
||||
expect(notificationsService.success).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
describe('the controls', () => {
|
||||
it('should be shown when shouldShow is true', () => {
|
||||
comp.shouldShow = true;
|
||||
fixture.detectChanges();
|
||||
const buttons = fixture.debugElement.queryAll(By.css('button'));
|
||||
expect(buttons.length).toEqual(3);
|
||||
});
|
||||
it('should be shown when shouldShow is false', () => {
|
||||
comp.shouldShow = false;
|
||||
fixture.detectChanges();
|
||||
const buttons = fixture.debugElement.queryAll(By.css('button'));
|
||||
expect(buttons.length).toEqual(0);
|
||||
});
|
||||
it('should be disabled when isEnabled is false', () => {
|
||||
comp.shouldShow = true;
|
||||
comp.isEnabled = false;
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const buttons = fixture.debugElement.queryAll(By.css('button'));
|
||||
|
||||
expect(buttons[0].nativeElement.disabled).toBeTrue();
|
||||
expect(buttons[1].nativeElement.disabled).toBeTrue();
|
||||
expect(buttons[2].nativeElement.disabled).toBeTrue();
|
||||
});
|
||||
it('should be enabled when isEnabled is true', () => {
|
||||
comp.shouldShow = true;
|
||||
comp.isEnabled = true;
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const buttons = fixture.debugElement.queryAll(By.css('button'));
|
||||
|
||||
expect(buttons[0].nativeElement.disabled).toBeFalse();
|
||||
expect(buttons[1].nativeElement.disabled).toBeFalse();
|
||||
expect(buttons[2].nativeElement.disabled).toBeFalse();
|
||||
});
|
||||
it('should call the corresponding button when clicked', () => {
|
||||
spyOn(comp, 'testConfiguration');
|
||||
spyOn(comp, 'importNow');
|
||||
spyOn(comp, 'resetAndReimport');
|
||||
|
||||
comp.shouldShow = true;
|
||||
comp.isEnabled = true;
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const buttons = fixture.debugElement.queryAll(By.css('button'));
|
||||
|
||||
buttons[0].triggerEventHandler('click', null);
|
||||
expect(comp.testConfiguration).toHaveBeenCalled();
|
||||
|
||||
buttons[1].triggerEventHandler('click', null);
|
||||
expect(comp.importNow).toHaveBeenCalled();
|
||||
|
||||
buttons[2].triggerEventHandler('click', null);
|
||||
expect(comp.resetAndReimport).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
@@ -22,14 +22,28 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
|
||||
|
||||
/**
|
||||
* Component that contains the controls to run, reset and test the harvest
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-collection-source-controls',
|
||||
templateUrl: './collection-source-controls.component.html',
|
||||
})
|
||||
export class CollectionSourceControlsComponent implements OnDestroy {
|
||||
|
||||
/**
|
||||
* Should the controls be enabled.
|
||||
*/
|
||||
@Input() isEnabled: boolean;
|
||||
|
||||
/**
|
||||
* The current collection
|
||||
*/
|
||||
@Input() collection: Collection;
|
||||
|
||||
/**
|
||||
* Should the control section be shown
|
||||
*/
|
||||
@Input() shouldShow: boolean;
|
||||
|
||||
contentSource$: Observable<ContentSource>;
|
||||
@@ -47,6 +61,7 @@ export class CollectionSourceControlsComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
// ensure the contentSource gets updated after being set to stale
|
||||
this.contentSource$ = this.collectionService.findByHref(this.collection._links.self.href, false).pipe(
|
||||
getAllSucceededRemoteDataPayload(),
|
||||
switchMap((collection) => this.collectionService.getContentSource(collection.uuid, false)),
|
||||
@@ -54,6 +69,10 @@ export class CollectionSourceControlsComponent implements OnDestroy {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the provided content source's configuration.
|
||||
* @param contentSource - The content source to be tested
|
||||
*/
|
||||
testConfiguration(contentSource) {
|
||||
this.subs.push(this.scriptDataService.invoke('harvest', [
|
||||
{name: '-g', value: null},
|
||||
@@ -63,9 +82,11 @@ export class CollectionSourceControlsComponent implements OnDestroy {
|
||||
getFirstCompletedRemoteData(),
|
||||
tap((rd) => {
|
||||
if (rd.hasFailed) {
|
||||
// show a notification when the script invocation fails
|
||||
this.notificationsService.error(this.translateService.get('collection.source.controls.test.submit.error'));
|
||||
}
|
||||
}),
|
||||
// filter out responses that aren't successful since the pinging of the process only needs to happen when the invocation was successful.
|
||||
filter((rd) => rd.hasSucceeded && hasValue(rd.payload)),
|
||||
switchMap((rd) => this.processDataService.findById(rd.payload.processId, false)),
|
||||
getAllCompletedRemoteData(),
|
||||
@@ -75,6 +96,7 @@ export class CollectionSourceControlsComponent implements OnDestroy {
|
||||
).subscribe((process: Process) => {
|
||||
if (process.processStatus.toString() !== ProcessStatus[ProcessStatus.COMPLETED].toString() &&
|
||||
process.processStatus.toString() !== ProcessStatus[ProcessStatus.FAILED].toString()) {
|
||||
// Ping the current process state every 5s
|
||||
setTimeout(() => {
|
||||
this.requestService.setStaleByHrefSubstring(process._links.self.href);
|
||||
}, 5000);
|
||||
@@ -83,12 +105,12 @@ export class CollectionSourceControlsComponent implements OnDestroy {
|
||||
this.notificationsService.error(this.translateService.get('collection.source.controls.test.failed'));
|
||||
}
|
||||
if (process.processStatus.toString() === ProcessStatus[ProcessStatus.COMPLETED].toString()) {
|
||||
this.bitstreamService.findByHref(process._links.output.href, false).pipe(getFirstSucceededRemoteDataPayload()).subscribe((bitstream) => {
|
||||
this.bitstreamService.findByHref(process._links.output.href).pipe(getFirstSucceededRemoteDataPayload()).subscribe((bitstream) => {
|
||||
this.httpClient.get(bitstream._links.content.href, {responseType: 'text'}).subscribe((data: any) => {
|
||||
const output = data.replaceAll(new RegExp('.*\\@(.*)', 'g'), '$1')
|
||||
.replaceAll('The script has started', '')
|
||||
.replaceAll('The script has completed', '');
|
||||
this.notificationsService.success(this.translateService.get('collection.source.controls.test.completed'), output);
|
||||
this.notificationsService.info(this.translateService.get('collection.source.controls.test.completed'), output);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -96,6 +118,9 @@ export class CollectionSourceControlsComponent implements OnDestroy {
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the harvest for the current collection
|
||||
*/
|
||||
importNow() {
|
||||
this.subs.push(this.scriptDataService.invoke('harvest', [
|
||||
{name: '-r', value: null},
|
||||
@@ -118,6 +143,7 @@ export class CollectionSourceControlsComponent implements OnDestroy {
|
||||
).subscribe((process) => {
|
||||
if (process.processStatus.toString() !== ProcessStatus[ProcessStatus.COMPLETED].toString() &&
|
||||
process.processStatus.toString() !== ProcessStatus[ProcessStatus.FAILED].toString()) {
|
||||
// Ping the current process state every 5s
|
||||
setTimeout(() => {
|
||||
this.requestService.setStaleByHrefSubstring(process._links.self.href);
|
||||
this.requestService.setStaleByHrefSubstring(this.collection._links.self.href);
|
||||
@@ -128,14 +154,15 @@ export class CollectionSourceControlsComponent implements OnDestroy {
|
||||
}
|
||||
if (process.processStatus.toString() === ProcessStatus[ProcessStatus.COMPLETED].toString()) {
|
||||
this.notificationsService.success(this.translateService.get('collection.source.controls.import.completed'));
|
||||
setTimeout(() => {
|
||||
this.requestService.setStaleByHrefSubstring(this.collection._links.self.href);
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset and reimport the current collection
|
||||
*/
|
||||
resetAndReimport() {
|
||||
// TODO implement when a single option is present
|
||||
}
|
||||
|
@@ -62,7 +62,8 @@ describe('CollectionSourceComponent', () => {
|
||||
label: 'DSpace Intermediate Metadata',
|
||||
nameSpace: 'http://www.dspace.org/xmlns/dspace/dim'
|
||||
}
|
||||
]
|
||||
],
|
||||
_links: { self: { href: 'contentsource-selflink' } }
|
||||
});
|
||||
fieldUpdate = {
|
||||
field: contentSource,
|
||||
@@ -115,7 +116,7 @@ describe('CollectionSourceComponent', () => {
|
||||
updateContentSource: observableOf(contentSource),
|
||||
getHarvesterEndpoint: observableOf('harvester-endpoint')
|
||||
});
|
||||
requestService = jasmine.createSpyObj('requestService', ['removeByHrefSubstring']);
|
||||
requestService = jasmine.createSpyObj('requestService', ['removeByHrefSubstring', 'setStaleByHrefSubstring']);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), RouterTestingModule],
|
||||
|
Reference in New Issue
Block a user