ff110137ee9e5702e26a26bf1cb01489e27c5847
[portal/nonrtric-controlpanel.git] / webapp-frontend / src / app / policy / policy-instance-dialog / policy-instance-dialog.component.spec.ts
1 /*-
2  * ========================LICENSE_START=================================
3  * O-RAN-SC
4  * %%
5  * Copyright (C) 2019 Nordix Foundation
6  * %%
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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===================================
19  */
20
21 import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
22 import { ComponentFixture, TestBed } from "@angular/core/testing";
23 import { HarnessLoader } from "@angular/cdk/testing";
24 import { MatButtonModule } from "@angular/material/button";
25 import { MatButtonHarness } from "@angular/material/button/testing";
26 import {
27   MatDialogModule,
28   MatDialogRef,
29   MAT_DIALOG_DATA,
30 } from "@angular/material/dialog";
31 import { MatSelectModule } from "@angular/material/select";
32 import { MatInputModule } from "@angular/material/input";
33 import {
34   AbstractControl,
35   FormControl,
36   FormGroup,
37   ReactiveFormsModule,
38   Validators,
39 } from "@angular/forms";
40 import { TestbedHarnessEnvironment } from "@angular/cdk/testing/testbed";
41 import { ToastrModule } from "ngx-toastr";
42
43 import { PolicyService } from "../../services/policy/policy.service";
44 import { ErrorDialogService } from "../../services/ui/error-dialog.service";
45 import { UiService } from "../../services/ui/ui.service";
46 import { PolicyInstanceDialogComponent } from "./policy-instance-dialog.component";
47 import {
48   ChangeDetectorRef,
49   Component,
50   CUSTOM_ELEMENTS_SCHEMA,
51   Input,
52 } from "@angular/core";
53 import { TypedPolicyEditorComponent } from "../typed-policy-editor/typed-policy-editor.component";
54 import { RicSelectorComponent } from "../ric-selector/ric-selector.component";
55 import { NoTypePolicyEditorComponent } from "../no-type-policy-editor/no-type-policy-editor.component";
56 import { By } from "@angular/platform-browser";
57
58 describe("PolicyInstanceDialogComponent", () => {
59   const untypedSchema = "{}";
60   const typedSchema =
61     '{ "description": "Type 1 policy type", "title": "1", "type": "object", "properties": { "priorityLevel": "number" }}';
62
63   let component: PolicyInstanceDialogComponent;
64   let fixture: ComponentFixture<PolicyInstanceDialogComponent>;
65   let loader: HarnessLoader;
66   let policyServiceSpy: jasmine.SpyObj<PolicyService>;
67   let errDialogServiceSpy: jasmine.SpyObj<ErrorDialogService>;
68
69   beforeEach(async () => {
70     policyServiceSpy = jasmine.createSpyObj("PolicyService", ["putPolicy"]);
71     errDialogServiceSpy = jasmine.createSpyObj("ErrorDialogService", [
72       "displayError",
73     ]);
74
75     TestBed.configureTestingModule({
76       imports: [
77         BrowserAnimationsModule,
78         MatButtonModule,
79         MatDialogModule,
80         MatInputModule,
81         MatSelectModule,
82         ReactiveFormsModule,
83         ToastrModule.forRoot(),
84       ],
85       schemas: [CUSTOM_ELEMENTS_SCHEMA],
86       declarations: [
87         PolicyInstanceDialogComponent,
88         RicSelectorStubComponent,
89         NoTypePolicyEditorStubComponent,
90         TypedPolicyEditorStubComponent,
91       ],
92       providers: [
93         ChangeDetectorRef,
94         { provide: MatDialogRef, useValue: component },
95         { provide: PolicyService, useValue: policyServiceSpy },
96         { provide: ErrorDialogService, useValue: errDialogServiceSpy },
97         { provide: MAT_DIALOG_DATA, useValue: true },
98         UiService,
99       ],
100     });
101   });
102
103   describe("content when creating policy without type", () => {
104     beforeEach(async () => {
105       const policyData = {
106         createSchema: untypedSchema,
107       };
108       TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy
109       ({ fixture, component, loader } = compileAndGetComponents(
110         fixture,
111         component,
112         loader
113       ));
114     });
115
116     it("should contain oran logo and create title and no instance info", async () => {
117       let ele = fixture.debugElement.nativeElement.querySelector("img");
118       expect(ele.src).toContain("assets/oran-logo.png");
119
120       ele = fixture.debugElement.nativeElement.querySelector("text");
121       expect(ele.textContent).toEqual(
122         "Create new policy instance of type < No Type >"
123       );
124
125       ele = fixture.debugElement.nativeElement.querySelector("#instanceInfo");
126       expect(ele).toBeFalsy();
127     });
128
129     it("should contain ric select with no policy type", async () => {
130       const ricSelector: RicSelectorComponent = fixture.debugElement.query(By.directive(RicSelectorComponent)).componentInstance;
131       expect(ricSelector).toBeTruthy();
132       expect(ricSelector.policyTypeName).toBeFalsy();
133     });
134
135     it("should contain json editor with empty JSON", async () => {
136       const noTypePolicyEditor: NoTypePolicyEditorComponent = fixture.debugElement.query(By.directive(NoTypePolicyEditorComponent)).componentInstance;
137       expect(noTypePolicyEditor).toBeTruthy();
138       expect(noTypePolicyEditor.policyJson).toEqual("{}");
139     });
140
141     it("should contain enabled Close button and Submit button", async () => {
142       component.ngOnInit();
143
144       let closeButton: MatButtonHarness = await loader.getHarness(
145         MatButtonHarness.with({ selector: "#closeButton" })
146       );
147       expect(await closeButton.isDisabled()).toBeFalsy();
148       expect(await closeButton.getText()).toEqual("Close");
149
150       let submitButton: MatButtonHarness = await loader.getHarness(
151         MatButtonHarness.with({ selector: "#submitButton" })
152       );
153       expect(await submitButton.getText()).toEqual("Submit");
154     });
155   });
156
157   describe("content when creating policy with type", () => {
158     beforeEach(async () => {
159       const policyData = {
160         name: "Type 1",
161         createSchema: typedSchema,
162       };
163       TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy
164       ({ fixture, component, loader } = compileAndGetComponents(
165         fixture,
166         component,
167         loader
168       ));
169     });
170
171     it("should contain oran logo and create title and no instance info", async () => {
172       let ele = fixture.debugElement.nativeElement.querySelector("img");
173       expect(ele.src).toContain("assets/oran-logo.png");
174
175       ele = fixture.debugElement.nativeElement.querySelector("text");
176       expect(ele.textContent).toEqual(
177         "Create new policy instance of type Type 1"
178       );
179
180       ele = fixture.debugElement.nativeElement.querySelector("#instanceInfo");
181       expect(ele).toBeFalsy();
182     });
183
184     it("should contain ric select with provided policy type", async () => {
185       const ricSelector: RicSelectorComponent = fixture.debugElement.query(By.directive(RicSelectorComponent)).componentInstance;
186       expect(ricSelector).toBeTruthy();
187       expect(ricSelector.policyTypeName).toEqual("Type 1");
188     });
189
190     it("should contain typed json editor with empty JSON, schema and dark mode true", async () => {
191       const typedPolicyEditor: TypedPolicyEditorComponent = fixture.debugElement.query(By.directive(TypedPolicyEditorComponent)).componentInstance;
192       expect(typedPolicyEditor).toBeTruthy();
193       expect(typedPolicyEditor.jsonObject).toBeFalsy();
194       expect(typedPolicyEditor.jsonSchemaObject).toEqual(typedSchema);
195       expect(typedPolicyEditor.darkMode).toBeTruthy();
196     });
197
198     it("should contain enabled Close button and Submit button", async () => {
199       component.ngOnInit();
200
201       let closeButton: MatButtonHarness = await loader.getHarness(
202         MatButtonHarness.with({ selector: "#closeButton" })
203       );
204       expect(await closeButton.isDisabled()).toBeFalsy();
205       expect(await closeButton.getText()).toEqual("Close");
206
207       let submitButton: MatButtonHarness = await loader.getHarness(
208         MatButtonHarness.with({ selector: "#submitButton" })
209       );
210       expect(await submitButton.getText()).toEqual("Submit");
211     });
212   });
213
214   describe("content when editing policy without type", () => {
215     const instanceJson = '{"qosObjectives": {"priorityLevel": 3100}}';
216     beforeEach(async () => {
217       const policyData = {
218         createSchema: untypedSchema,
219         instanceId: "instanceId",
220         instanceJson: instanceJson,
221         name: "Type 1",
222         ric: "ric1",
223       };
224       TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy
225       ({ fixture, component, loader } = compileAndGetComponents(
226         fixture,
227         component,
228         loader
229       ));
230     });
231
232     it("should contain oran logo and instance info", async () => {
233       let ele = fixture.debugElement.nativeElement.querySelector("img");
234       expect(ele.src).toContain("assets/oran-logo.png");
235
236       ele = fixture.debugElement.nativeElement.querySelector("text");
237       expect(ele.childNodes[0].childNodes[0]).toBeFalsy(); // No create title
238
239       ele = fixture.debugElement.nativeElement.querySelector("#instanceInfo");
240       expect(ele).toBeTruthy();
241       expect(ele.innerText).toEqual("[ric1] Instance ID: instanceId");
242     });
243
244     it("should not contain ric select", async () => {
245       const ricSelector = fixture.debugElement.query(By.directive(RicSelectorComponent));
246       expect(ricSelector).toBeFalsy();
247     });
248
249     it("should contain json editor with json data", async () => {
250       const noTypePolicyEditor: NoTypePolicyEditorComponent = fixture.debugElement.query(By.directive(NoTypePolicyEditorComponent)).componentInstance;
251       expect(noTypePolicyEditor).toBeTruthy();
252       expect(unescapeQuotes(noTypePolicyEditor.policyJson)).toEqual('"' + instanceJson + '"');
253     });
254
255     it("should contain enabled Close and Submit buttons when all inputs are valid", async () => {
256       let closeButton: MatButtonHarness = await loader.getHarness(
257         MatButtonHarness.with({ selector: "#closeButton" })
258       );
259       expect(await closeButton.isDisabled()).toBeFalsy();
260       expect(await closeButton.getText()).toEqual("Close");
261
262       let submitButton: MatButtonHarness = await loader.getHarness(
263         MatButtonHarness.with({ selector: "#submitButton" })
264       );
265       expect(await submitButton.isDisabled()).toBeFalsy();
266       expect(await submitButton.getText()).toEqual("Submit");
267     });
268   });
269
270   describe("content when editing policy with type", () => {
271     const instanceJson = '{"qosObjectives": {"priorityLevel": 3100}}';
272     beforeEach(async () => {
273       const policyData = {
274         createSchema: typedSchema,
275         instanceId: "instanceId",
276         instanceJson: instanceJson,
277         name: "name",
278         ric: "ric1",
279       };
280       TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy
281       ({ fixture, component, loader } = compileAndGetComponents(
282         fixture,
283         component,
284         loader
285       ));
286     });
287
288     it("should contain oran logo and instance info", async () => {
289       let ele = fixture.debugElement.nativeElement.querySelector("img");
290       expect(ele.src).toContain("assets/oran-logo.png");
291
292       ele = fixture.debugElement.nativeElement.querySelector("text");
293       expect(ele.childNodes[0].childNodes[0]).toBeFalsy(); // No create title
294
295       ele = fixture.debugElement.nativeElement.querySelector("#instanceInfo");
296       expect(ele).toBeTruthy();
297       expect(ele.innerText).toEqual("[ric1] Instance ID: instanceId");
298     });
299
300     it("should not contain ric select", async () => {
301       const ricSelector = fixture.debugElement.query(By.directive(RicSelectorComponent));
302       expect(ricSelector).toBeFalsy();
303     });
304
305     it("should contain typed json editor with instance JSON, schema and dark mode true", async () => {
306       const typedPolicyEditor: TypedPolicyEditorComponent = fixture.debugElement.query(By.directive(TypedPolicyEditorComponent)).componentInstance;
307       expect(typedPolicyEditor).toBeTruthy();
308       expect(unescapeQuotes(typedPolicyEditor.jsonObject)).toEqual(instanceJson);
309       expect(typedPolicyEditor.jsonSchemaObject).toEqual(typedSchema);
310       expect(typedPolicyEditor.darkMode).toBeTruthy();
311     });
312
313     it("should contain enabled Close and Submit buttons when all inputs are valid", async () => {
314       let closeButton: MatButtonHarness = await loader.getHarness(
315         MatButtonHarness.with({ selector: "#closeButton" })
316       );
317       expect(await closeButton.isDisabled()).toBeFalsy();
318       expect(await closeButton.getText()).toEqual("Close");
319
320       let submitButton: MatButtonHarness = await loader.getHarness(
321         MatButtonHarness.with({ selector: "#submitButton" })
322       );
323       expect(await submitButton.isDisabled()).toBeFalsy();
324       expect(await submitButton.getText()).toEqual("Submit");
325     });
326   });
327 });
328
329 function compileAndGetComponents(
330   fixture: ComponentFixture<PolicyInstanceDialogComponent>,
331   component: PolicyInstanceDialogComponent,
332   loader: HarnessLoader
333 ) {
334   TestBed.compileComponents();
335
336   fixture = TestBed.createComponent(PolicyInstanceDialogComponent);
337   component = fixture.componentInstance;
338   fixture.detectChanges();
339   loader = TestbedHarnessEnvironment.loader(fixture);
340   return { fixture, component, loader };
341 }
342
343 function unescapeQuotes(string: string): string {
344   return string.replace(/\\"/g, '"');
345 }
346
347 @Component({
348   selector: "nrcp-ric-selector",
349   template: "",
350   providers: [
351     {
352       provide: RicSelectorComponent,
353       useClass: RicSelectorStubComponent,
354     },
355   ],
356 })
357 class RicSelectorStubComponent {
358   @Input() policyTypeName: string = "";
359
360   get selectedRic(): string {
361     return "ric1";
362   }
363 }
364
365 @Component({
366   selector: "nrcp-no-type-policy-editor",
367   template: "",
368   providers: [
369     {
370       provide: NoTypePolicyEditorComponent,
371       useClass: NoTypePolicyEditorStubComponent,
372     },
373   ],
374 })
375 class NoTypePolicyEditorStubComponent {
376   @Input() policyJson: string;
377
378   get policyJsonTextArea(): AbstractControl {
379     const textArea = { value: "{}" } as AbstractControl;
380     return textArea;
381   }
382 }
383
384 @Component({
385   selector: "nrcp-typed-policy-editor",
386   template: "",
387   providers: [
388     {
389       provide: TypedPolicyEditorComponent,
390       useClass: TypedPolicyEditorStubComponent,
391     },
392   ],
393 })
394 class TypedPolicyEditorStubComponent {
395   @Input() jsonSchemaObject: any = {};
396   @Input() jsonObject: any = {};
397   @Input() darkMode: boolean;
398
399   prettyLiveFormData = '"A": "string"';
400   get formIsValid(): boolean {
401     return true;
402   }
403 }