Fix bug in PolicyInstanceDialogComponent
[portal/nonrtric-controlpanel.git] / webapp-frontend / src / app / policy / policy-instance-dialog / policy-instance-dialog.component.spec.ts
index e8038ed..438a295 100644 (file)
@@ -19,6 +19,8 @@
  */
 
 import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
+import { By } from "@angular/platform-browser";
+import { ChangeDetectorRef, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
 import { ComponentFixture, TestBed } from "@angular/core/testing";
 import { HarnessLoader } from "@angular/cdk/testing";
 import { MatButtonModule } from "@angular/material/button";
@@ -30,50 +32,45 @@ import {
 } from "@angular/material/dialog";
 import { MatSelectModule } from "@angular/material/select";
 import { MatInputModule } from "@angular/material/input";
-import { AbstractControl, ReactiveFormsModule } from "@angular/forms";
+import { of } from "rxjs";
+import { ReactiveFormsModule } from "@angular/forms";
 import { TestbedHarnessEnvironment } from "@angular/cdk/testing/testbed";
 import { ToastrModule } from "ngx-toastr";
+import { MockComponent } from "ng-mocks";
 
-import { PolicyService } from "../../services/policy/policy.service";
-import { ErrorDialogService } from "../../services/ui/error-dialog.service";
-import { UiService } from "../../services/ui/ui.service";
+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 {
-  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";
+import { TypedPolicyEditorComponent } from "@policy/typed-policy-editor/typed-policy-editor.component";
+import { RicSelectorComponent } from "@policy/ric-selector/ric-selector.component";
+import { NoTypePolicyEditorComponent } from "@policy/no-type-policy-editor/no-type-policy-editor.component";
+import { CreatePolicyInstance } from "@interfaces/policy.types";
+import { NotificationService } from "@services/ui/notification.service";
+import * as uuid from "uuid";
 
 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;
+    '{ "description": "Type 1 policy type", "title": "1", "type": "object", "properties": { "priorityLevel": "number" }}';
 
   let component: PolicyInstanceDialogComponent;
   let fixture: ComponentFixture<PolicyInstanceDialogComponent>;
   let loader: HarnessLoader;
+  let dialogRefSpy: MatDialogRef<PolicyInstanceDialogComponent>;
   let policyServiceSpy: jasmine.SpyObj<PolicyService>;
   let errDialogServiceSpy: jasmine.SpyObj<ErrorDialogService>;
+  let notificationServiceSpy: NotificationService;
 
   beforeEach(async () => {
+    dialogRefSpy = jasmine.createSpyObj("MatDialogRef", ["close"]);
     policyServiceSpy = jasmine.createSpyObj("PolicyService", ["putPolicy"]);
     errDialogServiceSpy = jasmine.createSpyObj("ErrorDialogService", [
       "displayError",
     ]);
+    notificationServiceSpy = jasmine.createSpyObj("NotificationService", [
+      "success",
+    ]);
 
     TestBed.configureTestingModule({
       imports: [
@@ -88,25 +85,44 @@ describe("PolicyInstanceDialogComponent", () => {
       schemas: [CUSTOM_ELEMENTS_SCHEMA],
       declarations: [
         PolicyInstanceDialogComponent,
-        RicSelectorStubComponent,
-        NoTypePolicyEditorStubComponent,
-        TypedPolicyEditorStubComponent,
+        MockComponent(RicSelectorComponent),
+        MockComponent(NoTypePolicyEditorComponent),
+        MockComponent(TypedPolicyEditorComponent),
       ],
       providers: [
         ChangeDetectorRef,
-        { provide: MatDialogRef, useValue: component },
+        { provide: MatDialogRef, useValue: dialogRefSpy },
         { provide: PolicyService, useValue: policyServiceSpy },
         { provide: ErrorDialogService, useValue: errDialogServiceSpy },
+        { provide: NotificationService, useValue: notificationServiceSpy },
         { provide: MAT_DIALOG_DATA, useValue: true },
         UiService,
       ],
     });
   });
 
-  describe("content when creating policy without type", () => {
+  it("should set correct dark mode from UIService", () => {
+    const policyData = {
+      createSchema: untypedSchema,
+    };
+    TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy
+    ({ fixture, component, loader } = compileAndGetComponents(
+      fixture,
+      component,
+      loader
+    ));
+    const uiService: UiService = TestBed.inject(UiService);
+    expect(component.darkMode).toBeTruthy();
+
+    uiService.darkModeState.next(false);
+    fixture.detectChanges();
+    expect(component.darkMode).toBeFalsy();
+  });
+
+  describe("creating policy without type", () => {
     beforeEach(async () => {
       const policyData = {
-        createSchema: untypedSchemaObject,
+        createSchema: untypedSchema,
       };
       TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy
       ({ fixture, component, loader } = compileAndGetComponents(
@@ -114,6 +130,7 @@ describe("PolicyInstanceDialogComponent", () => {
         component,
         loader
       ));
+      jasmine.addCustomEqualityTester(policyTester);
     });
 
     it("should contain oran logo and create title and no instance info", async () => {
@@ -129,21 +146,24 @@ describe("PolicyInstanceDialogComponent", () => {
       expect(ele).toBeFalsy();
     });
 
-    it("should contain ric select", async () => {
-      const ele = fixture.debugElement.nativeElement.querySelector(
-        "nrcp-ric-selector"
-      );
-      expect(ele).toBeTruthy();
+    it("should contain ric select with no policy type and no ric selected", async () => {
+      const ricSelector: RicSelectorComponent = fixture.debugElement.query(
+        By.directive(RicSelectorComponent)
+      ).componentInstance;
+      expect(ricSelector).toBeTruthy();
+      expect(ricSelector.policyTypeName).toBeFalsy();
+      expect(component.policyInstance.ric_id).toBeFalsy();
     });
 
-    it("should contain json editor", async () => {
-      const ele = fixture.debugElement.nativeElement.querySelector(
-        "nrcp-no-type-policy-editor"
-      );
-      expect(ele).toBeTruthy();
+    it("should contain json editor with no JSON", async () => {
+      const noTypePolicyEditor: NoTypePolicyEditorComponent = fixture.debugElement.query(
+        By.directive(NoTypePolicyEditorComponent)
+      ).componentInstance;
+      expect(noTypePolicyEditor).toBeTruthy();
+      expect(noTypePolicyEditor.policyJson).toBeFalsy();
     });
 
-    it("should contain enabled Close button and disabled Submit button", async () => {
+    it("should contain enabled Close button and Submit button", async () => {
       component.ngOnInit();
 
       let closeButton: MatButtonHarness = await loader.getHarness(
@@ -155,16 +175,60 @@ describe("PolicyInstanceDialogComponent", () => {
       let submitButton: MatButtonHarness = await loader.getHarness(
         MatButtonHarness.with({ selector: "#submitButton" })
       );
-      // expect(await submitButton.isDisabled()).toBeTruthy();
       expect(await submitButton.getText()).toEqual("Submit");
     });
+
+    it("should enable Submit button when ric is selected and json is valid", async () => {
+      const ricSelector: RicSelectorComponent = fixture.debugElement.query(
+        By.directive(RicSelectorComponent)
+      ).componentInstance;
+      const noTypePolicyEditor: NoTypePolicyEditorComponent = fixture.debugElement.query(
+        By.directive(NoTypePolicyEditorComponent)
+      ).componentInstance;
+      let submitButton: MatButtonHarness = await loader.getHarness(
+        MatButtonHarness.with({ selector: "#submitButton" })
+      );
+
+      noTypePolicyEditor.validJson.emit(null);
+      expect(await submitButton.isDisabled()).toBeTruthy();
+
+      ricSelector.selectedRic.emit("ric1");
+      expect(await submitButton.isDisabled()).toBeTruthy();
+
+      noTypePolicyEditor.validJson.emit("{}");
+      expect(await submitButton.isDisabled()).toBeFalsy();
+    });
+
+    it("should generate policy ID when submitting new policy", async () => {
+      const ricSelector: RicSelectorComponent = fixture.debugElement.query(
+        By.directive(RicSelectorComponent)
+      ).componentInstance;
+      const noTypePolicyEditor: NoTypePolicyEditorComponent = fixture.debugElement.query(
+        By.directive(NoTypePolicyEditorComponent)
+      ).componentInstance;
+      let submitButton: MatButtonHarness = await loader.getHarness(
+        MatButtonHarness.with({ selector: "#submitButton" })
+      );
+
+      spyOn(uuid, "v4").and.returnValue("1234567890");
+      ricSelector.selectedRic.emit("ric1");
+      noTypePolicyEditor.validJson.emit("{}");
+      await submitButton.click();
+
+      const policyInstance = {} as CreatePolicyInstance;
+      policyInstance.policy_data = JSON.parse("{}");
+      policyInstance.policy_id = "1234567890";
+      policyInstance.ric_id = "ric1";
+      policyInstance.service_id = "controlpanel";
+      expect(policyServiceSpy.putPolicy).toHaveBeenCalledWith(policyInstance);
+    });
   });
 
   describe("content when creating policy with type", () => {
     beforeEach(async () => {
       const policyData = {
         name: "Type 1",
-        createSchema: typedSchemaObject,
+        createSchema: typedSchema,
       };
       TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy
       ({ fixture, component, loader } = compileAndGetComponents(
@@ -187,21 +251,25 @@ describe("PolicyInstanceDialogComponent", () => {
       expect(ele).toBeFalsy();
     });
 
-    it("should contain ric select", async () => {
-      const ele = fixture.debugElement.nativeElement.querySelector(
-        "nrcp-ric-selector"
-      );
-      expect(ele).toBeTruthy();
+    it("should contain ric select with provided policy type", async () => {
+      const ricSelector: RicSelectorComponent = fixture.debugElement.query(
+        By.directive(RicSelectorComponent)
+      ).componentInstance;
+      expect(ricSelector).toBeTruthy();
+      expect(ricSelector.policyTypeName).toEqual("Type 1");
     });
 
-    it("should contain typed json editor", async () => {
-      const ele = fixture.debugElement.nativeElement.querySelector(
-        "nrcp-typed-policy-editor"
-      );
-      expect(ele).toBeTruthy();
+    it("should contain typed json editor with empty JSON, schema and dark mode true", async () => {
+      const typedPolicyEditor: TypedPolicyEditorComponent = fixture.debugElement.query(
+        By.directive(TypedPolicyEditorComponent)
+      ).componentInstance;
+      expect(typedPolicyEditor).toBeTruthy();
+      expect(typedPolicyEditor.jsonObject).toBeFalsy();
+      expect(typedPolicyEditor.jsonSchemaObject).toEqual(typedSchema);
+      expect(typedPolicyEditor.darkMode).toBeTruthy();
     });
 
-    it("should contain enabled Close button and disabled Submit button", async () => {
+    it("should contain enabled Close button and Submit button", async () => {
       component.ngOnInit();
 
       let closeButton: MatButtonHarness = await loader.getHarness(
@@ -213,18 +281,38 @@ describe("PolicyInstanceDialogComponent", () => {
       let submitButton: MatButtonHarness = await loader.getHarness(
         MatButtonHarness.with({ selector: "#submitButton" })
       );
-      // expect(await submitButton.isDisabled()).toBeTruthy();
       expect(await submitButton.getText()).toEqual("Submit");
     });
+
+    it("should enable Submit button when ric is selected and json is valid", async () => {
+      const ricSelector: RicSelectorComponent = fixture.debugElement.query(
+        By.directive(RicSelectorComponent)
+      ).componentInstance;
+      const typedPolicyEditor: TypedPolicyEditorComponent = fixture.debugElement.query(
+        By.directive(TypedPolicyEditorComponent)
+      ).componentInstance;
+      let submitButton: MatButtonHarness = await loader.getHarness(
+        MatButtonHarness.with({ selector: "#submitButton" })
+      );
+
+      typedPolicyEditor.validJson.emit(null);
+      expect(await submitButton.isDisabled()).toBeTruthy();
+
+      ricSelector.selectedRic.emit("ric1");
+      expect(await submitButton.isDisabled()).toBeTruthy();
+
+      typedPolicyEditor.validJson.emit("{}");
+      expect(await submitButton.isDisabled()).toBeFalsy();
+    });
   });
 
   describe("content when editing policy without type", () => {
+    const instanceJson = JSON.parse('{"qosObjectives": {"priorityLevel": 3100}}');
     beforeEach(async () => {
       const policyData = {
-        createSchema: untypedSchemaObject,
+        createSchema: untypedSchema,
         instanceId: "instanceId",
-        instanceJson: '{"qosObjectives": {"priorityLevel": 3100}}',
-        name: "Type 1",
+        instanceJson: instanceJson,
         ric: "ric1",
       };
       TestBed.overrideProvider(MAT_DIALOG_DATA, { useValue: policyData }); // Should be provided with a policy
@@ -233,6 +321,7 @@ describe("PolicyInstanceDialogComponent", () => {
         component,
         loader
       ));
+      jasmine.addCustomEqualityTester(policyTester);
     });
 
     it("should contain oran logo and instance info", async () => {
@@ -248,20 +337,23 @@ describe("PolicyInstanceDialogComponent", () => {
     });
 
     it("should not contain ric select", async () => {
-      const ele = fixture.debugElement.nativeElement.querySelector(
-        "nrcp-ric-selector"
+      const ricSelector = fixture.debugElement.query(
+        By.directive(RicSelectorComponent)
       );
-      expect(ele).toBeFalsy();
+      expect(ricSelector).toBeFalsy();
     });
 
-    it("should contain json editor", async () => {
-      const ele = fixture.debugElement.nativeElement.querySelector(
-        "nrcp-no-type-policy-editor"
+    it("should contain json editor with json data", async () => {
+      const noTypePolicyEditor: NoTypePolicyEditorComponent = fixture.debugElement.query(
+        By.directive(NoTypePolicyEditorComponent)
+      ).componentInstance;
+      expect(noTypePolicyEditor).toBeTruthy();
+      expect(noTypePolicyEditor.policyJson).toEqual(
+        instanceJson
       );
-      expect(ele).toBeTruthy();
     });
 
-    it("should contain enabled Close and Submit buttons", async () => {
+    it("should contain enabled Close and Submit buttons when all inputs are valid", async () => {
       let closeButton: MatButtonHarness = await loader.getHarness(
         MatButtonHarness.with({ selector: "#closeButton" })
       );
@@ -274,14 +366,36 @@ describe("PolicyInstanceDialogComponent", () => {
       expect(await submitButton.isDisabled()).toBeFalsy();
       expect(await submitButton.getText()).toEqual("Submit");
     });
+
+    it("should submit policy with correct data, close dialog and notify user about success", async () => {
+      policyServiceSpy.putPolicy.and.returnValue(of("ok"));
+      let submitButton: MatButtonHarness = await loader.getHarness(
+        MatButtonHarness.with({ selector: "#submitButton" })
+      );
+
+      await submitButton.click();
+
+      const policyInstance = {} as CreatePolicyInstance;
+      policyInstance.policy_data = instanceJson;
+      policyInstance.policy_id = "instanceId";
+      policyInstance.ric_id = "ric1";
+      policyInstance.service_id = "controlpanel";
+      expect(policyServiceSpy.putPolicy).toHaveBeenCalledWith(policyInstance);
+
+      expect(dialogRefSpy.close).toHaveBeenCalled();
+      expect(notificationServiceSpy.success).toHaveBeenCalledWith(
+        "Policy instanceId submitted"
+      );
+    });
   });
 
   describe("content when editing policy with type", () => {
+    const instanceJson = '{"qosObjectives": {"priorityLevel": 3100}}';
     beforeEach(async () => {
       const policyData = {
-        createSchema: typedSchemaObject,
+        createSchema: typedSchema,
         instanceId: "instanceId",
-        instanceJson: '{"qosObjectives": {"priorityLevel": 3100}}',
+        instanceJson: instanceJson,
         name: "name",
         ric: "ric1",
       };
@@ -306,20 +420,25 @@ describe("PolicyInstanceDialogComponent", () => {
     });
 
     it("should not contain ric select", async () => {
-      const ele = fixture.debugElement.nativeElement.querySelector(
-        "nrcp-ric-selector"
+      const ricSelector = fixture.debugElement.query(
+        By.directive(RicSelectorComponent)
       );
-      expect(ele).toBeFalsy();
+      expect(ricSelector).toBeFalsy();
     });
 
-    it("should contain typed json editor", async () => {
-      const ele = fixture.debugElement.nativeElement.querySelector(
-        "nrcp-typed-policy-editor"
+    it("should contain typed json editor with instance JSON, schema and dark mode true", async () => {
+      const typedPolicyEditor: TypedPolicyEditorComponent = fixture.debugElement.query(
+        By.directive(TypedPolicyEditorComponent)
+      ).componentInstance;
+      expect(typedPolicyEditor).toBeTruthy();
+      expect(unescapeQuotes(typedPolicyEditor.jsonObject)).toEqual(
+        instanceJson
       );
-      expect(ele).toBeTruthy();
+      expect(typedPolicyEditor.jsonSchemaObject).toEqual(typedSchema);
+      expect(typedPolicyEditor.darkMode).toBeTruthy();
     });
 
-    it("should contain enabled Close and Submit buttons", async () => {
+    it("should contain enabled Close and Submit buttons when all inputs are valid", async () => {
       let closeButton: MatButtonHarness = await loader.getHarness(
         MatButtonHarness.with({ selector: "#closeButton" })
       );
@@ -349,48 +468,22 @@ function compileAndGetComponents(
   return { fixture, component, loader };
 }
 
-@Component({
-  selector: "nrcp-ric-selecor",
-  template: "",
-  providers: [
-    { provide: RicSelectorComponent, useClass: RicSelectorStubComponent },
-  ],
-})
-class RicSelectorStubComponent {
-  get selectedRic(): string {
-    return "ric1";
-  }
-}
-
-@Component({
-  selector: "nrcp-no-type-policy-editor",
-  template: "",
-  providers: [
-    {
-      provide: NoTypePolicyEditorComponent,
-      useClass: NoTypePolicyEditorStubComponent,
-    },
-  ],
-})
-class NoTypePolicyEditorStubComponent {
-  get policyJsonTextArea(): AbstractControl {
-    const textArea = { value: "{}" } as AbstractControl;
-    return textArea;
-  }
+function unescapeQuotes(string: string): string {
+  return string.replace(/\\"/g, '"');
 }
 
-@Component({
-  selector: "nrcp-typed-policy-editor",
-  template: "",
-  providers: [
-    {
-      provide: TypedPolicyEditorComponent,
-      useClass: TypedPolicyEditorStubComponent,
-    },
-  ],
-})
-class TypedPolicyEditorStubComponent {
-  get formIsValid(): boolean {
-    return true;
+function policyTester(first, second) {
+  if (typeof first[0] === "object" && typeof second[0] === "object") {
+    const policy1 = first[0] as CreatePolicyInstance;
+    const policy2 = second[0] as CreatePolicyInstance;
+    return (
+      typeof policy1.policy_data === "object" &&
+      typeof policy2.policy_data === "object" &&
+      JSON.stringify(policy1.policy_data) === JSON.stringify(policy2.policy_data) &&
+      policy1.policy_id === policy2.policy_id &&
+      policy1.policytype_id === policy2.policytype_id &&
+      policy1.ric_id === policy2.ric_id &&
+      policy1.service_id === policy2.service_id
+    );
   }
 }