From ab80d214c358abf14d1351bd831943ef9bf1a6e5 Mon Sep 17 00:00:00 2001 From: Sergei Zaychenko Date: Fri, 8 Sep 2023 05:25:28 -0700 Subject: [PATCH] Increase unit test coverage in DatasetSettingsTabComponent --- src/app/common/base-test.helpers.spec.ts | 4 +- src/app/common/table.helper.ts | 2 +- .../dataset-create.component.spec.ts | 10 +- .../dataset-settings.component.html | 18 ++- .../dataset-settings.component.spec.ts | 148 ++++++++++++++++-- .../dataset-settings.component.ts | 9 +- .../checkbox-field.component.spec.ts | 4 +- .../input-field/input-field.component.spec.ts | 8 +- .../typeahead-field.component.spec.ts | 4 +- .../edit-license-modal.component.spec.ts | 6 +- 10 files changed, 168 insertions(+), 45 deletions(-) diff --git a/src/app/common/base-test.helpers.spec.ts b/src/app/common/base-test.helpers.spec.ts index 88255a9ec..249eeb53f 100644 --- a/src/app/common/base-test.helpers.spec.ts +++ b/src/app/common/base-test.helpers.spec.ts @@ -105,12 +105,12 @@ export const snapshotParamMapMock = { }, }; -export function findInputElememtByDataTestId(fixture: ComponentFixture, id: string): HTMLInputElement { +export function getInputElememtByDataTestId(fixture: ComponentFixture, id: string): HTMLInputElement { return getElementByDataTestId(fixture, id) as HTMLInputElement; } export function dispatchInputEvent(fixture: ComponentFixture, id: string, value: string): void { - const element = findInputElememtByDataTestId(fixture, id); + const element = getInputElememtByDataTestId(fixture, id); element.value = value; element.dispatchEvent(new Event("input")); fixture.detectChanges(); diff --git a/src/app/common/table.helper.ts b/src/app/common/table.helper.ts index e42a9bf77..3855b5a80 100644 --- a/src/app/common/table.helper.ts +++ b/src/app/common/table.helper.ts @@ -5,6 +5,6 @@ export const extractSchemaFieldsFromData = (data: DataRow): DataSchemaField[] => name: item, repetition: "", type: "", - logical_type: "", + logicalType: "", })); }; diff --git a/src/app/dataset-create/dataset-create.component.spec.ts b/src/app/dataset-create/dataset-create.component.spec.ts index cd5c1bf83..562200810 100644 --- a/src/app/dataset-create/dataset-create.component.spec.ts +++ b/src/app/dataset-create/dataset-create.component.spec.ts @@ -1,5 +1,5 @@ import { of } from "rxjs"; -import { findInputElememtByDataTestId } from "src/app/common/base-test.helpers.spec"; +import { getInputElememtByDataTestId } from "src/app/common/base-test.helpers.spec"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { ChangeDetectionStrategy, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core"; import { ComponentFixture, TestBed, fakeAsync, flush, tick } from "@angular/core/testing"; @@ -49,7 +49,7 @@ describe("DatasetCreateComponent", () => { datasetCreateService.errorMessageChanges(errorMessage); tick(); fixture.detectChanges(); - const element = findInputElememtByDataTestId(fixture, "create-error-message"); + const element = getInputElememtByDataTestId(fixture, "create-error-message"); expect(element.textContent).toEqual(errorMessage); flush(); })); @@ -81,7 +81,7 @@ describe("DatasetCreateComponent", () => { }); it("should check switch checkbox `Initialize from YAML snapshot`)", () => { - const checkboxInput = findInputElememtByDataTestId(fixture, "show-monaco-editor"); + const checkboxInput = getInputElememtByDataTestId(fixture, "show-monaco-editor"); expect(checkboxInput.checked).toBeFalse(); expect(component.showMonacoEditor).toBeFalse(); @@ -97,7 +97,7 @@ describe("DatasetCreateComponent", () => { }); it("should check call uploadFile when file picked)", async () => { - const checkboxInput = findInputElememtByDataTestId(fixture, "show-monaco-editor"); + const checkboxInput = getInputElememtByDataTestId(fixture, "show-monaco-editor"); checkboxInput.click(); fixture.detectChanges(); @@ -115,7 +115,7 @@ describe("DatasetCreateComponent", () => { }); it("should check call uploadFile when file not picked)", async () => { - const checkboxInput = findInputElememtByDataTestId(fixture, "show-monaco-editor"); + const checkboxInput = getInputElememtByDataTestId(fixture, "show-monaco-editor"); checkboxInput.click(); fixture.detectChanges(); diff --git a/src/app/dataset-view/additional-components/dataset-settings-component/dataset-settings.component.html b/src/app/dataset-view/additional-components/dataset-settings-component/dataset-settings.component.html index ab588dba6..75328ec02 100644 --- a/src/app/dataset-view/additional-components/dataset-settings-component/dataset-settings.component.html +++ b/src/app/dataset-view/additional-components/dataset-settings-component/dataset-settings.component.html @@ -53,12 +53,22 @@

