TSK-1349: Workbasket access items unit tests (#1246)

* TSK-1349: remove html coverage to optimize test speed

* TSK-1349: init workbasket access items testing env

* TSK-1349: update workbasket access items unit tests
This commit is contained in:
Chi Nguyen 2020-09-02 11:03:59 +02:00 committed by GitHub
parent 827703a176
commit 88b8486a49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 275 additions and 20 deletions

View File

@ -9,7 +9,8 @@ module.exports = {
testMatch: ['**/+(*.)+(spec).+(ts)'],
setupFilesAfterEnv: ['<rootDir>/src/test.ts'],
collectCoverage: true,
coverageReporters: ['html', 'text'],
coverageReporters: ['text'],
// coverageReporters: ['html', 'text'],
coverageDirectory: 'coverage/taskana-web',
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths || {}, {
prefix: '<rootDir>/'

View File

@ -6,7 +6,7 @@
<button type="button" (click)="onSubmit()" [disabled]="action === 'COPY'" data-toggle="tooltip" title="Save" class="btn btn-default btn-primary">
<span class="material-icons md-20">save</span>
</button>
<button type="button" (click)="clear()" data-toggle="tooltip" title="Undo Changes" class="btn btn-default">
<button type="button" (click)="clear()" data-toggle="tooltip" title="Undo Changes" class="btn btn-default undo-button">
<span class="material-icons md-20 blue">undo</span>
</button>
</div>
@ -115,7 +115,7 @@
</form>
<!-- ADD ACCESS ITEM -->
<button type="button" (click)="addAccessItem()" data-toggle="tooltip" title="Add new access" class="btn btn-default">
<button type="button" (click)="addAccessItem()" data-toggle="tooltip" title="Add new access" class="btn btn-default add-access-item">
<span class="material-icons md-20 green-blue">add</span>
<span>Add new access</span>
</button>

View File

@ -0,0 +1,197 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { WorkbasketAccessItemsComponent } from './workbasket-access-items.component';
import { Component, DebugElement, Input } from '@angular/core';
import { Actions, NgxsModule, ofActionDispatched, Store } from '@ngxs/store';
import { Observable, of } from 'rxjs';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TypeAheadComponent } from '../../../shared/components/type-ahead/type-ahead.component';
import { TypeaheadModule } from 'ngx-bootstrap';
import { SavingWorkbasketService } from '../../services/saving-workbaskets.service';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
import { FormsValidatorService } from '../../../shared/services/forms-validator/forms-validator.service';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { WorkbasketState } from '../../../shared/store/workbasket-store/workbasket.state';
import { EngineConfigurationState } from '../../../shared/store/engine-configuration-store/engine-configuration.state';
import { ClassificationCategoriesService } from '../../../shared/services/classification-categories/classification-categories.service';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { WorkbasketService } from '../../../shared/services/workbasket/workbasket.service';
import { DomainService } from '../../../shared/services/domain/domain.service';
import { RouterTestingModule } from '@angular/router/testing';
import { SelectedRouteService } from '../../../shared/services/selected-route/selected-route';
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 {
workbasketAccessItemsMock,
engineConfigurationMock,
selectedWorkbasketMock
} from '../../../shared/store/mock-data/mock-store';
import {
GetWorkbasketAccessItems,
UpdateWorkbasketAccessItems
} from '../../../shared/store/workbasket-store/workbasket.actions';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ACTION } from '../../../shared/models/action';
import { WorkbasketAccessItems } from '../../../shared/models/workbasket-access-items';
@Component({ selector: 'taskana-shared-spinner', template: '' })
class SpinnerStub {
@Input() isRunning: boolean;
@Input() positionClass: string;
}
const savingWorkbasketServiceSpy = jest.fn().mockImplementation(
(): Partial<SavingWorkbasketService> => ({
triggeredAccessItemsSaving: jest.fn().mockReturnValue(of(true))
})
);
const requestInProgressServiceSpy = jest.fn().mockImplementation(
(): Partial<RequestInProgressService> => ({
setRequestInProgress: jest.fn()
})
);
const showDialogFn = jest.fn().mockReturnValue(true);
const notificationServiceSpy = jest.fn().mockImplementation(
(): Partial<NotificationService> => ({
triggerError: showDialogFn,
showToast: showDialogFn
})
);
const validateFormInformationFn = jest.fn().mockImplementation((): Promise<any> => Promise.resolve(true));
const formValidatorServiceSpy = jest.fn().mockImplementation(
(): Partial<FormsValidatorService> => ({
isFieldValid: jest.fn().mockReturnValue(true),
validateInputOverflow: jest.fn(),
validateFormInformation: validateFormInformationFn,
get inputOverflowObservable(): Observable<Map<string, boolean>> {
return of(new Map<string, boolean>());
}
})
);
describe('WorkbasketAccessItemsComponent', () => {
let fixture: ComponentFixture<WorkbasketAccessItemsComponent>;
let debugElement: DebugElement;
let component: WorkbasketAccessItemsComponent;
let store: Store;
let actions$: Observable<any>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
FormsModule,
ReactiveFormsModule,
TypeaheadModule.forRoot(),
NgxsModule.forRoot([WorkbasketState, EngineConfigurationState]),
HttpClientTestingModule,
RouterTestingModule.withRoutes([]),
BrowserAnimationsModule
],
declarations: [WorkbasketAccessItemsComponent, TypeAheadComponent, SpinnerStub],
providers: [
{ provide: SavingWorkbasketService, useClass: savingWorkbasketServiceSpy },
{ provide: RequestInProgressService, useClass: requestInProgressServiceSpy },
{ provide: FormsValidatorService, useClass: formValidatorServiceSpy },
{ provide: NotificationService, useClass: notificationServiceSpy },
ClassificationCategoriesService,
WorkbasketService,
DomainService,
SelectedRouteService,
StartupService,
TaskanaEngineService,
WindowRefService
]
}).compileComponents();
fixture = TestBed.createComponent(WorkbasketAccessItemsComponent);
debugElement = fixture.debugElement;
component = fixture.componentInstance;
store = TestBed.inject(Store);
actions$ = TestBed.inject(Actions);
component.workbasket = { ...selectedWorkbasketMock };
component.accessItemsRepresentation = workbasketAccessItemsMock;
store.reset({
...store.snapshot(),
engineConfiguration: engineConfigurationMock,
workbasket: {
workbasketAccessItems: workbasketAccessItemsMock
}
});
fixture.detectChanges();
}));
afterEach(async(() => {
component.workbasket = { ...selectedWorkbasketMock };
}));
it('should create component', () => {
expect(component).toBeTruthy();
});
it('should initialize when accessItems exist', async(() => {
component.action = ACTION.COPY;
let actionDispatched = false;
component.onSave = jest.fn().mockImplementation();
actions$.pipe(ofActionDispatched(GetWorkbasketAccessItems)).subscribe(() => (actionDispatched = true));
component.init();
expect(component.initialized).toBe(true);
expect(actionDispatched).toBe(true);
expect(component.onSave).toHaveBeenCalled();
}));
it("should discard initializing when accessItems don't exist", () => {
component.workbasket._links.accessItems = null;
component.init();
expect(component.initialized).toBe(false);
});
it('should add accessItems when add access item button is clicked', () => {
const addAccessItemButton = debugElement.nativeElement.querySelector('button.add-access-item');
const clearSpy = jest.spyOn(component, 'addAccessItem');
expect(addAccessItemButton.title).toMatch('Add new access');
addAccessItemButton.click();
expect(clearSpy).toHaveBeenCalled();
});
it('should undo changes when undo button is clicked', () => {
const undoButton = debugElement.nativeElement.querySelector('button.undo-button');
const clearSpy = jest.spyOn(component, 'clear');
expect(undoButton.title).toMatch('Undo Changes');
undoButton.click();
expect(clearSpy).toHaveBeenCalled();
});
it('should check all permissions when check all box is checked', () => {
const checkAllSpy = jest.spyOn(component, 'checkAll');
const checkAllButton = debugElement.nativeElement.querySelector('#checkbox-0-00');
expect(checkAllButton).toBeTruthy();
checkAllButton.click();
expect(checkAllSpy).toHaveBeenCalled();
});
it('should dispatch UpdateWorkbasketAccessItems action when save button is triggered', () => {
component.accessItemsRepresentation._links.self.href = 'https://link.mock';
const onSaveSpy = jest.spyOn(component, 'onSave');
let actionDispatched = false;
actions$.pipe(ofActionDispatched(UpdateWorkbasketAccessItems)).subscribe(() => (actionDispatched = true));
component.onSave();
expect(onSaveSpy).toHaveBeenCalled();
expect(actionDispatched).toBe(true);
});
it('should set badge correctly', () => {
component.action = ACTION.READ;
component.setBadge();
expect(component.badgeMessage).toMatch('');
component.action = ACTION.COPY;
component.setBadge();
expect(component.badgeMessage).toMatch(`Copying workbasket: ${component.workbasket.key}`);
});
});

