Skip to content

Commit 88b8486

Browse files
authored
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
1 parent 827703a commit 88b8486

File tree

6 files changed

+275
-20
lines changed

6 files changed

+275
-20
lines changed

web/jest.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ module.exports = {
99
testMatch: ['**/+(*.)+(spec).+(ts)'],
1010
setupFilesAfterEnv: ['<rootDir>/src/test.ts'],
1111
collectCoverage: true,
12-
coverageReporters: ['html', 'text'],
12+
coverageReporters: ['text'],
13+
// coverageReporters: ['html', 'text'],
1314
coverageDirectory: 'coverage/taskana-web',
1415
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths || {}, {
1516
prefix: '<rootDir>/'

web/src/app/administration/components/workbasket-access-items/workbasket-access-items.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<button type="button" (click)="onSubmit()" [disabled]="action === 'COPY'" data-toggle="tooltip" title="Save" class="btn btn-default btn-primary">
77
<span class="material-icons md-20">save</span>
88
</button>
9-
<button type="button" (click)="clear()" data-toggle="tooltip" title="Undo Changes" class="btn btn-default">
9+
<button type="button" (click)="clear()" data-toggle="tooltip" title="Undo Changes" class="btn btn-default undo-button">
1010
<span class="material-icons md-20 blue">undo</span>
1111
</button>
1212
</div>
@@ -115,7 +115,7 @@ <h4 class="panel-header">{{workbasket.name}}
115115
</form>
116116

117117
<!-- ADD ACCESS ITEM -->
118-
<button type="button" (click)="addAccessItem()" data-toggle="tooltip" title="Add new access" class="btn btn-default">
118+
<button type="button" (click)="addAccessItem()" data-toggle="tooltip" title="Add new access" class="btn btn-default add-access-item">
119119
<span class="material-icons md-20 green-blue">add</span>
120120
<span>Add new access</span>
121121
</button>
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { WorkbasketAccessItemsComponent } from './workbasket-access-items.component';
3+
import { Component, DebugElement, Input } from '@angular/core';
4+
import { Actions, NgxsModule, ofActionDispatched, Store } from '@ngxs/store';
5+
import { Observable, of } from 'rxjs';
6+
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
7+
import { TypeAheadComponent } from '../../../shared/components/type-ahead/type-ahead.component';
8+
import { TypeaheadModule } from 'ngx-bootstrap';
9+
import { SavingWorkbasketService } from '../../services/saving-workbaskets.service';
10+
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
11+
import { FormsValidatorService } from '../../../shared/services/forms-validator/forms-validator.service';
12+
import { NotificationService } from '../../../shared/services/notifications/notification.service';
13+
import { WorkbasketState } from '../../../shared/store/workbasket-store/workbasket.state';
14+
import { EngineConfigurationState } from '../../../shared/store/engine-configuration-store/engine-configuration.state';
15+
import { ClassificationCategoriesService } from '../../../shared/services/classification-categories/classification-categories.service';
16+
import { HttpClientTestingModule } from '@angular/common/http/testing';
17+
import { WorkbasketService } from '../../../shared/services/workbasket/workbasket.service';
18+
import { DomainService } from '../../../shared/services/domain/domain.service';
19+
import { RouterTestingModule } from '@angular/router/testing';
20+
import { SelectedRouteService } from '../../../shared/services/selected-route/selected-route';
21+
import { StartupService } from '../../../shared/services/startup/startup.service';
22+
import { TaskanaEngineService } from '../../../shared/services/taskana-engine/taskana-engine.service';
23+
import { WindowRefService } from '../../../shared/services/window/window.service';
24+
import {
25+
workbasketAccessItemsMock,
26+
engineConfigurationMock,
27+
selectedWorkbasketMock
28+
} from '../../../shared/store/mock-data/mock-store';
29+
import {
30+
GetWorkbasketAccessItems,
31+
UpdateWorkbasketAccessItems
32+
} from '../../../shared/store/workbasket-store/workbasket.actions';
33+
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
34+
import { ACTION } from '../../../shared/models/action';
35+
import { WorkbasketAccessItems } from '../../../shared/models/workbasket-access-items';
36+
37+
@Component({ selector: 'taskana-shared-spinner', template: '' })
38+
class SpinnerStub {
39+
@Input() isRunning: boolean;
40+
@Input() positionClass: string;
41+
}
42+
43+
const savingWorkbasketServiceSpy = jest.fn().mockImplementation(
44+
(): Partial<SavingWorkbasketService> => ({
45+
triggeredAccessItemsSaving: jest.fn().mockReturnValue(of(true))
46+
})
47+
);
48+
49+
const requestInProgressServiceSpy = jest.fn().mockImplementation(
50+
(): Partial<RequestInProgressService> => ({
51+
setRequestInProgress: jest.fn()
52+
})
53+
);
54+
55+
const showDialogFn = jest.fn().mockReturnValue(true);
56+
const notificationServiceSpy = jest.fn().mockImplementation(
57+
(): Partial<NotificationService> => ({
58+
triggerError: showDialogFn,
59+
showToast: showDialogFn
60+
})
61+
);
62+
63+
const validateFormInformationFn = jest.fn().mockImplementation((): Promise<any> => Promise.resolve(true));
64+
const formValidatorServiceSpy = jest.fn().mockImplementation(
65+
(): Partial<FormsValidatorService> => ({
66+
isFieldValid: jest.fn().mockReturnValue(true),
67+
validateInputOverflow: jest.fn(),
68+
validateFormInformation: validateFormInformationFn,
69+
get inputOverflowObservable(): Observable<Map<string, boolean>> {
70+
return of(new Map<string, boolean>());
71+
}
72+
})
73+
);
74+
75+
describe('WorkbasketAccessItemsComponent', () => {
76+
let fixture: ComponentFixture<WorkbasketAccessItemsComponent>;
77+
let debugElement: DebugElement;
78+
let component: WorkbasketAccessItemsComponent;
79+
let store: Store;
80+
let actions$: Observable<any>;
81+
82+
beforeEach(async(() => {
83+
TestBed.configureTestingModule({
84+
imports: [
85+
FormsModule,
86+
ReactiveFormsModule,
87+
TypeaheadModule.forRoot(),
88+
NgxsModule.forRoot([WorkbasketState, EngineConfigurationState]),
89+
HttpClientTestingModule,
90+
RouterTestingModule.withRoutes([]),
91+
BrowserAnimationsModule
92+
],
93+
declarations: [WorkbasketAccessItemsComponent, TypeAheadComponent, SpinnerStub],
94+
providers: [
95+
{ provide: SavingWorkbasketService, useClass: savingWorkbasketServiceSpy },
96+
{ provide: RequestInProgressService, useClass: requestInProgressServiceSpy },
97+
{ provide: FormsValidatorService, useClass: formValidatorServiceSpy },
98+
{ provide: NotificationService, useClass: notificationServiceSpy },
99+
ClassificationCategoriesService,
100+
WorkbasketService,
101+
DomainService,
102+
SelectedRouteService,
103+
StartupService,
104+
TaskanaEngineService,
105+
WindowRefService
106+
]
107+
}).compileComponents();
108+
109+
fixture = TestBed.createComponent(WorkbasketAccessItemsComponent);
110+
debugElement = fixture.debugElement;
111+
component = fixture.componentInstance;
112+
store = TestBed.inject(Store);
113+
actions$ = TestBed.inject(Actions);
114+
component.workbasket = { ...selectedWorkbasketMock };
115+
component.accessItemsRepresentation = workbasketAccessItemsMock;
116+
store.reset({
117+
...store.snapshot(),
118+
engineConfiguration: engineConfigurationMock,
119+
workbasket: {
120+
workbasketAccessItems: workbasketAccessItemsMock
121+
}
122+
});
123+
fixture.detectChanges();
124+
}));
125+
126+
afterEach(async(() => {
127+
component.workbasket = { ...selectedWorkbasketMock };
128+
}));
129+
130+
it('should create component', () => {
131+
expect(component).toBeTruthy();
132+
});
133+
134+
it('should initialize when accessItems exist', async(() => {
135+
component.action = ACTION.COPY;
136+
let actionDispatched = false;
137+
component.onSave = jest.fn().mockImplementation();
138+
actions$.pipe(ofActionDispatched(GetWorkbasketAccessItems)).subscribe(() => (actionDispatched = true));
139+
component.init();
140+
expect(component.initialized).toBe(true);
141+
expect(actionDispatched).toBe(true);
142+
expect(component.onSave).toHaveBeenCalled();
143+
}));
144+
145+
it("should discard initializing when accessItems don't exist", () => {
146+
component.workbasket._links.accessItems = null;
147+
component.init();
148+
expect(component.initialized).toBe(false);
149+
});
150+
151+
it('should add accessItems when add access item button is clicked', () => {
152+
const addAccessItemButton = debugElement.nativeElement.querySelector('button.add-access-item');
153+
const clearSpy = jest.spyOn(component, 'addAccessItem');
154+
expect(addAccessItemButton.title).toMatch('Add new access');
155+
156+
addAccessItemButton.click();
157+
expect(clearSpy).toHaveBeenCalled();
158+
});
159+
160+
it('should undo changes when undo button is clicked', () => {
161+
const undoButton = debugElement.nativeElement.querySelector('button.undo-button');
162+
const clearSpy = jest.spyOn(component, 'clear');
163+
expect(undoButton.title).toMatch('Undo Changes');
164+
165+
undoButton.click();
166+
expect(clearSpy).toHaveBeenCalled();
167+
});
168+
169+
it('should check all permissions when check all box is checked', () => {
170+
const checkAllSpy = jest.spyOn(component, 'checkAll');
171+
const checkAllButton = debugElement.nativeElement.querySelector('#checkbox-0-00');
172+
expect(checkAllButton).toBeTruthy();
173+
174+
checkAllButton.click();
175+
expect(checkAllSpy).toHaveBeenCalled();
176+
});
177+
178+
it('should dispatch UpdateWorkbasketAccessItems action when save button is triggered', () => {
179+
component.accessItemsRepresentation._links.self.href = 'https://link.mock';
180+
const onSaveSpy = jest.spyOn(component, 'onSave');
181+
let actionDispatched = false;
182+
actions$.pipe(ofActionDispatched(UpdateWorkbasketAccessItems)).subscribe(() => (actionDispatched = true));
183+
component.onSave();
184+
expect(onSaveSpy).toHaveBeenCalled();
185+
expect(actionDispatched).toBe(true);
186+
});
187+
188+
it('should set badge correctly', () => {
189+
component.action = ACTION.READ;
190+
component.setBadge();
191+
expect(component.badgeMessage).toMatch('');
192+
193+
component.action = ACTION.COPY;
194+
component.setBadge();
195+
expect(component.badgeMessage).toMatch(`Copying workbasket: ${component.workbasket.key}`);
196+
});
197+
});

web/src/app/administration/components/workbasket-access-items/workbasket-access-items.component.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
7878
accessItemsRepresentation$: Observable<WorkbasketAccessItemsRepresentation>;
7979

8080
constructor(
81-
private workbasketService: WorkbasketService,
8281
private savingWorkbaskets: SavingWorkbasketService,
8382
private requestInProgressService: RequestInProgressService,
8483
private formBuilder: FormBuilder,
@@ -111,7 +110,7 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
111110
});
112111
}
113112

