TSK-1349: Added test for import-export
This commit is contained in:
parent
fc6d6b908a
commit
8cbbab4050
|
@ -10,7 +10,7 @@
|
|||
</button>
|
||||
|
||||
<taskana-administration-import-export
|
||||
class ="btn-group" [currentSelection]="taskanaType.CLASSIFICATIONS">
|
||||
class="btn-group" [currentSelection]="taskanaType.CLASSIFICATIONS">
|
||||
</taskana-administration-import-export>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
<button type="button" [ngClass]="{disabled: uploadservice?.isInUse}" (click)="selectedFile.click()" data-toggle="tooltip" title="Import" class="btn btn-default">
|
||||
<button type="button" [ngClass]="{disabled: uploadService?.isInUse}" (click)="selectedFile.click()" data-toggle="tooltip" title="Import" class="btn btn-default">
|
||||
<span class="material-icons md-20 green-blue">cloud_upload</span>
|
||||
</button>
|
||||
<form class="hidden" id="upload_form" enctype="multipart/form-data" method="post">
|
||||
|
@ -18,6 +18,6 @@
|
|||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<button [ngClass]="{disabled: uploadservice?.isInUse}" type="button" data-toggle="dropdown" title="Export" class="btn btn-default">
|
||||
<button [ngClass]="{disabled: uploadService?.isInUse}" type="button" data-toggle="dropdown" title="Export" class="btn btn-default">
|
||||
<span class="material-icons md-20 red">cloud_download</span>
|
||||
</button>
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { ImportExportComponent } from './import-export.component';
|
||||
import { StartupService } from '../../../shared/services/startup/startup.service';
|
||||
import { TaskanaEngineService } from '../../../shared/services/taskana-engine/taskana-engine.service';
|
||||
import { WindowRefService } from '../../../shared/services/window/window.service';
|
||||
import { DomainService } from '../../../shared/services/domain/domain.service';
|
||||
import { WorkbasketDefinitionService } from '../../services/workbasket-definition.service';
|
||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||
import { UploadService } from '../../../shared/services/upload/upload.service';
|
||||
import { ImportExportService } from '../../services/import-export.service';
|
||||
import { HttpClient, HttpHandler } from '@angular/common/http';
|
||||
import { Router } from '@angular/router';
|
||||
import { of } from 'rxjs';
|
||||
import { ClassificationDefinitionService } from '../../services/classification-definition.service';
|
||||
import { take, timeout } from 'rxjs/operators';
|
||||
import { TaskanaType } from '../../../shared/models/taskana-type';
|
||||
import { BlobGenerator } from '../../../shared/util/blob-generator';
|
||||
jest.mock('../../../shared/util/blob-generator');
|
||||
|
||||
describe('ImportExportComponent', () => {
|
||||
let fixture: ComponentFixture<ImportExportComponent>;
|
||||
let debugElement: DebugElement;
|
||||
let app: ImportExportComponent;
|
||||
|
||||
const domainServiceSpy = jest.fn().mockImplementation(
|
||||
(): Partial<DomainService> => ({
|
||||
getSelectedDomainValue: jest.fn().mockReturnValue(of()),
|
||||
getSelectedDomain: jest.fn().mockReturnValue(of()),
|
||||
getDomains: jest.fn().mockReturnValue(of())
|
||||
})
|
||||
);
|
||||
|
||||
const httpSpy = jest.fn().mockImplementation(
|
||||
(): Partial<HttpClient> => ({
|
||||
get: jest.fn().mockReturnValue(of([])),
|
||||
post: jest.fn().mockReturnValue(of([]))
|
||||
})
|
||||
);
|
||||
|
||||
const showDialogFn = jest.fn().mockReturnValue(true);
|
||||
const notificationServiceSpy = jest.fn().mockImplementation(
|
||||
(): Partial<NotificationService> => ({
|
||||
showDialog: showDialogFn,
|
||||
showToast: showDialogFn,
|
||||
triggerError: showDialogFn
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [],
|
||||
declarations: [ImportExportComponent],
|
||||
providers: [
|
||||
StartupService,
|
||||
TaskanaEngineService,
|
||||
WindowRefService,
|
||||
WorkbasketDefinitionService,
|
||||
ClassificationDefinitionService,
|
||||
UploadService,
|
||||
ImportExportService,
|
||||
{ provide: DomainService, useClass: domainServiceSpy },
|
||||
{ provide: NotificationService, useClass: notificationServiceSpy },
|
||||
{ provide: HttpClient, useClass: httpSpy }
|
||||
]
|
||||
}).compileComponents();
|
||||
|
||||
jest.clearAllMocks();
|
||||
|
||||
fixture = TestBed.createComponent(ImportExportComponent);
|
||||
debugElement = fixture.debugElement;
|
||||
app = fixture.debugElement.componentInstance;
|
||||
app.currentSelection = TaskanaType.WORKBASKETS;
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
|
||||
it('should successfully upload a valid file', () => {
|
||||
app.selectedFileInput = {
|
||||
nativeElement: {
|
||||
files: [
|
||||
{
|
||||
lastModified: 1599117374674,
|
||||
name: 'Workbaskets_2020-09-03T09_16_14.1414Z.json',
|
||||
size: 59368,
|
||||
type: 'application/json',
|
||||
webkitRelativePath: ''
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
app.uploadFile();
|
||||
expect(app.uploadService.isInUse).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should successfully export the classifications', async (done) => {
|
||||
app
|
||||
.export()
|
||||
.pipe(take(1))
|
||||
.subscribe(() => {
|
||||
expect(BlobGenerator.saveFile).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,14 +1,17 @@
|
|||
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||
import { ClassificationDefinitionService } from 'app/administration/services/classification-definition.service';
|
||||
import { WorkbasketDefinitionService } from 'app/administration/services/workbasket-definition.service';
|
||||
import { DomainService } from 'app/shared/services/domain/domain.service';
|
||||
import { TaskanaType } from 'app/shared/models/taskana-type';
|
||||
import { environment } from 'environments/environment';
|
||||
import { UploadService } from 'app/shared/services/upload/upload.service';
|
||||
import { ImportExportService } from 'app/administration/services/import-export.service';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
|
||||
import { Observable } from 'rxjs';
|
||||
import { TaskanaType } from '../../../shared/models/taskana-type';
|
||||
import { DomainService } from '../../../shared/services/domain/domain.service';
|
||||
import { WorkbasketDefinitionService } from '../../services/workbasket-definition.service';
|
||||
import { ClassificationDefinitionService } from '../../services/classification-definition.service';
|
||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||
import { UploadService } from '../../../shared/services/upload/upload.service';
|
||||
import { ImportExportService } from '../../services/import-export.service';
|
||||
import { WorkbasketDefinition } from '../../../shared/models/workbasket-definition';
|
||||
import { Classification } from '../../../shared/models/classification';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-administration-import-export',
|
||||
|
@ -29,7 +32,7 @@ export class ImportExportComponent implements OnInit {
|
|||
private workbasketDefinitionService: WorkbasketDefinitionService,
|
||||
private classificationDefinitionService: ClassificationDefinitionService,
|
||||
private notificationsService: NotificationService,
|
||||
public uploadservice: UploadService,
|
||||
public uploadService: UploadService,
|
||||
private errorsService: NotificationService,
|
||||
private importExportService: ImportExportService
|
||||
) {}
|
||||
|
@ -40,68 +43,65 @@ export class ImportExportComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
export(domain = '') {
|
||||
export(domain = ''): Observable<WorkbasketDefinition[] | Classification[]> {
|
||||
if (this.currentSelection === TaskanaType.WORKBASKETS) {
|
||||
this.workbasketDefinitionService.exportWorkbaskets(domain);
|
||||
return this.workbasketDefinitionService.exportWorkbaskets(domain);
|
||||
} else {
|
||||
this.classificationDefinitionService.exportClassifications(domain);
|
||||
return this.classificationDefinitionService.exportClassifications(domain);
|
||||
}
|
||||
}
|
||||
|
||||
uploadFile() {
|
||||
const file = this.selectedFileInput.nativeElement.files[0];
|
||||
const formdata = new FormData();
|
||||
const ajax = new XMLHttpRequest();
|
||||
console.log(this.selectedFileInput);
|
||||
const formData = new FormData();
|
||||
const xhr = new XMLHttpRequest();
|
||||
if (this.checkFormatFile(file)) {
|
||||
formdata.append('file', file);
|
||||
ajax.upload.addEventListener('progress', this.progressHandler.bind(this), false);
|
||||
ajax.addEventListener('load', this.resetProgress.bind(this), false);
|
||||
ajax.addEventListener('error', this.onFailedResponse.bind(this, ajax), false);
|
||||
ajax.onreadystatechange = this.onReadyStateChangeHandler.bind(this, ajax);
|
||||
formData.append('file', file);
|
||||
xhr.upload.addEventListener('progress', this.progressHandler.bind(this), false);
|
||||
xhr.addEventListener('load', this.resetProgress.bind(this), false);
|
||||
xhr.addEventListener('error', this.onFailedResponse.bind(this, xhr), false);
|
||||
xhr.onreadystatechange = this.onReadyStateChangeHandler.bind(this, xhr);
|
||||
if (this.currentSelection === TaskanaType.WORKBASKETS) {
|
||||
ajax.open('POST', `${environment.taskanaRestUrl}/v1/workbasket-definitions`);
|
||||
xhr.open('POST', `${environment.taskanaRestUrl}/v1/workbasket-definitions`);
|
||||
} else {
|
||||
ajax.open('POST', `${environment.taskanaRestUrl}/v1/classification-definitions`);
|
||||
xhr.open('POST', `${environment.taskanaRestUrl}/v1/classification-definitions`);
|
||||
}
|
||||
if (!environment.production) {
|
||||
ajax.setRequestHeader('Authorization', 'Basic YWRtaW46YWRtaW4=');
|
||||
xhr.setRequestHeader('Authorization', 'Basic YWRtaW46YWRtaW4=');
|
||||
}
|
||||
ajax.send(formdata);
|
||||
this.uploadservice.isInUse = true;
|
||||
this.uploadservice.setCurrentProgressValue(1);
|
||||
xhr.send(formData);
|
||||
this.uploadService.isInUse = true;
|
||||
this.uploadService.setCurrentProgressValue(1);
|
||||
}
|
||||
}
|
||||
|
||||
progressHandler(event) {
|
||||
const percent = (event.loaded / event.total) * 100;
|
||||
this.uploadservice.setCurrentProgressValue(Math.round(percent));
|
||||
this.uploadService.setCurrentProgressValue(Math.round(percent));
|
||||
}
|
||||
|
||||
private checkFormatFile(file): boolean {
|
||||
const ending = file.name.match(/\.([^.]+)$/)[1];
|
||||
let check = false;
|
||||
if (ending === 'json') {
|
||||
check = true;
|
||||
if (file.name.endsWith('json')) {
|
||||
return true;
|
||||
} else {
|
||||
file.value = '';
|
||||
this.errorsService.triggerError(NOTIFICATION_TYPES.FILE_ERR);
|
||||
return false;
|
||||
}
|
||||
return check;
|
||||
}
|
||||
|
||||
private resetProgress() {
|
||||
this.uploadservice.setCurrentProgressValue(0);
|
||||
this.uploadservice.isInUse = false;
|
||||
this.uploadService.setCurrentProgressValue(0);
|
||||
this.uploadService.isInUse = false;
|
||||
this.selectedFileInput.nativeElement.value = '';
|
||||
}
|
||||
|
||||
private onReadyStateChangeHandler(event) {
|
||||
if (event.readyState === 4 && event.status >= 400) {
|
||||
let title;
|
||||
let key: NOTIFICATION_TYPES;
|
||||
if (event.status === 401) {
|
||||
key = NOTIFICATION_TYPES.IMPORT_ERR_1;
|
||||
title = 'Import was not successful, you have no access to apply this operation.';
|
||||
} else if (event.status === 404) {
|
||||
key = NOTIFICATION_TYPES.IMPORT_ERR_2;
|
||||
} else if (event.status === 409) {
|
||||
|
@ -122,6 +122,7 @@ export class ImportExportComponent implements OnInit {
|
|||
}
|
||||
|
||||
private errorHandler(key: NOTIFICATION_TYPES, passedError?: HttpErrorResponse) {
|
||||
console.log(key, passedError);
|
||||
this.errorsService.triggerError(key, passedError);
|
||||
delete this.selectedFileInput.files;
|
||||
this.resetProgress();
|
||||
|
|
|
@ -4,6 +4,8 @@ import { TaskanaDate } from 'app/shared/util/taskana.date';
|
|||
import { BlobGenerator } from 'app/shared/util/blob-generator';
|
||||
import { Classification } from '../../shared/models/classification';
|
||||
import { StartupService } from '../../shared/services/startup/startup.service';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class ClassificationDefinitionService {
|
||||
|
@ -14,9 +16,12 @@ export class ClassificationDefinitionService {
|
|||
}
|
||||
|
||||
// GET
|
||||
async exportClassifications(domain: string) {
|
||||
exportClassifications(domain: string): Observable<Classification[]> {
|
||||
const domainRequest = domain ? '' : `?domain=${domain}`;
|
||||
const classificationDefinitions = await this.httpClient.get<Classification[]>(this.url + domainRequest).toPromise();
|
||||
BlobGenerator.saveFile(classificationDefinitions, `Classifications_${TaskanaDate.getDate()}.json`);
|
||||
const classificationDefObservable = this.httpClient.get<Classification[]>(this.url + domainRequest).pipe(take(1));
|
||||
classificationDefObservable.subscribe((classificationDefinitions) =>
|
||||
BlobGenerator.saveFile(classificationDefinitions, `Classifications_${TaskanaDate.getDate()}.json`)
|
||||
);
|
||||
return classificationDefObservable;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import { environment } from 'environments/environment';
|
|||
import { WorkbasketDefinition } from 'app/shared/models/workbasket-definition';
|
||||
import { TaskanaDate } from 'app/shared/util/taskana.date';
|
||||
import { BlobGenerator } from 'app/shared/util/blob-generator';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class WorkbasketDefinitionService {
|
||||
|
@ -12,11 +14,12 @@ export class WorkbasketDefinitionService {
|
|||
constructor(private httpClient: HttpClient) {}
|
||||
|
||||
// GET
|
||||
async exportWorkbaskets(domain: string) {
|
||||
exportWorkbaskets(domain: string): Observable<WorkbasketDefinition[]> {
|
||||
const domainRequest = domain === '' ? domain : `?domain=${domain}`;
|
||||
const workbasketDefinitions = await this.httpClient
|
||||
.get<WorkbasketDefinition[]>(this.url + domainRequest)
|
||||
.toPromise();
|
||||
BlobGenerator.saveFile(workbasketDefinitions, `Workbaskets_${TaskanaDate.getDate()}.json`);
|
||||
const workbasketDefObservable = this.httpClient.get<WorkbasketDefinition[]>(this.url + domainRequest).pipe(take(1));
|
||||
workbasketDefObservable.subscribe((workbasketDefinitions) =>
|
||||
BlobGenerator.saveFile(workbasketDefinitions, `Classifications_${TaskanaDate.getDate()}.json`)
|
||||
);
|
||||
return workbasketDefObservable;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
this.selectedRoute = value;
|
||||
});
|
||||
this.uploadingFileSubscription = this.uploadService.getCurrentProgressValue().subscribe((value) => {
|
||||
this.uploadingFileSubscription = this.uploadService.getCurrentProgressObservable().subscribe((value) => {
|
||||
this.currentProgressValue = value;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -12,7 +12,7 @@ export class UploadService {
|
|||
this.currentProgressValue.next(value);
|
||||
}
|
||||
|
||||
getCurrentProgressValue() {
|
||||
getCurrentProgressObservable(): Observable<number> {
|
||||
return this.currentProgressValue.asObservable();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue