2 * ========================LICENSE_START=================================
5 * Copyright (C) 2019 Nordix Foundation
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ========================LICENSE_END===================================
21 import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
22 import { By } from "@angular/platform-browser";
23 import { ChangeDetectorRef, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
24 import { ComponentFixture, TestBed } from "@angular/core/testing";
25 import { HarnessLoader } from "@angular/cdk/testing";
26 import { MatButtonModule } from "@angular/material/button";
27 import { MatButtonHarness } from "@angular/material/button/testing";
32 } from "@angular/material/dialog";
33 import { MatSelectModule } from "@angular/material/select";
34 import { MatInputModule } from "@angular/material/input";
35 import { of } from "rxjs";
36 import { ReactiveFormsModule } from "@angular/forms";
37 import { TestbedHarnessEnvironment } from "@angular/cdk/testing/testbed";
38 import { ToastrModule } from "ngx-toastr";
39 import { MockComponent } from "ng-mocks";
41 import { PolicyService } from "@services/policy/policy.service";
42 import { ErrorDialogService } from "@services/ui/error-dialog.service";
43 import { UiService } from "@services/ui/ui.service";
44 import { PolicyInstanceDialogComponent } from "./policy-instance-dialog.component";
45 import { TypedPolicyEditorComponent } from "@policy/typed-policy-editor/typed-policy-editor.component";
46 import { RicSelectorComponent } from "@policy/ric-selector/ric-selector.component";
47 import { NoTypePolicyEditorComponent } from "@policy/no-type-policy-editor/no-type-policy-editor.component";
48 import { CreatePolicyInstance } from "@interfaces/policy.types";
49 import { NotificationService } from "@services/ui/notification.service";
50 import * as uuid from "uuid";
52 describe("PolicyInstanceDialogComponent", () => {
53 const untypedSchema = JSON.parse("{}");
55 JSON.parse('{ "description": "Type 1 policy type", "title": "1", "type": "object", "properties": { "priorityLevel": "number" }}');
57 let component: PolicyInstanceDialogComponent;
58 let fixture: ComponentFixture<PolicyInstanceDialogComponent>;
59 let loader: HarnessLoader;
60 let dialogRefSpy: MatDialogRef<PolicyInstanceDialogComponent>;
61 let policyServiceSpy: jasmine.SpyObj<PolicyService>;
62 let errDialogServiceSpy: jasmine.SpyObj<ErrorDialogService>;
63 let notificationServiceSpy: NotificationService;
65 beforeEach(async () => {
66 dialogRefSpy = jasmine.createSpyObj("MatDialogRef", ["close"]);
67 policyServiceSpy = jasmine.createSpyObj("PolicyService", ["putPolicy"]);
68 errDialogServiceSpy = jasmine.createSpyObj("ErrorDialogService", [
71 notificationServiceSpy = jasmine.createSpyObj("NotificationService", [
75 TestBed.configureTestingModule({
77 BrowserAnimationsModule,
83 ToastrModule.forRoot(),
85 schemas: [CUSTOM_ELEMENTS_SCHEMA],
87 PolicyInstanceDialogComponent,
88 MockComponent(RicSelectorComponent),
89 MockComponent(NoTypePolicyEditorComponent),
90 MockComponent(TypedPolicyEditorComponent),
94 { provide: MatDialogRef, useValue: dialogRefSpy },
95 { provide: PolicyService, useValue: policyServiceSpy },
96 { provide: ErrorDialogService, useValue: errDialogServiceSpy },
97 { provide: NotificationService, useValue: notificationServiceSpy },
98 { provide: MAT_DIALOG_DATA, useValue: true },
104 it("should set correct dark mode from UIService", () => {
106 createSchema: untypedSchema,
108 TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy
109 ({ fixture, component, loader } = compileAndGetComponents(
114 const uiService: UiService = TestBed.inject(UiService);
115 expect(component.darkMode).toBeTruthy();
117 uiService.darkModeState.next(false);
118 fixture.detectChanges();
119 expect(component.darkMode).toBeFalsy();
122 describe("creating policy without type", () => {
123 beforeEach(async () => {
125 createSchema: untypedSchema,
127 TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy
128 ({ fixture, component, loader } = compileAndGetComponents(
133 jasmine.addCustomEqualityTester(policyTester);
136 it("should contain oran logo and create title and no instance info", async () => {
137 let ele = fixture.debugElement.nativeElement.querySelector("img");
138 expect(ele.src).toContain("assets/oran-logo.png");
140 ele = fixture.debugElement.nativeElement.querySelector("text");
141 expect(ele.textContent).toEqual(
142 "Create new policy instance of type < No Type >"
145 ele = fixture.debugElement.nativeElement.querySelector("#instanceInfo");
146 expect(ele).toBeFalsy();
149 it("should contain ric select with no policy type and no ric selected", async () => {
150 const ricSelector: RicSelectorComponent = fixture.debugElement.query(
151 By.directive(RicSelectorComponent)
153 expect(ricSelector).toBeTruthy();
154 expect(ricSelector.policyTypeName).toBeFalsy();
155 expect(component.policyInstance.ric_id).toBeFalsy();
158 it("should contain json editor with no JSON", async () => {
159 const noTypePolicyEditor: NoTypePolicyEditorComponent = fixture.debugElement.query(
160 By.directive(NoTypePolicyEditorComponent)
162 expect(noTypePolicyEditor).toBeTruthy();
163 expect(noTypePolicyEditor.policyJson).toBeFalsy();
166 it("should contain enabled Close button and Submit button", async () => {
167 component.ngOnInit();
169 let closeButton: MatButtonHarness = await loader.getHarness(
170 MatButtonHarness.with({ selector: "#closeButton" })
172 expect(await closeButton.isDisabled()).toBeFalsy();
173 expect(await closeButton.getText()).toEqual("Close");
175 let submitButton: MatButtonHarness = await loader.getHarness(
176 MatButtonHarness.with({ selector: "#submitButton" })
178 expect(await submitButton.getText()).toEqual("Submit");
181 it("should enable Submit button when ric is selected and json is valid", async () => {
182 const ricSelector: RicSelectorComponent = fixture.debugElement.query(
183 By.directive(RicSelectorComponent)
185 const noTypePolicyEditor: NoTypePolicyEditorComponent = fixture.debugElement.query(
186 By.directive(NoTypePolicyEditorComponent)
188 let submitButton: MatButtonHarness = await loader.getHarness(
189 MatButtonHarness.with({ selector: "#submitButton" })
192 noTypePolicyEditor.validJson.emit(null);
193 expect(await submitButton.isDisabled()).toBeTruthy();
195 ricSelector.selectedRic.emit("ric1");
196 expect(await submitButton.isDisabled()).toBeTruthy();
198 noTypePolicyEditor.validJson.emit("{}");
199 expect(await submitButton.isDisabled()).toBeFalsy();
202 it("should generate policy ID when submitting new policy", async () => {
203 const ricSelector: RicSelectorComponent = fixture.debugElement.query(
204 By.directive(RicSelectorComponent)
206 const noTypePolicyEditor: NoTypePolicyEditorComponent = fixture.debugElement.query(
207 By.directive(NoTypePolicyEditorComponent)
209 let submitButton: MatButtonHarness = await loader.getHarness(
210 MatButtonHarness.with({ selector: "#submitButton" })
213 spyOn(uuid, "v4").and.returnValue("1234567890");
214 ricSelector.selectedRic.emit("ric1");
215 noTypePolicyEditor.validJson.emit("{}");
216 await submitButton.click();
218 const policyInstance = {} as CreatePolicyInstance;
219 policyInstance.policy_data = JSON.parse("{}");
220 policyInstance.policy_id = "1234567890";
221 policyInstance.policytype_id = "";
222 policyInstance.ric_id = "ric1";
223 policyInstance.service_id = "controlpanel";
224 expect(policyServiceSpy.putPolicy).toHaveBeenCalledWith(policyInstance);
228 describe("content when creating policy with type", () => {
229 beforeEach(async () => {
232 createSchema: typedSchema,
234 TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy
235 ({ fixture, component, loader } = compileAndGetComponents(
242 it("should contain oran logo and create title and no instance info", async () => {
243 let ele = fixture.debugElement.nativeElement.querySelector("img");
244 expect(ele.src).toContain("assets/oran-logo.png");
246 ele = fixture.debugElement.nativeElement.querySelector("text");
247 expect(ele.textContent).toEqual(
248 "Create new policy instance of type Type 1"
251 ele = fixture.debugElement.nativeElement.querySelector("#instanceInfo");
252 expect(ele).toBeFalsy();
255 it("should contain ric select with provided policy type", async () => {
256 const ricSelector: RicSelectorComponent = fixture.debugElement.query(
257 By.directive(RicSelectorComponent)
259 expect(ricSelector).toBeTruthy();
260 expect(ricSelector.policyTypeName).toEqual("Type 1");
263 it("should contain typed json editor with empty JSON, schema and dark mode true", async () => {
264 const typedPolicyEditor: TypedPolicyEditorComponent = fixture.debugElement.query(
265 By.directive(TypedPolicyEditorComponent)
267 expect(typedPolicyEditor).toBeTruthy();
268 expect(typedPolicyEditor.jsonObject).toBeFalsy();
269 expect(typedPolicyEditor.jsonSchemaObject).toEqual(typedSchema);
270 expect(typedPolicyEditor.darkMode).toBeTruthy();
273 it("should contain enabled Close button and Submit button", async () => {
274 component.ngOnInit();
276 let closeButton: MatButtonHarness = await loader.getHarness(
277 MatButtonHarness.with({ selector: "#closeButton" })
279 expect(await closeButton.isDisabled()).toBeFalsy();
280 expect(await closeButton.getText()).toEqual("Close");
282 let submitButton: MatButtonHarness = await loader.getHarness(
283 MatButtonHarness.with({ selector: "#submitButton" })
285 expect(await submitButton.getText()).toEqual("Submit");
288 it("should enable Submit button when ric is selected and json is valid", async () => {
289 const ricSelector: RicSelectorComponent = fixture.debugElement.query(
290 By.directive(RicSelectorComponent)
292 const typedPolicyEditor: TypedPolicyEditorComponent = fixture.debugElement.query(
293 By.directive(TypedPolicyEditorComponent)
295 let submitButton: MatButtonHarness = await loader.getHarness(
296 MatButtonHarness.with({ selector: "#submitButton" })
299 typedPolicyEditor.validJson.emit(null);
300 expect(await submitButton.isDisabled()).toBeTruthy();
302 ricSelector.selectedRic.emit("ric1");
303 expect(await submitButton.isDisabled()).toBeTruthy();
305 typedPolicyEditor.validJson.emit("{}");
306 expect(await submitButton.isDisabled()).toBeFalsy();
310 describe("content when editing policy without type", () => {
311 const instanceJson = JSON.parse('{"qosObjectives": {"priorityLevel": 3100}}');
312 beforeEach(async () => {
314 createSchema: untypedSchema,
315 instanceId: "instanceId",
316 instanceJson: instanceJson,
319 TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy
320 ({ fixture, component, loader } = compileAndGetComponents(
325 jasmine.addCustomEqualityTester(policyTester);
328 it("should contain oran logo and instance info", async () => {
329 let ele = fixture.debugElement.nativeElement.querySelector("img");
330 expect(ele.src).toContain("assets/oran-logo.png");
332 ele = fixture.debugElement.nativeElement.querySelector("text");
333 expect(ele.childNodes[0].childNodes[0]).toBeFalsy(); // No create title
335 ele = fixture.debugElement.nativeElement.querySelector("#instanceInfo");
336 expect(ele).toBeTruthy();
337 expect(ele.innerText).toEqual("[ric1] Instance ID: instanceId");
340 it("should not contain ric select", async () => {
341 const ricSelector = fixture.debugElement.query(
342 By.directive(RicSelectorComponent)
344 expect(ricSelector).toBeFalsy();
347 it("should contain json editor with json data", async () => {
348 const noTypePolicyEditor: NoTypePolicyEditorComponent = fixture.debugElement.query(
349 By.directive(NoTypePolicyEditorComponent)
351 expect(noTypePolicyEditor).toBeTruthy();
352 expect(noTypePolicyEditor.policyJson).toEqual(
357 it("should contain enabled Close and Submit buttons when all inputs are valid", async () => {
358 let closeButton: MatButtonHarness = await loader.getHarness(
359 MatButtonHarness.with({ selector: "#closeButton" })
361 expect(await closeButton.isDisabled()).toBeFalsy();
362 expect(await closeButton.getText()).toEqual("Close");
364 let submitButton: MatButtonHarness = await loader.getHarness(
365 MatButtonHarness.with({ selector: "#submitButton" })
367 expect(await submitButton.isDisabled()).toBeFalsy();
368 expect(await submitButton.getText()).toEqual("Submit");
371 it("should submit policy with correct data, close dialog and notify user about success", async () => {
372 policyServiceSpy.putPolicy.and.returnValue(of("ok"));
373 let submitButton: MatButtonHarness = await loader.getHarness(
374 MatButtonHarness.with({ selector: "#submitButton" })
377 await submitButton.click();
379 const policyInstance = {} as CreatePolicyInstance;
380 policyInstance.policy_data = instanceJson;
381 policyInstance.policy_id = "instanceId";
382 policyInstance.policytype_id = "";
383 policyInstance.ric_id = "ric1";
384 policyInstance.service_id = "controlpanel";
385 expect(policyServiceSpy.putPolicy).toHaveBeenCalledWith(policyInstance);
387 expect(dialogRefSpy.close).toHaveBeenCalled();
388 expect(notificationServiceSpy.success).toHaveBeenCalledWith(
389 "Policy instanceId submitted"
394 describe("content when editing policy with type", () => {
395 const instanceJson = '{"qosObjectives": {"priorityLevel": 3100}}';
396 beforeEach(async () => {
398 createSchema: typedSchema,
399 instanceId: "instanceId",
400 instanceJson: instanceJson,
404 TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy
405 ({ fixture, component, loader } = compileAndGetComponents(
412 it("should contain oran logo and instance info", async () => {
413 let ele = fixture.debugElement.nativeElement.querySelector("img");
414 expect(ele.src).toContain("assets/oran-logo.png");
416 ele = fixture.debugElement.nativeElement.querySelector("text");
417 expect(ele.childNodes[0].childNodes[0]).toBeFalsy(); // No create title
419 ele = fixture.debugElement.nativeElement.querySelector("#instanceInfo");
420 expect(ele).toBeTruthy();
421 expect(ele.innerText).toEqual("[ric1] Instance ID: instanceId");
424 it("should not contain ric select", async () => {
425 const ricSelector = fixture.debugElement.query(
426 By.directive(RicSelectorComponent)
428 expect(ricSelector).toBeFalsy();
431 it("should contain typed json editor with instance JSON, schema and dark mode true", async () => {
432 const typedPolicyEditor: TypedPolicyEditorComponent = fixture.debugElement.query(
433 By.directive(TypedPolicyEditorComponent)
435 expect(typedPolicyEditor).toBeTruthy();
436 expect(unescapeQuotes(typedPolicyEditor.jsonObject)).toEqual(
439 expect(typedPolicyEditor.jsonSchemaObject).toEqual(typedSchema);
440 expect(typedPolicyEditor.darkMode).toBeTruthy();
443 it("should contain enabled Close and Submit buttons when all inputs are valid", async () => {
444 let closeButton: MatButtonHarness = await loader.getHarness(
445 MatButtonHarness.with({ selector: "#closeButton" })
447 expect(await closeButton.isDisabled()).toBeFalsy();
448 expect(await closeButton.getText()).toEqual("Close");
450 let submitButton: MatButtonHarness = await loader.getHarness(
451 MatButtonHarness.with({ selector: "#submitButton" })
453 expect(await submitButton.isDisabled()).toBeFalsy();
454 expect(await submitButton.getText()).toEqual("Submit");
459 function compileAndGetComponents(
460 fixture: ComponentFixture<PolicyInstanceDialogComponent>,
461 component: PolicyInstanceDialogComponent,
462 loader: HarnessLoader
464 TestBed.compileComponents();
466 fixture = TestBed.createComponent(PolicyInstanceDialogComponent);
467 component = fixture.componentInstance;
468 fixture.detectChanges();
469 loader = TestbedHarnessEnvironment.loader(fixture);
470 return { fixture, component, loader };
473 function unescapeQuotes(string: string): string {
474 return string.replace(/\\"/g, '"');
477 function policyTester(first, second) {
478 if (typeof first[0] === "object" && typeof second[0] === "object") {
479 const policy1 = first[0] as CreatePolicyInstance;
480 const policy2 = second[0] as CreatePolicyInstance;
482 typeof policy1.policy_data === "object" &&
483 typeof policy2.policy_data === "object" &&
484 JSON.stringify(policy1.policy_data) === JSON.stringify(policy2.policy_data) &&
485 policy1.policy_id === policy2.policy_id &&
486 policy1.policytype_id === policy2.policytype_id &&
487 policy1.ric_id === policy2.ric_id &&
488 policy1.service_id === policy2.service_id