General

> Rename -
- Name is required - Invalid dataset name +
+ Name is required + Invalid dataset name
-
{{ renameError }}
+
{{ renameError }}
diff --git a/src/app/dataset-view/additional-components/dataset-settings-component/dataset-settings.component.spec.ts b/src/app/dataset-view/additional-components/dataset-settings-component/dataset-settings.component.spec.ts index 9a1551efa..fad79d61c 100644 --- a/src/app/dataset-view/additional-components/dataset-settings-component/dataset-settings.component.spec.ts +++ b/src/app/dataset-view/additional-components/dataset-settings-component/dataset-settings.component.spec.ts @@ -6,13 +6,19 @@ import { ApolloTestingModule } from "apollo-angular/testing"; import { Apollo, ApolloModule } from "apollo-angular"; import { DatasetSettingsService } from "./services/dataset-settings.service"; import { mockDatasetBasicsDerivedFragment, mockFullPowerDatasetPermissionsFragment } from "src/app/search/mock.data"; -import { emitClickOnElementByDataTestId, findInputElememtByDataTestId } from "src/app/common/base-test.helpers.spec"; +import { + checkVisible, + dispatchInputEvent, + emitClickOnElementByDataTestId, + getInputElememtByDataTestId, +} from "src/app/common/base-test.helpers.spec"; import { MatDividerModule } from "@angular/material/divider"; import { MatIconModule } from "@angular/material/icon"; import { AngularSvgIconModule } from "angular-svg-icon"; import { HttpClientTestingModule } from "@angular/common/http/testing"; import { of } from "rxjs"; import { ModalService } from "src/app/components/modal/modal.service"; +import _ from "lodash"; describe("DatasetSettingsTabComponent", () => { let component: DatasetSettingsTabComponent; @@ -39,48 +45,156 @@ describe("DatasetSettingsTabComponent", () => { fixture = TestBed.createComponent(DatasetSettingsTabComponent); component = fixture.componentInstance; component.datasetBasics = mockDatasetBasicsDerivedFragment; - component.datasetPermissions = mockFullPowerDatasetPermissionsFragment; + component.datasetPermissions = _.cloneDeep(mockFullPowerDatasetPermissionsFragment); datasetSettingsService = TestBed.inject(DatasetSettingsService); modalService = TestBed.inject(ModalService); fixture.detectChanges(); }); + enum Elements { + RenameDatasetButton = "rename-dataset-button", + RenameDatasetInput = "rename-dataset-input", + + RenameDatasetErrorNameRequired = "rename-dataset-error-name-required", + RenameDatasetErrorPattern = "rename-dataset-error-name-pattern", + RenameDatasetErrorCustom = "rename-dataset-error-custom", + + DeleteDatasetButton = "delete-dataset-button", + } + it("should create", () => { expect(component).toBeTruthy(); }); + it("should check default state of properties", () => { + expect(component.isDeleteDatasetDisabled).toEqual(false); + expect(component.renameDatasetForm.disabled).toEqual(false); + }); + + it("should check missing canDelete permission", () => { + component.datasetPermissions.permissions.canDelete = false; + fixture.detectChanges(); + + expect(component.isDeleteDatasetDisabled).toEqual(true); + expect(component.renameDatasetForm.disabled).toEqual(false); + }); + + it("should check missing rename permission", () => { + component.datasetPermissions.permissions.canRename = false; + component.ngOnInit(); + fixture.detectChanges(); + + expect(component.isDeleteDatasetDisabled).toEqual(false); + expect(component.renameDatasetForm.disabled).toEqual(true); + }); + + it("should check rename dataset", () => { + const renameDatasetSpy = spyOn(datasetSettingsService, "renameDataset").and.returnValue(of()); + + dispatchInputEvent(fixture, Elements.RenameDatasetInput, "someName"); + emitClickOnElementByDataTestId(fixture, Elements.RenameDatasetButton); + + expect(renameDatasetSpy).toHaveBeenCalledOnceWith( + component.datasetBasics.owner.name, + component.datasetBasics.id, + "someName", + ); + checkVisible(fixture, Elements.RenameDatasetErrorNameRequired, false); + checkVisible(fixture, Elements.RenameDatasetErrorPattern, false); + checkVisible(fixture, Elements.RenameDatasetErrorCustom, false); + }); + it("should check init renameError", fakeAsync(() => { const errorMessage = "Dataset is already exist."; datasetSettingsService.errorRenameDatasetChanges(errorMessage); - tick(); fixture.detectChanges(); - const elemInput = findInputElememtByDataTestId(fixture, "rename-dataset-input"); + + tick(); + + const elemInput = getInputElememtByDataTestId(fixture, "rename-dataset-input"); expect(elemInput).toHaveClass("error-border-color"); + + checkVisible(fixture, Elements.RenameDatasetErrorNameRequired, false); + checkVisible(fixture, Elements.RenameDatasetErrorPattern, false); + checkVisible(fixture, Elements.RenameDatasetErrorCustom, true); + flush(); })); - it("should check rename dataset", () => { - const renameDatasetSpy = spyOn(datasetSettingsService, "renameDataset").and.returnValue(of()); - emitClickOnElementByDataTestId(fixture, "rename-dataset-button"); - expect(renameDatasetSpy).toHaveBeenCalledTimes(1); + it("should check rename validation required", () => { + const renameDatasetSpy = spyOn(component, "renameDataset").and.stub(); + + dispatchInputEvent(fixture, Elements.RenameDatasetInput, ""); + emitClickOnElementByDataTestId(fixture, Elements.RenameDatasetButton); + + expect(renameDatasetSpy).not.toHaveBeenCalled(); + + checkVisible(fixture, Elements.RenameDatasetErrorNameRequired, true); + checkVisible(fixture, Elements.RenameDatasetErrorPattern, false); + checkVisible(fixture, Elements.RenameDatasetErrorCustom, false); }); - it("should check renameError is empty", fakeAsync(() => { + it("should check rename validation pattern", () => { + const renameDatasetSpy = spyOn(component, "renameDataset").and.stub(); + + dispatchInputEvent(fixture, Elements.RenameDatasetInput, "#illegal#"); + emitClickOnElementByDataTestId(fixture, Elements.RenameDatasetButton); + + expect(renameDatasetSpy).not.toHaveBeenCalled(); + + checkVisible(fixture, Elements.RenameDatasetErrorNameRequired, false); + checkVisible(fixture, Elements.RenameDatasetErrorPattern, true); + checkVisible(fixture, Elements.RenameDatasetErrorCustom, false); + }); + + it("should check renameError is empty after keyup", fakeAsync(() => { const errorMessage = "Dataset is already exist."; datasetSettingsService.errorRenameDatasetChanges(errorMessage); - const input = findInputElememtByDataTestId(fixture, "rename-dataset-input"); - input.value = "newDatasetName"; - input.dispatchEvent(new Event("keyup")); + + const renameDatasetInput = getInputElememtByDataTestId(fixture, Elements.RenameDatasetInput); + renameDatasetInput.dispatchEvent(new Event("keyup")); + fixture.detectChanges(); + tick(); + + expect(renameDatasetInput).not.toHaveClass("error-border-color"); + flush(); + })); + + it("should check delete modal window is shown and sends API call after confirm", fakeAsync(() => { + const modalServiceSpy = spyOn(modalService, "error").and.callFake((options) => { + options.handler?.call(undefined, true); + return Promise.resolve(""); + }); + const deleteDatasetSpy = spyOn(datasetSettingsService, "deleteDataset").and.returnValue(of()); + + emitClickOnElementByDataTestId(fixture, Elements.DeleteDatasetButton); + expect(modalServiceSpy).toHaveBeenCalledTimes(1); fixture.detectChanges(); - expect(input).not.toHaveClass("error-border-color"); + + tick(); + + expect(deleteDatasetSpy).toHaveBeenCalledOnceWith(component.datasetBasics.id); + flush(); })); - it("should check modal window is shown", () => { - const modalServiceSpy = spyOn(modalService, "error").and.callThrough(); - emitClickOnElementByDataTestId(fixture, "delete-dataset-button"); + it("should check delete modal window is shown and does not send API call after reject", fakeAsync(() => { + const modalServiceSpy = spyOn(modalService, "error").and.callFake((options) => { + options.handler?.call(undefined, false); + return Promise.resolve(""); + }); + const deleteDatasetSpy = spyOn(datasetSettingsService, "deleteDataset").and.stub(); + + emitClickOnElementByDataTestId(fixture, Elements.DeleteDatasetButton); expect(modalServiceSpy).toHaveBeenCalledTimes(1); - }); + fixture.detectChanges(); + + tick(); + + expect(deleteDatasetSpy).not.toHaveBeenCalled(); + + flush(); + })); }); diff --git a/src/app/dataset-view/additional-components/dataset-settings-component/dataset-settings.component.ts b/src/app/dataset-view/additional-components/dataset-settings-component/dataset-settings.component.ts index 6acfdf148..633ce24f7 100644 --- a/src/app/dataset-view/additional-components/dataset-settings-component/dataset-settings.component.ts +++ b/src/app/dataset-view/additional-components/dataset-settings-component/dataset-settings.component.ts @@ -6,7 +6,6 @@ import { promiseWithCatch } from "src/app/common/app.helpers"; import { BaseComponent } from "src/app/common/base.component"; import { ModalService } from "src/app/components/modal/modal.service"; import { Observable, shareReplay } from "rxjs"; -import { MaybeNull } from "src/app/common/app.types"; @Component({ selector: "app-dataset-settings", @@ -42,8 +41,8 @@ export class DatasetSettingsTabComponent extends BaseComponent implements OnInit } } - public get datasetName(): MaybeNull { - return this.renameDatasetForm.get("datasetName"); + public get datasetNameControl(): AbstractControl { + return this.renameDatasetForm.controls.datasetName; } public get isDeleteDatasetDisabled(): boolean { @@ -52,10 +51,10 @@ export class DatasetSettingsTabComponent extends BaseComponent implements OnInit public renameDataset(): void { const datasetId = this.datasetBasics.id; - const accountName = this.getDatasetInfoFromUrl().accountName; + const accountName = this.datasetBasics.owner.name; this.trackSubscription( this.datasetSettingsService - .renameDataset(accountName, datasetId, this.datasetName?.value as string) + .renameDataset(accountName, datasetId, this.datasetNameControl.value as string) .subscribe(), ); } diff --git a/src/app/dataset-view/additional-components/metadata-component/components/form-components/checkbox-field/checkbox-field.component.spec.ts b/src/app/dataset-view/additional-components/metadata-component/components/form-components/checkbox-field/checkbox-field.component.spec.ts index aadf24ba2..061d93220 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/form-components/checkbox-field/checkbox-field.component.spec.ts +++ b/src/app/dataset-view/additional-components/metadata-component/components/form-components/checkbox-field/checkbox-field.component.spec.ts @@ -3,7 +3,7 @@ import { FormControl, FormGroup, ReactiveFormsModule } from "@angular/forms"; import { CheckboxFieldComponent } from "./checkbox-field.component"; import { TooltipIconComponent } from "src/app/dataset-block/metadata-block/components/tooltip-icon/tooltip-icon.component"; import { NgbTooltipModule } from "@ng-bootstrap/ng-bootstrap"; -import { findInputElememtByDataTestId } from "src/app/common/base-test.helpers.spec"; +import { getInputElememtByDataTestId } from "src/app/common/base-test.helpers.spec"; import { SharedTestModule } from "src/app/common/shared-test.module"; describe("CheckboxFieldComponent", () => { @@ -31,7 +31,7 @@ describe("CheckboxFieldComponent", () => { }); it("should check state control", () => { - const element = findInputElememtByDataTestId(fixture, "checkbox"); + const element = getInputElememtByDataTestId(fixture, "checkbox"); expect(element.checked).toBe(false); expect(component.form.controls.test.value).toBe(false); diff --git a/src/app/dataset-view/additional-components/metadata-component/components/form-components/input-field/input-field.component.spec.ts b/src/app/dataset-view/additional-components/metadata-component/components/form-components/input-field/input-field.component.spec.ts index 635357aa7..1c76adb40 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/form-components/input-field/input-field.component.spec.ts +++ b/src/app/dataset-view/additional-components/metadata-component/components/form-components/input-field/input-field.component.spec.ts @@ -4,7 +4,7 @@ import { FormControl, FormGroup, ReactiveFormsModule, Validators } from "@angula import { InputFieldComponent } from "./input-field.component"; import { TooltipIconComponent } from "src/app/dataset-block/metadata-block/components/tooltip-icon/tooltip-icon.component"; import { NgbTooltipModule } from "@ng-bootstrap/ng-bootstrap"; -import { dispatchInputEvent, findInputElememtByDataTestId } from "src/app/common/base-test.helpers.spec"; +import { dispatchInputEvent, getInputElememtByDataTestId } from "src/app/common/base-test.helpers.spec"; import { ChangeDetectionStrategy } from "@angular/core"; import AppValues from "src/app/common/app.values"; import { SharedTestModule } from "src/app/common/shared-test.module"; @@ -41,7 +41,7 @@ describe("InputFieldComponent", () => { fixture.detectChanges(); dispatchInputEvent(fixture, "input", ""); - const requiredMessage = findInputElememtByDataTestId(fixture, "error-test-required"); + const requiredMessage = getInputElememtByDataTestId(fixture, "error-test-required"); expect(requiredMessage.textContent?.trim()).toBe("Field is required"); }); @@ -53,7 +53,7 @@ describe("InputFieldComponent", () => { dispatchInputEvent(fixture, "input", "mock"); - const maxLengthdMessage = findInputElememtByDataTestId(fixture, "error-test-maxLength"); + const maxLengthdMessage = getInputElememtByDataTestId(fixture, "error-test-maxLength"); expect(maxLengthdMessage.textContent?.trim()).toBe("Field can be max 1 character"); }); @@ -62,7 +62,7 @@ describe("InputFieldComponent", () => { dispatchInputEvent(fixture, "input", "mock"); - const patternMessage = findInputElememtByDataTestId(fixture, "error-test-pattern"); + const patternMessage = getInputElememtByDataTestId(fixture, "error-test-pattern"); expect(patternMessage.textContent?.trim()).toBe("Field format is wrong"); }); }); diff --git a/src/app/dataset-view/additional-components/metadata-component/components/form-components/typeahead-field/typeahead-field.component.spec.ts b/src/app/dataset-view/additional-components/metadata-component/components/form-components/typeahead-field/typeahead-field.component.spec.ts index f36cfef88..feacd42bb 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/form-components/typeahead-field/typeahead-field.component.spec.ts +++ b/src/app/dataset-view/additional-components/metadata-component/components/form-components/typeahead-field/typeahead-field.component.spec.ts @@ -5,7 +5,7 @@ import { TypeaheadFieldComponent } from "./typeahead-field.component"; import { TooltipIconComponent } from "src/app/dataset-block/metadata-block/components/tooltip-icon/tooltip-icon.component"; import { MatIconModule } from "@angular/material/icon"; import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from "@angular/forms"; -import { findInputElememtByDataTestId } from "src/app/common/base-test.helpers.spec"; +import { getInputElememtByDataTestId } from "src/app/common/base-test.helpers.spec"; import { interval } from "rxjs"; import { map, take } from "rxjs/operators"; import AppValues from "src/app/common/app.values"; @@ -56,7 +56,7 @@ describe("TypeaheadFieldComponent", () => { }); it("should check call search method", fakeAsync(() => { - const inputEl = findInputElememtByDataTestId(fixture, "typeahead"); + const inputEl = getInputElememtByDataTestId(fixture, "typeahead"); inputEl.click(); const textMock$ = interval(100).pipe( take(2), diff --git a/src/app/dataset-view/additional-components/overview-component/components/edit-license-modal/edit-license-modal.component.spec.ts b/src/app/dataset-view/additional-components/overview-component/components/edit-license-modal/edit-license-modal.component.spec.ts index b54910a33..0480b5f36 100644 --- a/src/app/dataset-view/additional-components/overview-component/components/edit-license-modal/edit-license-modal.component.spec.ts +++ b/src/app/dataset-view/additional-components/overview-component/components/edit-license-modal/edit-license-modal.component.spec.ts @@ -7,7 +7,7 @@ import { DatasetOverviewFragment, DatasetDataSizeFragment } from "src/app/api/ka import { emitClickOnElementByDataTestId, getElementByDataTestId, - findInputElememtByDataTestId, + getInputElememtByDataTestId, } from "src/app/common/base-test.helpers.spec"; import { mockDatasetBasicsDerivedFragment } from "src/app/search/mock.data"; import { mockMetadataDerivedUpdate, mockOverviewDataUpdate, mockOverviewWithSetLicense } from "../../../data-tabs.mock"; @@ -77,7 +77,7 @@ describe("EditLicenseModalComponent", () => { component.licenseForm.patchValue({ websiteUrl: "bad url", }); - const inputEl: HTMLInputElement = findInputElememtByDataTestId(fixture, `license-websiteUrl`); + const inputEl: HTMLInputElement = getInputElememtByDataTestId(fixture, `license-websiteUrl`); const focusEvent = new InputEvent("focus"); inputEl.dispatchEvent(focusEvent); fixture.detectChanges(); @@ -99,7 +99,7 @@ describe("EditLicenseModalComponent", () => { fixture.detectChanges(); ["name", "shortName", "websiteUrl"].forEach((controlName: string) => { - const inputEl: HTMLInputElement = findInputElememtByDataTestId(fixture, `license-${controlName}`); + const inputEl: HTMLInputElement = getInputElememtByDataTestId(fixture, `license-${controlName}`); const focusEvent = new InputEvent("focus"); inputEl.dispatchEvent(focusEvent);