114-
ngOnChanges(changes: SimpleChanges) {
113+
ngOnChanges(changes?: SimpleChanges) {
115114
if (!this.initialized && changes.active && changes.active.currentValue === 'accessItems') {
116115
this.init();
117116
}
@@ -125,7 +124,7 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
125124
}
126125
}
127126

128-
private init() {
127+
init() {
129128
if (!this.workbasket._links.accessItems) {
130129
return;
131130
}
@@ -243,7 +242,7 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
243242
this.accessItemsGroups.controls[row].get('accessName').setValue(accessItem.name);
244243
}
245244

246-
private onSave() {
245+
onSave() {
247246
this.requestInProgressService.setRequestInProgress(true);
248247
this.store
249248
.dispatch(
@@ -257,19 +256,19 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
257256
});
258257
}
259258

260-
private setBadge() {
259+
setBadge() {
261260
if (this.action === ACTION.COPY) {
262261
this.badgeMessage = `Copying workbasket: ${this.workbasket.key}`;
263262
}
264263
}
265264

266-
private cloneAccessItems(inputaccessItem): Array<WorkbasketAccessItems> {
265+
cloneAccessItems(inputaccessItem): Array<WorkbasketAccessItems> {
267266
return this.AccessItemsForm.value.accessItemsGroups.map((accessItems: WorkbasketAccessItems) => ({
268267
...accessItems
269268
}));
270269
}
271270

272-
private setWorkbasketIdForCopy(workbasketId: string) {
271+
setWorkbasketIdForCopy(workbasketId: string) {
273272
this.accessItemsGroups.value.forEach((element) => {
274273
delete element.accessItemId;
275274
element.workbasketId = workbasketId;

web/src/app/shared/models/workbasket-access-items.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export interface WorkbasketAccessItems {
2323
permCustom10: boolean;
2424
permCustom11: boolean;
2525
permCustom12: boolean;
26-
_links: Links;
26+
_links?: Links;
2727
}
2828

2929
export const customFieldCount: number = 12;

0 commit comments

Comments
 (0)