From ffb56b1ee4e3c4d95cd574c29159181b726db38b Mon Sep 17 00:00:00 2001 From: elinuxhenrik Date: Mon, 15 Mar 2021 11:05:13 +0100 Subject: [PATCH] Add tests of PolicyInstanceDialogComponent Change-Id: I25381affae0f609c49add72f14f3747333f92384 Signed-off-by: elinuxhenrik Issue-ID: NONRTRIC-463 --- .../policy-instance-dialog.component.html | 4 +- .../policy-instance-dialog.component.spec.ts | 335 +++++++++++++++++---- .../policy-instance-dialog.component.ts | 143 +++++---- .../policy/ric-selector/ric-selector.component.ts | 67 +++-- 4 files changed, 407 insertions(+), 142 deletions(-) diff --git a/webapp-frontend/src/app/policy/policy-instance-dialog/policy-instance-dialog.component.html b/webapp-frontend/src/app/policy/policy-instance-dialog/policy-instance-dialog.component.html index 0b85c58..df4c1cf 100644 --- a/webapp-frontend/src/app/policy/policy-instance-dialog/policy-instance-dialog.component.html +++ b/webapp-frontend/src/app/policy/policy-instance-dialog/policy-instance-dialog.component.html @@ -27,9 +27,7 @@ - Create new policy instance of type - {{jsonSchemaObject.title}} - {{policyTypeName}} + Create new policy instance of type {{policyTypeName}} diff --git a/webapp-frontend/src/app/policy/policy-instance-dialog/policy-instance-dialog.component.spec.ts b/webapp-frontend/src/app/policy/policy-instance-dialog/policy-instance-dialog.component.spec.ts index 156d653..e8038ed 100644 --- a/webapp-frontend/src/app/policy/policy-instance-dialog/policy-instance-dialog.component.spec.ts +++ b/webapp-frontend/src/app/policy/policy-instance-dialog/policy-instance-dialog.component.spec.ts @@ -21,12 +21,16 @@ import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; import { ComponentFixture, TestBed } from "@angular/core/testing"; import { HarnessLoader } from "@angular/cdk/testing"; -import { MatButtonModule } from '@angular/material/button'; -import { MatButtonHarness } from '@angular/material/button/testing'; -import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; -import { MatSelectModule } from '@angular/material/select'; -import { MatInputModule } from '@angular/material/input'; -import { ReactiveFormsModule } from "@angular/forms"; +import { MatButtonModule } from "@angular/material/button"; +import { MatButtonHarness } from "@angular/material/button/testing"; +import { + MatDialogModule, + MatDialogRef, + MAT_DIALOG_DATA, +} from "@angular/material/dialog"; +import { MatSelectModule } from "@angular/material/select"; +import { MatInputModule } from "@angular/material/input"; +import { AbstractControl, ReactiveFormsModule } from "@angular/forms"; import { TestbedHarnessEnvironment } from "@angular/cdk/testing/testbed"; import { ToastrModule } from "ngx-toastr"; @@ -34,9 +38,31 @@ import { PolicyService } from "../../services/policy/policy.service"; import { ErrorDialogService } from "../../services/ui/error-dialog.service"; import { UiService } from "../../services/ui/ui.service"; import { PolicyInstanceDialogComponent } from "./policy-instance-dialog.component"; -import { CUSTOM_ELEMENTS_SCHEMA } from "@angular/core"; +import { + ChangeDetectorRef, + Component, + CUSTOM_ELEMENTS_SCHEMA, +} from "@angular/core"; +import { TypedPolicyEditorComponent } from "../typed-policy-editor/typed-policy-editor.component"; +import { RicSelectorComponent } from "../ric-selector/ric-selector.component"; +import { NoTypePolicyEditorComponent } from "../no-type-policy-editor/no-type-policy-editor.component"; +import { PolicyTypeSchema } from "../../interfaces/policy.types"; + +describe("PolicyInstanceDialogComponent", () => { + const untypedSchema = "{}"; + const untypedSchemaObject = { + id: "", + name: "", + schemaObject: untypedSchema, + } as PolicyTypeSchema; + const typedSchema = + '{ "description": "Type 1 policy type", "title": "1", "type": "object", "properties": { "priorityLevel": "number" }, "required": [ "priorityLevel" ]}'; + const typedSchemaObject = { + id: "Type 1", + name: "Type 1", + schemaObject: typedSchema, + } as PolicyTypeSchema; -describe('PolicyInstanceDialogComponent', () => { let component: PolicyInstanceDialogComponent; let fixture: ComponentFixture; let loader: HarnessLoader; @@ -44,8 +70,10 @@ describe('PolicyInstanceDialogComponent', () => { let errDialogServiceSpy: jasmine.SpyObj; beforeEach(async () => { - policyServiceSpy = jasmine.createSpyObj('PolicyService', ['putPolicy']); - errDialogServiceSpy = jasmine.createSpyObj('ErrorDialogService', ['displayError']); + policyServiceSpy = jasmine.createSpyObj("PolicyService", ["putPolicy"]); + errDialogServiceSpy = jasmine.createSpyObj("ErrorDialogService", [ + "displayError", + ]); TestBed.configureTestingModule({ imports: [ @@ -55,116 +83,263 @@ describe('PolicyInstanceDialogComponent', () => { MatInputModule, MatSelectModule, ReactiveFormsModule, - ToastrModule.forRoot() - ], - schemas: [ - CUSTOM_ELEMENTS_SCHEMA + ToastrModule.forRoot(), ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], declarations: [ - PolicyInstanceDialogComponent + PolicyInstanceDialogComponent, + RicSelectorStubComponent, + NoTypePolicyEditorStubComponent, + TypedPolicyEditorStubComponent, ], providers: [ + ChangeDetectorRef, { provide: MatDialogRef, useValue: component }, { provide: PolicyService, useValue: policyServiceSpy }, { provide: ErrorDialogService, useValue: errDialogServiceSpy }, { provide: MAT_DIALOG_DATA, useValue: true }, - UiService - ] + UiService, + ], }); }); - describe('content when creating policy without type', () => { + describe("content when creating policy without type", () => { beforeEach(async () => { const policyData = { - createSchema: '{}' + createSchema: untypedSchemaObject, }; TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy - ({ fixture, component, loader } = compileAndGetComponents(fixture, component, loader)); + ({ fixture, component, loader } = compileAndGetComponents( + fixture, + component, + loader + )); }); - it('should contain oran logo and create title and no instance info', async () => { - let ele = fixture.debugElement.nativeElement.querySelector('img'); - expect(ele.src).toContain('assets/oran-logo.png'); + it("should contain oran logo and create title and no instance info", async () => { + let ele = fixture.debugElement.nativeElement.querySelector("img"); + expect(ele.src).toContain("assets/oran-logo.png"); - ele = fixture.debugElement.nativeElement.querySelector('text'); - expect(ele.textContent).toEqual('Create new policy instance of type < No Type >'); + ele = fixture.debugElement.nativeElement.querySelector("text"); + expect(ele.textContent).toEqual( + "Create new policy instance of type < No Type >" + ); - ele = fixture.debugElement.nativeElement.querySelector('#instanceInfo'); + ele = fixture.debugElement.nativeElement.querySelector("#instanceInfo"); expect(ele).toBeFalsy(); }); - it('should contain ric select', async () => { - const ele = fixture.debugElement.nativeElement.querySelector('nrcp-ric-selector'); + it("should contain ric select", async () => { + const ele = fixture.debugElement.nativeElement.querySelector( + "nrcp-ric-selector" + ); expect(ele).toBeTruthy(); }); - it('should contain json editor', async () => { - const ele = fixture.debugElement.nativeElement.querySelector('nrcp-no-type-policy-editor'); + it("should contain json editor", async () => { + const ele = fixture.debugElement.nativeElement.querySelector( + "nrcp-no-type-policy-editor" + ); expect(ele).toBeTruthy(); }); - it('should contain enabled Close button and disabled Submit button', async () => { + it("should contain enabled Close button and disabled Submit button", async () => { component.ngOnInit(); - let closeButton: MatButtonHarness = await loader.getHarness(MatButtonHarness.with({ selector: '#closeButton' })); + let closeButton: MatButtonHarness = await loader.getHarness( + MatButtonHarness.with({ selector: "#closeButton" }) + ); expect(await closeButton.isDisabled()).toBeFalsy(); - expect(await closeButton.getText()).toEqual('Close'); + expect(await closeButton.getText()).toEqual("Close"); - let submitButton: MatButtonHarness = await loader.getHarness(MatButtonHarness.with({ selector: '#submitButton' })); + let submitButton: MatButtonHarness = await loader.getHarness( + MatButtonHarness.with({ selector: "#submitButton" }) + ); // expect(await submitButton.isDisabled()).toBeTruthy(); - expect(await submitButton.getText()).toEqual('Submit'); + expect(await submitButton.getText()).toEqual("Submit"); }); }); - describe('content when editing policy without type', () => { + describe("content when creating policy with type", () => { beforeEach(async () => { const policyData = { - createSchema: '{}', - instanceId: 'instanceId', + name: "Type 1", + createSchema: typedSchemaObject, + }; + TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy + ({ fixture, component, loader } = compileAndGetComponents( + fixture, + component, + loader + )); + }); + + it("should contain oran logo and create title and no instance info", async () => { + let ele = fixture.debugElement.nativeElement.querySelector("img"); + expect(ele.src).toContain("assets/oran-logo.png"); + + ele = fixture.debugElement.nativeElement.querySelector("text"); + expect(ele.textContent).toEqual( + "Create new policy instance of type Type 1" + ); + + ele = fixture.debugElement.nativeElement.querySelector("#instanceInfo"); + expect(ele).toBeFalsy(); + }); + + it("should contain ric select", async () => { + const ele = fixture.debugElement.nativeElement.querySelector( + "nrcp-ric-selector" + ); + expect(ele).toBeTruthy(); + }); + + it("should contain typed json editor", async () => { + const ele = fixture.debugElement.nativeElement.querySelector( + "nrcp-typed-policy-editor" + ); + expect(ele).toBeTruthy(); + }); + + it("should contain enabled Close button and disabled Submit button", async () => { + component.ngOnInit(); + + let closeButton: MatButtonHarness = await loader.getHarness( + MatButtonHarness.with({ selector: "#closeButton" }) + ); + expect(await closeButton.isDisabled()).toBeFalsy(); + expect(await closeButton.getText()).toEqual("Close"); + + let submitButton: MatButtonHarness = await loader.getHarness( + MatButtonHarness.with({ selector: "#submitButton" }) + ); + // expect(await submitButton.isDisabled()).toBeTruthy(); + expect(await submitButton.getText()).toEqual("Submit"); + }); + }); + + describe("content when editing policy without type", () => { + beforeEach(async () => { + const policyData = { + createSchema: untypedSchemaObject, + instanceId: "instanceId", instanceJson: '{"qosObjectives": {"priorityLevel": 3100}}', - name: 'name', - ric: 'ric1' + name: "Type 1", + ric: "ric1", }; TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy - ({ fixture, component, loader } = compileAndGetComponents(fixture, component, loader)); + ({ fixture, component, loader } = compileAndGetComponents( + fixture, + component, + loader + )); }); - it('should contain oran logo and instance info', async () => { - let ele = fixture.debugElement.nativeElement.querySelector('img'); - expect(ele.src).toContain('assets/oran-logo.png'); + it("should contain oran logo and instance info", async () => { + let ele = fixture.debugElement.nativeElement.querySelector("img"); + expect(ele.src).toContain("assets/oran-logo.png"); - ele = fixture.debugElement.nativeElement.querySelector('text'); + ele = fixture.debugElement.nativeElement.querySelector("text"); expect(ele.childNodes[0].childNodes[0]).toBeFalsy(); // No create title - ele = fixture.debugElement.nativeElement.querySelector('#instanceInfo'); + ele = fixture.debugElement.nativeElement.querySelector("#instanceInfo"); expect(ele).toBeTruthy(); - expect(ele.innerText).toEqual('[ric1] Instance ID: instanceId'); + expect(ele.innerText).toEqual("[ric1] Instance ID: instanceId"); }); - it('should not contain ric select', async () => { - const ele = fixture.debugElement.nativeElement.querySelector('nrcp-ric-selector'); + it("should not contain ric select", async () => { + const ele = fixture.debugElement.nativeElement.querySelector( + "nrcp-ric-selector" + ); expect(ele).toBeFalsy(); }); - it('should contain json editor', async () => { - const ele = fixture.debugElement.nativeElement.querySelector('nrcp-no-type-policy-editor'); + it("should contain json editor", async () => { + const ele = fixture.debugElement.nativeElement.querySelector( + "nrcp-no-type-policy-editor" + ); expect(ele).toBeTruthy(); }); - it('should contain enabled Close and Submit buttons', async () => { - let closeButton: MatButtonHarness = await loader.getHarness(MatButtonHarness.with({ selector: '#closeButton' })); + it("should contain enabled Close and Submit buttons", async () => { + let closeButton: MatButtonHarness = await loader.getHarness( + MatButtonHarness.with({ selector: "#closeButton" }) + ); expect(await closeButton.isDisabled()).toBeFalsy(); - expect(await closeButton.getText()).toEqual('Close'); + expect(await closeButton.getText()).toEqual("Close"); - let submitButton: MatButtonHarness = await loader.getHarness(MatButtonHarness.with({ selector: '#submitButton' })); + let submitButton: MatButtonHarness = await loader.getHarness( + MatButtonHarness.with({ selector: "#submitButton" }) + ); expect(await submitButton.isDisabled()).toBeFalsy(); - expect(await submitButton.getText()).toEqual('Submit'); + expect(await submitButton.getText()).toEqual("Submit"); + }); + }); + + describe("content when editing policy with type", () => { + beforeEach(async () => { + const policyData = { + createSchema: typedSchemaObject, + instanceId: "instanceId", + instanceJson: '{"qosObjectives": {"priorityLevel": 3100}}', + name: "name", + ric: "ric1", + }; + TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy + ({ fixture, component, loader } = compileAndGetComponents( + fixture, + component, + loader + )); }); + it("should contain oran logo and instance info", async () => { + let ele = fixture.debugElement.nativeElement.querySelector("img"); + expect(ele.src).toContain("assets/oran-logo.png"); + + ele = fixture.debugElement.nativeElement.querySelector("text"); + expect(ele.childNodes[0].childNodes[0]).toBeFalsy(); // No create title + + ele = fixture.debugElement.nativeElement.querySelector("#instanceInfo"); + expect(ele).toBeTruthy(); + expect(ele.innerText).toEqual("[ric1] Instance ID: instanceId"); + }); + + it("should not contain ric select", async () => { + const ele = fixture.debugElement.nativeElement.querySelector( + "nrcp-ric-selector" + ); + expect(ele).toBeFalsy(); + }); + + it("should contain typed json editor", async () => { + const ele = fixture.debugElement.nativeElement.querySelector( + "nrcp-typed-policy-editor" + ); + expect(ele).toBeTruthy(); + }); + + it("should contain enabled Close and Submit buttons", async () => { + let closeButton: MatButtonHarness = await loader.getHarness( + MatButtonHarness.with({ selector: "#closeButton" }) + ); + expect(await closeButton.isDisabled()).toBeFalsy(); + expect(await closeButton.getText()).toEqual("Close"); + + let submitButton: MatButtonHarness = await loader.getHarness( + MatButtonHarness.with({ selector: "#submitButton" }) + ); + expect(await submitButton.isDisabled()).toBeFalsy(); + expect(await submitButton.getText()).toEqual("Submit"); + }); }); }); -function compileAndGetComponents(fixture: ComponentFixture, component: PolicyInstanceDialogComponent, loader: HarnessLoader) { +function compileAndGetComponents( + fixture: ComponentFixture, + component: PolicyInstanceDialogComponent, + loader: HarnessLoader +) { TestBed.compileComponents(); fixture = TestBed.createComponent(PolicyInstanceDialogComponent); @@ -173,3 +348,49 @@ function compileAndGetComponents(fixture: ComponentFixture, private policySvc: PolicyService, private errorService: ErrorDialogService, private notificationService: NotificationService, @Inject(MAT_DIALOG_DATA) private data, - private ui: UiService) { + private ui: UiService + ) { this.policyInstanceId = data.instanceId; - this.policyTypeName = data.name ? data.name : '< No Type >'; + this.policyTypeName = data.name ? data.name : "< No Type >"; this.policyJson = data.instanceJson; this.jsonSchemaObject = data.createSchema; this.ric = data.ric; @@ -74,12 +94,17 @@ export class PolicyInstanceDialogComponent implements OnInit { this.formatNoTypePolicyJson(); } + // Do not remove! Needed to avoid "Expression has changed after it was checked" warning + ngAfterViewInit() { + this.cdr.detectChanges(); + } + private formatNoTypePolicyJson() { if (!this.typeHasSchema()) { if (this.policyJson) { this.policyJson = formatJsonString(this.policyJson); } else { - this.policyJson = '{}'; + this.policyJson = "{}"; } } } @@ -95,28 +120,34 @@ export class PolicyInstanceDialogComponent implements OnInit { } else { policyData = this.noTypePolicyEditor.policyJsonTextArea.value; } - let createPolicyInstance: CreatePolicyInstance = this.createPolicyInstance(policyData); - this.policySvc.putPolicy(createPolicyInstance).subscribe( - { - next(_) { - self.notificationService.success('Policy without type:' + self.policyInstanceId + ' submitted'); - self.dialogRef.close(); - }, - error(error: HttpErrorResponse) { - self.errorService.displayError('Submit failed: ' + error.error); - }, - complete() { } - }); + let createPolicyInstance: CreatePolicyInstance = this.createPolicyInstance( + policyData + ); + this.policySvc.putPolicy(createPolicyInstance).subscribe({ + next(_) { + self.notificationService.success( + "Policy without type:" + self.policyInstanceId + " submitted" + ); + self.dialogRef.close(); + }, + error(error: HttpErrorResponse) { + self.errorService.displayError("Submit failed: " + error.error); + }, + complete() {}, + }); } typeHasSchema(): boolean { - return this.jsonSchemaObject !== '{}'; + return this.jsonSchemaObject.schemaObject !== "{}"; } isFormValid(): boolean { let isValid: boolean = this.instanceForm.valid; if (this.typeHasSchema()) { - isValid = isValid && this.typedPolicyEditor ? this.typedPolicyEditor.formIsValid : false; + isValid = + isValid && this.typedPolicyEditor + ? this.typedPolicyEditor.formIsValid + : false; } return isValid; } @@ -125,32 +156,38 @@ export class PolicyInstanceDialogComponent implements OnInit { let createPolicyInstance = {} as CreatePolicyInstance; createPolicyInstance.policy_data = JSON.parse(policyJson); createPolicyInstance.policy_id = this.policyInstanceId; - createPolicyInstance.policytype_id = ''; - createPolicyInstance.ric_id = this.ricSelector ? this.ricSelector.selectedRic : this.ric; - createPolicyInstance.service_id = 'controlpanel'; + createPolicyInstance.policytype_id = ""; + createPolicyInstance.ric_id = this.ricSelector + ? this.ricSelector.selectedRic + : this.ric; + createPolicyInstance.service_id = "controlpanel"; return createPolicyInstance; } } -export function getPolicyDialogProperties(policyTypeSchema: PolicyTypeSchema, instance: PolicyInstance, darkMode: boolean): MatDialogConfig { +export function getPolicyDialogProperties( + policyTypeSchema: PolicyTypeSchema, + instance: PolicyInstance, + darkMode: boolean +): MatDialogConfig { const createSchema = policyTypeSchema.schemaObject; const instanceId = instance ? instance.policy_id : null; const instanceJson = instance ? instance.policy_data : null; const name = policyTypeSchema.name; const ric = instance ? instance.ric_id : null; return { - maxWidth: '1200px', - maxHeight: '900px', - width: '900px', - role: 'dialog', - disableClose: false, - panelClass: darkMode ? 'dark-theme' : '', - data: { - createSchema, - instanceId, - instanceJson, - name, - ric - } + maxWidth: "1200px", + maxHeight: "900px", + width: "900px", + role: "dialog", + disableClose: false, + panelClass: darkMode ? "dark-theme" : "", + data: { + createSchema, + instanceId, + instanceJson, + name, + ric, + }, }; -} \ No newline at end of file +} diff --git a/webapp-frontend/src/app/policy/ric-selector/ric-selector.component.ts b/webapp-frontend/src/app/policy/ric-selector/ric-selector.component.ts index e0ba87e..996d9a0 100644 --- a/webapp-frontend/src/app/policy/ric-selector/ric-selector.component.ts +++ b/webapp-frontend/src/app/policy/ric-selector/ric-selector.component.ts @@ -18,57 +18,66 @@ // ========================LICENSE_END=================================== // / -import { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl, ControlContainer, FormBuilder, FormControl, FormGroup, FormGroupDirective, Validators } from '@angular/forms'; -import { Rics } from 'src/app/interfaces/ric'; -import { PolicyService } from 'src/app/services/policy/policy.service'; +import { Component, Input, OnInit } from "@angular/core"; +import { + AbstractControl, + ControlContainer, + FormBuilder, + FormControl, + FormGroup, + FormGroupDirective, + Validators, +} from "@angular/forms"; +import { Rics } from "src/app/interfaces/ric"; +import { PolicyService } from "src/app/services/policy/policy.service"; @Component({ - selector: 'nrcp-ric-selector', - templateUrl: './ric-selector.component.html', - styleUrls: ['./ric-selector.component.scss'], - viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }] - + selector: "nrcp-ric-selector", + templateUrl: "./ric-selector.component.html", + styleUrls: ["./ric-selector.component.scss"], + viewProviders: [ + { provide: ControlContainer, useExisting: FormGroupDirective }, + ], }) export class RicSelectorComponent implements OnInit { - @Input() instanceForm: FormGroup; - @Input() policyTypeName: string = ''; + @Input() policyTypeName: string = ""; ric: string; allRics: string[] = []; constructor( private dataService: PolicyService, - private formBuilder: FormBuilder) { - } + private formBuilder: FormBuilder + ) {} ngOnInit(): void { this.instanceForm.addControl( - 'ricSelector', new FormControl(this.ric, [ - Validators.required - ])); + "ricSelector", + new FormControl(this.ric, [Validators.required]) + ); - console.log('Ric:', this.ric); + console.log("Ric:", this.ric); this.fetchRics(); } - get selectedRic(): string { return this.ric; } + get selectedRic(): string { + return this.ric; + } get ricSelector(): AbstractControl { - return this.instanceForm.get('ricSelector'); + return this.instanceForm.get("ricSelector"); } private fetchRics() { - console.log('fetchRics ', this.policyTypeName); + console.log("fetchRics ", this.policyTypeName); const self: RicSelectorComponent = this; - this.dataService.getRics(this.policyTypeName).subscribe( - { - next(value: Rics) { - value.rics.forEach(ric => { - self.allRics.push(ric.ric_id) - }); - console.log(value); - } - }); + this.dataService.getRics(this.policyTypeName).subscribe({ + next(value: Rics) { + value.rics.forEach((ric) => { + self.allRics.push(ric.ric_id); + }); + console.log(value); + }, + }); } } -- 2.16.6