From 8a6e68d0b9e6c9c3f0d60110950cb479c7c3f17e Mon Sep 17 00:00:00 2001 From: Chi Nguyen <6671583+cnguyen-de@users.noreply.github.com> Date: Mon, 17 Aug 2020 17:35:59 +0200 Subject: [PATCH] TSK-1349: Added unit test for access items management (#1218) * TSK-1349: added unit test for access items management * TSK-1349: updated test * TSK-1349: clean up test code * TSK-1349: fixed fixture not working correctly in test * TSK-1349: added shared sort stub * TSK-1349: added new tests and fixed html attr * TSK-1349: updated test desc and matcher * TSK-1349: fixed stub not working correctly --- web/jasmine-seed-reporter.js | 13 -- web/jest.config.js | 4 +- .../access-items-management.component.html | 6 +- .../access-items-management.component.spec.ts | 216 ++++++++++++++++++ .../access-items-management.component.ts | 3 - 5 files changed, 222 insertions(+), 20 deletions(-) delete mode 100644 web/jasmine-seed-reporter.js create mode 100644 web/src/app/administration/components/access-items-management/access-items-management.component.spec.ts diff --git a/web/jasmine-seed-reporter.js b/web/jasmine-seed-reporter.js deleted file mode 100644 index bd18f328d..000000000 --- a/web/jasmine-seed-reporter.js +++ /dev/null @@ -1,13 +0,0 @@ -var SeedReporter = function (baseReporterDecorator) { - baseReporterDecorator(this); - - this.onBrowserComplete = function (browser, result) { - if (result.order && result.order.random && result.order.seed) { - this.write('%s: Randomized with seed %s\n', browser, result.order.seed); - } - }; -}; - -module.exports = { - 'reporter:jasmine-seed': ['type', SeedReporter] -}; diff --git a/web/jest.config.js b/web/jest.config.js index 538da3ef2..2970429be 100644 --- a/web/jest.config.js +++ b/web/jest.config.js @@ -3,7 +3,9 @@ const { compilerOptions } = require('./tsconfig'); module.exports = { preset: 'jest-preset-angular', - roots: ['/src/'], + roots: ['/src'], + modulePaths: [''], + moduleDirectories: ['node_modules', 'src'], testMatch: ['**/+(*.)+(spec).+(ts)'], setupFilesAfterEnv: ['/src/test.ts'], collectCoverage: true, diff --git a/web/src/app/administration/components/access-items-management/access-items-management.component.html b/web/src/app/administration/components/access-items-management/access-items-management.component.html index b1439991e..a2acc8eb4 100644 --- a/web/src/app/administration/components/access-items-management/access-items-management.component.html +++ b/web/src/app/administration/components/access-items-management/access-items-management.component.html @@ -6,7 +6,7 @@
- @@ -21,7 +21,7 @@
-
+ @@ -153,7 +153,7 @@ clear - + diff --git a/web/src/app/administration/components/access-items-management/access-items-management.component.spec.ts b/web/src/app/administration/components/access-items-management/access-items-management.component.spec.ts new file mode 100644 index 000000000..bb17ecaca --- /dev/null +++ b/web/src/app/administration/components/access-items-management/access-items-management.component.spec.ts @@ -0,0 +1,216 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { AccessItemsManagementComponent } from './access-items-management.component'; +import { FormsValidatorService } from '../../../shared/services/forms-validator/forms-validator.service'; +import { Actions, NgxsModule, ofActionDispatched, Store } from '@ngxs/store'; +import { Component, DebugElement, EventEmitter, Input, Output } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { AngularSvgIconModule } from 'angular-svg-icon'; +import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service'; +import { NotificationService } from '../../../shared/services/notifications/notification.service'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { EngineConfigurationState } from '../../../shared/store/engine-configuration-store/engine-configuration.state'; +import { ClassificationCategoriesService } from '../../../shared/services/classification-categories/classification-categories.service'; +import { AccessItemsManagementState } from '../../../shared/store/access-items-management-store/access-items-management.state'; +import { Observable } from 'rxjs'; +import { GetAccessItems } from '../../../shared/store/access-items-management-store/access-items-management.actions'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { MatDialogModule } from '@angular/material/dialog'; +import { TypeAheadComponent } from '../../../shared/components/type-ahead/type-ahead.component'; +import { TypeaheadModule } from 'ngx-bootstrap'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { Direction, Sorting } from '../../../shared/models/sorting'; + +const isFieldValidFn = jest.fn().mockReturnValue(true); +const formValidatorServiceSpy = jest.fn().mockImplementation( + (): Partial => ({ + isFieldValid: isFieldValidFn + }) +); + +const showDialogFn = jest.fn().mockReturnValue(true); +const notificationServiceSpy = jest.fn().mockImplementation( + (): Partial => ({ + showDialog: showDialogFn + }) +); + +export const engineConfigInitState = { + customisation: { + EN: { + workbaskets: { + 'access-items': { + accessId: { + lookupField: true + }, + custom3: { + field: '', + visible: false + }, + custom9: { + field: 'Some custom field', + visible: true + }, + custom10: { + field: '', + visible: false + }, + custom11: { + field: '', + visible: false + }, + custom12: { + field: '', + visible: false + } + } + } + } + } +}; + +describe('AccessItemsManagementComponent', () => { + let fixture: ComponentFixture; + let debugElement: DebugElement; + let app: AccessItemsManagementComponent; + let store: Store; + let actions$: Observable; + + @Component({ selector: 'taskana-shared-spinner', template: '' }) + class TaskanaSharedSpinnerStub { + @Input() isRunning: boolean; + } + + @Component({ selector: 'taskana-shared-sort', template: '' }) + class TaskanaSharedSortStub { + @Input() sortingFields: Map; + @Output() performSorting = new EventEmitter(); + } + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + HttpClientTestingModule, + NgxsModule.forRoot([EngineConfigurationState, AccessItemsManagementState]), + FormsModule, + ReactiveFormsModule, + AngularSvgIconModule, + MatSnackBarModule, + MatDialogModule, + TypeaheadModule.forRoot(), + BrowserAnimationsModule + ], + declarations: [ + AccessItemsManagementComponent, + TypeAheadComponent, + TaskanaSharedSortStub, + TaskanaSharedSpinnerStub + ], + providers: [ + { provide: FormsValidatorService, useClass: formValidatorServiceSpy }, + { provide: NotificationService, useClass: notificationServiceSpy }, + RequestInProgressService, + ClassificationCategoriesService + ] + }).compileComponents(); + + fixture = TestBed.createComponent(AccessItemsManagementComponent); + debugElement = fixture.debugElement; + app = fixture.debugElement.componentInstance; + store = TestBed.inject(Store); + actions$ = TestBed.inject(Actions); + store.reset({ + ...store.snapshot(), + engineConfiguration: engineConfigInitState + }); + app.accessIdSelected = '1'; + fixture.detectChanges(); + })); + + it('should create the app', () => { + expect(app).toBeTruthy(); + }); + + it('should display header correctly as Access items management', () => { + const panelHeader = () => debugElement.nativeElement.querySelector('h4.panel-header').textContent; + expect(panelHeader()).toBe('Access items management'); + }); + + it('should render search type ahead', () => { + const typeAhead = () => debugElement.nativeElement.querySelector('taskana-shared-type-ahead'); + expect(typeAhead()).toBeTruthy(); + }); + + it('should not display result table when search bar is empty', () => { + const form = () => debugElement.nativeElement.querySelector('ng-form'); + expect(form()).toBeFalsy(); + }); + + it('should initialize app with ngxs store', () => { + const engineConfigs = store.selectSnapshot((state) => { + return state.engineConfiguration.customisation.EN.workbaskets['access-items']; + }); + expect(engineConfigs).toBeDefined(); + expect(engineConfigs).not.toEqual([]); + + const groups = store.selectSnapshot((state) => state.accessItemsManagement); + expect(groups).toBeDefined(); + }); + + it('should be able to get groups if selected access ID is not null in onSelectAccessId', () => { + const selectedAccessId = { accessId: '1', name: '' }; + app.onSelectAccessId(selectedAccessId); + const groups = store.selectSnapshot((state) => state.accessItemsManagement); + expect(selectedAccessId).not.toBeNull(); + expect(groups).not.toBeNull(); + expect(app.accessItemsForm).not.toBeNull(); + + app.onSelectAccessId(null); + expect(app.accessItemsForm).toBeNull(); + }); + + it('should dispatch GetAccessItems action in searchForAccessItemsWorkbaskets', async((done) => { + app.accessId = { accessId: '1', name: 'max' }; + app.groups = [ + { accessId: '1', name: 'users' }, + { accessId: '2', name: 'users' } + ]; + app.sortModel = { sortBy: 'access-id', sortDirection: 'desc' }; + app.searchForAccessItemsWorkbaskets(); + fixture.detectChanges(); + let actionDispatched = false; + actions$.pipe(ofActionDispatched(GetAccessItems)).subscribe(() => { + actionDispatched = true; + expect(actionDispatched).toBe(true); + expect(app.setAccessItemsGroups).toHaveBeenCalled(); + done(); + }); + })); + + it('should display a dialog in when access is revoked', async(() => { + app.accessIdSelected = ''; + const notificationService = TestBed.inject(NotificationService); + const showDialogSpy = jest.spyOn(notificationService, 'showDialog').mockImplementation(); + app.revokeAccess(); + fixture.detectChanges(); + expect(showDialogSpy).toHaveBeenCalled(); + })); + + it('should create accessItemsForm in setAccessItemsGroups', () => { + app.setAccessItemsGroups([]); + expect(app.accessItemsForm).toBeDefined(); + expect(app.accessItemsForm).not.toBeNull(); + }); + + it('should invoke sorting function correctly', () => { + const newSort = new Sorting('access-id', Direction.DESC); + app.accessId = { accessId: '1', name: 'max' }; + app.groups = [{ accessId: '1', name: 'users' }]; + app.sorting(newSort); + expect(app.sortModel).toMatchObject(newSort); + }); + + it('should not return accessItemsGroups when accessItemsForm is null', () => { + app.accessItemsForm = null; + expect(app.accessItemsGroups).toBeNull(); + }); +}); diff --git a/web/src/app/administration/components/access-items-management/access-items-management.component.ts b/web/src/app/administration/components/access-items-management/access-items-management.component.ts index 8a45fbd0a..335e54403 100644 --- a/web/src/app/administration/components/access-items-management/access-items-management.component.ts +++ b/web/src/app/administration/components/access-items-management/access-items-management.component.ts @@ -3,13 +3,11 @@ import { Select, Store } from '@ngxs/store'; import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { Observable, Subject } from 'rxjs'; import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service'; -import { AccessItemWorkbasketResource } from 'app/shared/models/access-item-workbasket-resource'; import { AccessItemWorkbasket } from 'app/shared/models/access-item-workbasket'; import { Direction, Sorting } from 'app/shared/models/sorting'; import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors'; import { takeUntil } from 'rxjs/operators'; import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service'; -import { AccessIdsService } from '../../../shared/services/access-ids/access-ids.service'; import { AccessIdDefinition } from '../../../shared/models/access-id'; import { NotificationService } from '../../../shared/services/notifications/notification.service'; import { AccessItemsCustomisation, CustomField, getCustomFields } from '../../../shared/models/customisation'; @@ -50,7 +48,6 @@ export class AccessItemsManagementComponent implements OnInit { constructor( private formBuilder: FormBuilder, - private accessIdsService: AccessIdsService, private formsValidatorService: FormsValidatorService, private requestInProgressService: RequestInProgressService, private notificationService: NotificationService,