From 7ca2d23ec5f7405f219951ccd669dcb17778c56a Mon Sep 17 00:00:00 2001 From: elinuxhenrik Date: Tue, 16 Feb 2021 15:38:47 +0100 Subject: [PATCH] Add coverage of ei coordinator component Change-Id: I0903deb8dd13f4b2b4fe67f255f2f4ae4a50cdd2 Signed-off-by: elinuxhenrik Issue-ID: NONRTRIC-437 --- webapp-frontend/src/app/app.component.spec.ts | 1 + .../ei-coordinator/ei-coordinator.component.html | 31 ++- .../ei-coordinator/ei-coordinator.component.scss | 9 - .../ei-coordinator.component.spec.ts | 215 ++++++++++++++++++++- .../app/ei-coordinator/ei-coordinator.component.ts | 74 ++----- .../src/app/mock/ei-jobs-producer1.json | 4 +- 6 files changed, 238 insertions(+), 96 deletions(-) diff --git a/webapp-frontend/src/app/app.component.spec.ts b/webapp-frontend/src/app/app.component.spec.ts index bb65313..02b5fc6 100644 --- a/webapp-frontend/src/app/app.component.spec.ts +++ b/webapp-frontend/src/app/app.component.spec.ts @@ -101,6 +101,7 @@ describe('AppComponent', () => { expect(uiService.getDarkMode()).toBeTruthy(); expect(app.darkMode).toBeTruthy(); + expect(cookieServiceSpy.get).toHaveBeenCalled(); }); it('should toggle dark mode when selector is clicked', () => { diff --git a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.html b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.html index e1832f0..fc560dd 100644 --- a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.html +++ b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.html @@ -31,7 +31,7 @@ limitations under the License.

Producers

- @@ -39,7 +39,7 @@ limitations under the License.
- + Producer ID
@@ -53,13 +53,13 @@ limitations under the License.
- + Producer types
- {{this.getEIProducerTypes(eiProducer)}} + {{this.getProducerTypes(eiProducer)}} @@ -67,18 +67,17 @@ limitations under the License.
- + Producer status
- {{this.getEIProducerStatus(eiProducer)}} + {{this.getProducerStatus(eiProducer)}}
-
@@ -86,7 +85,7 @@ limitations under the License.

Jobs

- @@ -94,52 +93,52 @@ limitations under the License.
- + Job ID
- {{this.getDisplayName(eiJob)}} + {{eiJob.ei_job_identity}}
- + Type ID
- {{this.getEITypeId(eiJob)}} + {{this.getJobTypeId(eiJob)}}
- + Owner
- {{eiJob.owner}} + {{this.getJobOwner(eiJob)}}
- + Target URI
- {{this.getTargetUri(eiJob)}} + {{eiJob.target_uri}}
diff --git a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.scss b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.scss index 955ca31..109d883 100644 --- a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.scss +++ b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.scss @@ -18,15 +18,6 @@ * ========================LICENSE_END=================================== */ -.spinner-container { - height: 100px; - width: 100px; -} - -.spinner-container mat-spinner { - margin: 0 auto 0 auto; -} - .ei-coordinator-table { width: 100%; min-height: 150px; diff --git a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.spec.ts b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.spec.ts index 4767de6..b1007c2 100644 --- a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.spec.ts +++ b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.spec.ts @@ -21,27 +21,55 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations' import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; +import {HarnessLoader} from '@angular/cdk/testing'; import { MatIconModule } from '@angular/material/icon'; +import { MatInputHarness } from '@angular/material/input/testing' import { MatTableModule } from '@angular/material/table'; +import { MatTableHarness } from '@angular/material/table/testing'; +import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; import { EICoordinatorComponent } from './ei-coordinator.component'; import { EIJobDataSource } from './ei-job.datasource'; import { EIProducerDataSource } from './ei-producer.datasource'; import { UiService } from '../services/ui/ui.service'; +import { EIJob, EIProducer } from '../interfaces/ei.types'; describe('EICoordinatorComponent', () => { let component: EICoordinatorComponent; let fixture: ComponentFixture; + let loader: HarnessLoader; + let producerDataSourceSpy: jasmine.SpyObj; + let jobDataSourceSpy: jasmine.SpyObj; - beforeEach(async(() => { - const jobDataSourceSpy = jasmine.createSpyObj('EIJobDataSource', [ 'loadJobs', 'eiJobs' ]); - const producerDataSourceSpy = jasmine.createSpyObj('EIProducerDataSource', [ 'loadProducers', 'eiProducers' ]); + const producer1 = { + ei_producer_id: 'producer1', + ei_producer_types: [ 'type1', 'type2' ], + status: 'ENABLED' + } as EIProducer; + const producer2 = { + ei_producer_id: 'producer2', + ei_producer_types: [ 'type2', 'type3' ], + status: 'DISABLED' + } as EIProducer; - jobDataSourceSpy.eiJobs.and.returnValue([]); + const job1 = { + ei_job_identity: 'job1', + ei_type_identity: 'type1', + owner: 'owner1', + target_uri: 'http://one' + } as EIJob; + const job2 = { + ei_job_identity: 'job2', + ei_type_identity: 'type2', + owner: 'owner2', + target_uri: 'http://two' + } as EIJob; - producerDataSourceSpy.eiProducers.and.returnValue([]); + beforeEach(async () => { + producerDataSourceSpy = jasmine.createSpyObj('EIProducerDataSource', [ 'loadProducers', 'eiProducers' ]); + jobDataSourceSpy = jasmine.createSpyObj('EIJobDataSource', [ 'loadJobs', 'eiJobs' ]); - TestBed.configureTestingModule({ + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatTableModule, @@ -62,15 +90,186 @@ describe('EICoordinatorComponent', () => { ] }) .compileComponents(); - })); - beforeEach(() => { fixture = TestBed.createComponent(EICoordinatorComponent); component = fixture.componentInstance; fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); }); it('should create', () => { expect(component).toBeTruthy(); }); + + describe('#content', () => { + it('should contain refresh button with coorect icon', () => { + const button = fixture.debugElement.nativeElement.querySelector('#refreshButton'); + expect(button).toBeTruthy(); + expect(button.innerHTML).toContain('refresh'); + }); + + it('should contain producers table with correct columns', async () => { + let producersTable = await loader.getHarness(MatTableHarness.with({selector: '#producersTable'})); + let headerRow = (await producersTable.getHeaderRows())[0]; + let headers = await headerRow.getCellTextByColumnName(); + + expect(headers).toEqual({id: 'Producer ID', types: 'Producer types', status: 'Producer status'}); + }); + + it('should contain jobs table with correct columns', async () => { + let producersTable = await loader.getHarness(MatTableHarness.with({selector: '#jobsTable'})); + let headerRow = (await producersTable.getHeaderRows())[0]; + let headers = await headerRow.getCellTextByColumnName(); + + expect(headers).toEqual({id: 'Job ID', typeId: 'Type ID', owner: 'Owner', targetUri: 'Target URI'}); + }); + + it('should set correct dark mode from UIService', () => { + const uiService: UiService = TestBed.inject(UiService); + expect(component.darkMode).toBeTruthy(); + + uiService.darkModeState.next(false); + fixture.detectChanges(); + expect(component.darkMode).toBeFalsy(); + + }); + }); + + describe('#producersTable', () => { + const expectedProducer1Row = { id: 'producer1', types: 'type1,type2', status: 'ENABLED' }; + beforeEach(() => { + const producers: EIProducer[] =[ producer1, producer2 ]; + producerDataSourceSpy.eiProducers.and.returnValue(producers); + }); + + it('should contain data after initialization', async () => { + component.ngOnInit(); + const expectedProducerRows = [ + expectedProducer1Row, + {id: 'producer2', types: 'type2,type3', status: 'DISABLED'} + ]; + let producersTable = await loader.getHarness(MatTableHarness.with({selector: '#producersTable'})); + let producerRows = await producersTable.getRows(); + expect(producerRows.length).toEqual(2); + producerRows.forEach(row => { + row.getCellTextByColumnName().then(values => { + expect(expectedProducerRows).toContain(jasmine.objectContaining(values)); + }); + }); + }); + + describe('should display default values for non required properties', () => { + it('producer defaults', async () => { + const producerMissingProperties = { + ei_producer_id: 'producer1' + } as EIProducer; + const producers: EIProducer[] =[ producerMissingProperties ]; + producerDataSourceSpy.eiProducers.and.returnValue(producers); + component.ngOnInit(); + + const expectedProducerRow = { id: 'producer1', types: '< No types >', status: '< No status >' }; + let producersTable = await loader.getHarness(MatTableHarness.with({selector: '#producersTable'})); + let producerRows = await producersTable.getRows(); + expect(await producerRows[0].getCellTextByColumnName()).toEqual(expectedProducerRow); + }); + + it('job defaults', async () => { + const jobMissingProperties = { + ei_job_identity: 'job1', + target_uri: 'http://one' + } as EIJob; + const jobs: EIJob[] =[ jobMissingProperties ]; + jobDataSourceSpy.eiJobs.and.returnValue(jobs); + component.ngOnInit(); + + const expectedJobRow = { id: 'job1', typeId: '< No type >', owner: '< No owner >', targetUri: 'http://one' }; + let jobsTable = await loader.getHarness(MatTableHarness.with({selector: '#jobsTable'})); + let jobRows = await jobsTable.getRows(); + expect(await jobRows[0].getCellTextByColumnName()).toEqual(expectedJobRow); + }); + }); + + it('filtering', async () => { + component.ngOnInit(); + let producersTable = await loader.getHarness(MatTableHarness.with({selector: '#producersTable'})); + + let idFilterInput = await loader.getHarness(MatInputHarness.with({selector: '#producerIdFilter'})); + await idFilterInput.setValue("1"); + let producerRows = await producersTable.getRows(); + expect(producerRows.length).toEqual(1); + expect(await producerRows[0].getCellTextByColumnName()).toEqual(expectedProducer1Row); + + idFilterInput.setValue(''); + let typesFilterInput = await loader.getHarness(MatInputHarness.with({selector: '#producerTypesFilter'})); + await typesFilterInput.setValue("1"); + producerRows = await producersTable.getRows(); + expect(producerRows.length).toEqual(1); + expect(await producerRows[0].getCellTextByColumnName()).toEqual(expectedProducer1Row); + await typesFilterInput.setValue("2"); + producerRows = await producersTable.getRows(); + expect(producerRows.length).toEqual(2); + + typesFilterInput.setValue(''); + let statusFilterInput = await loader.getHarness(MatInputHarness.with({selector: '#producerStatusFilter'})); + await statusFilterInput.setValue("enabled"); + producerRows = await producersTable.getRows(); + expect(producerRows.length).toEqual(1); + expect(await producerRows[0].getCellTextByColumnName()).toEqual(expectedProducer1Row); + }); + }); + + describe('#jobsTable', () => { + const expectedJob1Row = { id: 'job1', typeId: 'type1', owner: 'owner1', targetUri: 'http://one' }; + beforeEach(() => { + const jobs: EIJob[] =[ job1, job2 ]; + jobDataSourceSpy.eiJobs.and.returnValue(jobs); + }); + + it('should contain data after initialization', async () => { + component.ngOnInit(); + const expectedJobRows = [ + expectedJob1Row, + { id: 'job2', typeId: 'type2', owner: 'owner2', targetUri: 'http://two' } + ]; + let jobsTable = await loader.getHarness(MatTableHarness.with({selector: '#jobsTable'})); + let jobRows = await jobsTable.getRows(); + expect(jobRows.length).toEqual(2); + jobRows.forEach(row => { + row.getCellTextByColumnName().then(values => { + expect(expectedJobRows).toContain(jasmine.objectContaining(values)); + }); + }); + }); + + it('filtering', async () => { + component.ngOnInit(); + let jobsTable = await loader.getHarness(MatTableHarness.with({selector: '#jobsTable'})); + + let idFilterInput = await loader.getHarness(MatInputHarness.with({selector: '#jobIdFilter'})); + await idFilterInput.setValue("1"); + let jobRows = await jobsTable.getRows(); + expect(jobRows.length).toEqual(1); + expect(await jobRows[0].getCellTextByColumnName()).toEqual(expectedJob1Row); + + idFilterInput.setValue(''); + let typeIdFilterInput = await loader.getHarness(MatInputHarness.with({selector: '#jobTypeIdFilter'})); + await typeIdFilterInput.setValue("1"); + jobRows = await jobsTable.getRows(); + expect(jobRows.length).toEqual(1); + + typeIdFilterInput.setValue(''); + let ownerFilterInput = await loader.getHarness(MatInputHarness.with({selector: '#jobOwnerFilter'})); + await ownerFilterInput.setValue("1"); + jobRows = await jobsTable.getRows(); + expect(jobRows.length).toEqual(1); + expect(await jobRows[0].getCellTextByColumnName()).toEqual(expectedJob1Row); + + ownerFilterInput.setValue(''); + let targetUriFilterInput = await loader.getHarness(MatInputHarness.with({selector: '#jobTargetUriFilter'})); + await targetUriFilterInput.setValue("one"); + jobRows = await jobsTable.getRows(); + expect(jobRows.length).toEqual(1); + expect(await jobRows[0].getCellTextByColumnName()).toEqual(expectedJob1Row); + }); + }); }); diff --git a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.ts b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.ts index b823018..5e5b363 100644 --- a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.ts +++ b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.ts @@ -19,39 +19,21 @@ */ import { Component, OnInit } from '@angular/core'; import { Sort } from '@angular/material/sort'; -import { animate, state, style, transition, trigger } from '@angular/animations'; import { FormBuilder, FormGroup, AbstractControl } from '@angular/forms'; import { MatTableDataSource, MatTable } from '@angular/material/table'; -import { BehaviorSubject, Observable } from 'rxjs'; - import { EIJob, EIProducer } from '../interfaces/ei.types'; import { EIJobDataSource } from './ei-job.datasource'; import { EIProducerDataSource } from './ei-producer.datasource'; import { UiService } from '../services/ui/ui.service'; -class EIJobInfo { - constructor(public eiJob: EIJob) { } - - isExpanded: BehaviorSubject = new BehaviorSubject(false); -} - @Component({ selector: 'nrcp-ei-coordinator', templateUrl: './ei-coordinator.component.html', - styleUrls: ['./ei-coordinator.component.scss'], - animations: [ - trigger('detailExpand', [ - state('collapsed, void', style({ height: '0px', minHeight: '0', display: 'none' })), - state('expanded', style({ height: '*' })), - transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')), - transition('expanded <=> void', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')) - ]), - ], + styleUrls: ['./ei-coordinator.component.scss'] }) export class EICoordinatorComponent implements OnInit { - eiJobInfo = new Map(); darkMode: boolean; searchString: string; formGroup: FormGroup; @@ -85,7 +67,8 @@ export class EICoordinatorComponent implements OnInit { this.eiJobsDataSource.loadJobs(); this.eiProducersDataSource.loadProducers(); this.jobsDataSource = new MatTableDataSource(this.eiJobsDataSource.eiJobs()); - this.producersDataSource = new MatTableDataSource(this.eiProducersDataSource.eiProducers()); + const prods = this.eiProducersDataSource.eiProducers(); + this.producersDataSource = new MatTableDataSource(prods); this.jobsFormControl.valueChanges.subscribe(value => { const filter = {...value, id: value.id.trim().toLowerCase()} as string; @@ -98,16 +81,16 @@ export class EICoordinatorComponent implements OnInit { this.jobsDataSource.filterPredicate = ((data: EIJob, filter) => { return this.isDataIncluding(data.ei_job_identity, filter.id) - && this.isDataIncluding(data.target_uri, filter.target_uri) + && this.isDataIncluding(data.target_uri, filter.targetUri) && this.isDataIncluding(data.owner, filter.owner) && this.isDataIncluding(data.ei_type_identity, filter.typeId); - }) as (EIJob, string) => boolean; + }) as (data: EIJob, filter: any) => boolean; this.producersDataSource.filterPredicate = ((data, filter) => { return this.isDataIncluding(data.ei_producer_id, filter.ei_producer_id) && this.isDataIncluding(data.ei_producer_types.join(','), filter.ei_producer_types) && this.isDataIncluding(data.status, filter.status); - }) as (EIProducer, string) => boolean; + }) as (data: EIProducer, filter: any) => boolean; this.ui.darkModeState.subscribe((isDark) => { this.darkMode = isDark; @@ -156,59 +139,28 @@ export class EICoordinatorComponent implements OnInit { return !filter || data.toLowerCase().includes(filter); } - getEIJobInfo(eiJob: EIJob): EIJobInfo { - let info: EIJobInfo = this.eiJobInfo.get(eiJob.ei_job_data); - if (!info) { - info = new EIJobInfo(eiJob); - this.eiJobInfo.set(eiJob.ei_job_data, info); - } - return info; - } - - getDisplayName(eiJob: EIJob): string { - if (eiJob.ei_job_identity) { - return eiJob.ei_job_identity; - } - return '< No id >'; - } - - getEITypeId(eiJob: EIJob): string { + getJobTypeId(eiJob: EIJob): string { if (eiJob.ei_type_identity) { return eiJob.ei_type_identity; } return '< No type >'; } - getTargetUri(eiJob: EIJob): string { - if (eiJob.target_uri) { - return eiJob.target_uri; - } - return '< No target URI >'; - } - - isInstancesShown(eiJob: EIJob): boolean { - return this.getEIJobInfo(eiJob).isExpanded.getValue(); - } - - getExpandedObserver(eiJob: EIJob): Observable { - return this.getEIJobInfo(eiJob).isExpanded.asObservable(); - } - - getEIProducerId(eiProducer: EIProducer): string { - if (eiProducer.ei_producer_id) { - return eiProducer.ei_producer_id; + getJobOwner(eiJob: EIJob): string { + if (eiJob.owner) { + return eiJob.owner; } - return '< No id>'; + return '< No owner >'; } - getEIProducerTypes(eiProducer: EIProducer): string[] { + getProducerTypes(eiProducer: EIProducer): string[] { if (eiProducer.ei_producer_types) { return eiProducer.ei_producer_types; } return ['< No types >']; } - getEIProducerStatus(eiProducer: EIProducer): string { + getProducerStatus(eiProducer: EIProducer): string { if (eiProducer.status) { return eiProducer.status; } diff --git a/webapp-frontend/src/app/mock/ei-jobs-producer1.json b/webapp-frontend/src/app/mock/ei-jobs-producer1.json index 1f79777..2a910c1 100644 --- a/webapp-frontend/src/app/mock/ei-jobs-producer1.json +++ b/webapp-frontend/src/app/mock/ei-jobs-producer1.json @@ -8,7 +8,7 @@ "jobparam3": "value3_job1", "jobparam1": "value1_job1" }, - "target_uri": "https://ricsim_g3_1:8185/datadelivery" + "target_uri": "https://ricsim_g1_1:8185/datadelivery" }, { "ei_job_identity": "job2", @@ -19,7 +19,7 @@ "jobparam3": "value3_job2", "jobparam1": "value1_job2" }, - "target_uri": "https://ricsim_g3_1:8185/datadelivery" + "target_uri": "https://ricsim_g2_1:8185/datadelivery" }, { "ei_job_identity": "job4", -- 2.16.6