View File

@ -78,7 +78,6 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
accessItemsRepresentation$: Observable<WorkbasketAccessItemsRepresentation>;
constructor(
private workbasketService: WorkbasketService,
private savingWorkbaskets: SavingWorkbasketService,
private requestInProgressService: RequestInProgressService,
private formBuilder: FormBuilder,
@ -111,7 +110,7 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
});
}
ngOnChanges(changes: SimpleChanges) {
ngOnChanges(changes?: SimpleChanges) {
if (!this.initialized && changes.active && changes.active.currentValue === 'accessItems') {
this.init();
}
@ -125,7 +124,7 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
}
}
private init() {
init() {
if (!this.workbasket._links.accessItems) {
return;
}
@ -243,7 +242,7 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
this.accessItemsGroups.controls[row].get('accessName').setValue(accessItem.name);
}
private onSave() {
onSave() {
this.requestInProgressService.setRequestInProgress(true);
this.store
.dispatch(
@ -257,19 +256,19 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
});
}
private setBadge() {
setBadge() {
if (this.action === ACTION.COPY) {
this.badgeMessage = `Copying workbasket: ${this.workbasket.key}`;
}
}
private cloneAccessItems(inputaccessItem): Array<WorkbasketAccessItems> {
cloneAccessItems(inputaccessItem): Array<WorkbasketAccessItems> {
return this.AccessItemsForm.value.accessItemsGroups.map((accessItems: WorkbasketAccessItems) => ({
...accessItems
}));
}
private setWorkbasketIdForCopy(workbasketId: string) {
setWorkbasketIdForCopy(workbasketId: string) {
this.accessItemsGroups.value.forEach((element) => {
delete element.accessItemId;
element.workbasketId = workbasketId;

View File

@ -23,7 +23,7 @@ export interface WorkbasketAccessItems {
permCustom10: boolean;
permCustom11: boolean;
permCustom12: boolean;
_links: Links;
_links?: Links;
}
export const customFieldCount: number = 12;

View File

@ -1,6 +1,7 @@
import { Workbasket } from '../../models/workbasket';
import { ICONTYPES } from '../../models/icon-types';
import { ACTION } from '../../models/action';
import { WorkbasketAccessItemsRepresentation } from '../../models/workbasket-access-items-representation';
export const classificationStateMock = {
selectedClassificationType: 'DOCUMENT',
@ -13,14 +14,6 @@ export const classificationStateMock = {
export const engineConfigurationMock = {
customisation: {
EN: {
classifications: {
categories: {
EXTERNAL: 'assets/icons/categories/external.svg',
MANUAL: 'assets/icons/categories/manual.svg',
AUTOMATIC: 'assets/icons/categories/automatic.svg',
missing: 'assets/icons/categories/missing-icon.svg'
}
},
workbaskets: {
information: {
owner: {
@ -60,6 +53,32 @@ export const engineConfigurationMock = {
visible: false
}
}
},
classifications: {
information: {
custom1: {
field: 'Classification custom 1',
visible: true
},
custom3: {
field: '',
visible: false
}
},
categories: {
EXTERNAL: 'assets/icons/categories/external.svg',
MANUAL: 'assets/icons/categories/manual.svg',
AUTOMATIC: 'assets/icons/categories/automatic.svg',
PROCESS: 'assets/icons/categories/process.svg',
missing: 'assets/icons/categories/missing-icon.svg'
}
},
tasks: {
information: {
owner: {
lookupField: true
}
}
}
}
},
@ -107,6 +126,44 @@ export const selectedWorkbasketMock: Workbasket = {
}
};
export const workbasketAccessItemsMock: WorkbasketAccessItemsRepresentation = {
accessItems: [
{
accessItemId: 'WBI:000000000000000000000000000000000901',
workbasketId: 'WBI:000000000000000000000000000000000901',
workbasketKey: 'Sort002',
accessId: 'user-b-1',
accessName: 'Bern, Bernd',
permRead: true,
permOpen: true,
permAppend: true,
permTransfer: true,
permDistribute: true,
permCustom1: true,
permCustom2: true,
permCustom3: true,
permCustom4: true,
permCustom5: true,
permCustom6: true,
permCustom7: true,
permCustom8: true,
permCustom9: true,
permCustom10: true,
permCustom11: true,
permCustom12: true
}
],
_links: {
self: {
href:
'http://localhost:8080/taskana/api/v1/workbaskets/WBI:000000000000000000000000000000000901/workbasketAccessItems'
},
workbasket: {
href: 'http://localhost:8080/taskana/api/v1/workbaskets/WBI:000000000000000000000000000000000901'
}
}
};
export const workbasketReadStateMock = {
selectedWorkbasket: selectedWorkbasketMock,
paginatedWorkbasketsSummary: {
@ -227,5 +284,6 @@ export const workbasketReadStateMock = {
number: 3
}
},
action: ACTION.READ
action: ACTION.READ,
workbasketAccessItems: workbasketAccessItemsMock
};