Skip to content

Commit

Permalink
Increase unit test coverage in DatasetSettingsTabComponent
Browse files Browse the repository at this point in the history
  • Loading branch information
zaychenko-sergei committed Sep 8, 2023
1 parent f814901 commit ab80d21
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 45 deletions.
4 changes: 2 additions & 2 deletions src/app/common/base-test.helpers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,12 @@ export const snapshotParamMapMock = {
},
};

export function findInputElememtByDataTestId<T>(fixture: ComponentFixture<T>, id: string): HTMLInputElement {
export function getInputElememtByDataTestId<T>(fixture: ComponentFixture<T>, id: string): HTMLInputElement {
return getElementByDataTestId(fixture, id) as HTMLInputElement;
}

export function dispatchInputEvent<T>(fixture: ComponentFixture<T>, 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();
Expand Down
2 changes: 1 addition & 1 deletion src/app/common/table.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ export const extractSchemaFieldsFromData = (data: DataRow): DataSchemaField[] =>
name: item,
repetition: "",
type: "",
logical_type: "",
logicalType: "",
}));
};
10 changes: 5 additions & 5 deletions src/app/dataset-create/dataset-create.component.spec.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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();
}));
Expand Down Expand Up @@ -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();

Expand All @@ -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();
Expand All @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,22 @@ <h2>General</h2>
>
Rename
</button>
<div *ngIf="datasetName?.invalid && (datasetName?.touched || datasetName?.dirty)">
<span *ngIf="datasetName?.errors?.['required']" class="text-danger fs-12">Name is required</span>
<span *ngIf="datasetName?.errors?.['pattern']" class="text-danger fs-12">Invalid dataset name</span>
<div *ngIf="datasetNameControl.invalid && (datasetNameControl.touched || datasetNameControl.dirty)">
<span
*ngIf="datasetNameControl.errors?.required"
class="text-danger fs-12"
data-test-id="rename-dataset-error-name-required"
>Name is required</span
>
<span
*ngIf="datasetNameControl.errors?.pattern"
class="text-danger fs-12"
data-test-id="rename-dataset-error-name-pattern"
>Invalid dataset name</span
>
</div>
<div *ngIf="renameError$ | async as renameError">
<div class="error-block">{{ renameError }}</div>
<div class="error-block" data-test-id="rename-dataset-error-custom">{{ renameError }}</div>
</div>
</form>
<div class="mt-4">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
}));
});
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -42,8 +41,8 @@ export class DatasetSettingsTabComponent extends BaseComponent implements OnInit
}
}

public get datasetName(): MaybeNull<AbstractControl> {
return this.renameDatasetForm.get("datasetName");
public get datasetNameControl(): AbstractControl {
return this.renameDatasetForm.controls.datasetName;
}

public get isDeleteDatasetDisabled(): boolean {
Expand All @@ -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(),
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => {
Expand Down Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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");
});

Expand All @@ -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");
});

Expand All @@ -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");
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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),
Expand Down
Loading

0 comments on commit ab80d21

Please sign in to comment.