/*
Copyright (C) 2023 Cloudbase Solutions SRL
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import React, { act } from "react";
import metalHubStore from "@src/stores/MetalHubStore";
import { fireEvent, render, waitFor } from "@testing-library/react";
import { METALHUB_SERVER_MOCK } from "@tests/mocks/MetalHubServerMock";
import MetalHubModal from "./MetalHubModal";
describe("MetalHubModal", () => {
let defaultProps: MetalHubModal["props"];
let metalHubStoreSpies: {
clearValidationError: jest.SpyInstance;
patchServer: jest.SpyInstance;
validateServer: jest.SpyInstance;
addServer: jest.SpyInstance;
};
beforeEach(() => {
metalHubStoreSpies = {
clearValidationError: jest.spyOn(metalHubStore, "clearValidationError"),
patchServer: jest.spyOn(metalHubStore, "patchServer").mockResolvedValue(),
validateServer: jest
.spyOn(metalHubStore, "validateServer")
.mockResolvedValue(true),
addServer: jest.spyOn(metalHubStore, "addServer").mockResolvedValue({
...METALHUB_SERVER_MOCK,
}),
};
defaultProps = {
onRequestClose: jest.fn(),
onUpdateDone: jest.fn(),
};
});
it("renders without crashing and clears validation error on unmount", () => {
const { getByText, unmount } = render();
expect(getByText("Add Coriolis Bare Metal Server")).toBeTruthy();
unmount();
expect(metalHubStoreSpies.clearValidationError).toHaveBeenCalledTimes(1);
});
it("shows the server for editing", () => {
const { getByText } = render(
,
);
expect(getByText("Update Coriolis Bare Metal Server")).toBeTruthy();
const testInput = (label: string, value: string) => {
const input =
getByText(label).parentElement!.parentElement!.querySelector("input");
expect(input).toBeTruthy();
expect(input!.value).toBe(value);
};
testInput(
"Host",
METALHUB_SERVER_MOCK.api_endpoint!.split(":")[1].replace("//", ""),
);
testInput(
"Port",
METALHUB_SERVER_MOCK.api_endpoint!.split(":")[2].replace(/\/.*/, ""),
);
});
it("renders validation error", async () => {
await act(async () => {
metalHubStore.validationError = [
"Validation error",
"Validation error 2",
];
});
const { getByText } = render(
,
);
expect(getByText("Validation error")).toBeTruthy();
expect(getByText("Validation error 2")).toBeTruthy();
await act(async () => {
metalHubStore.validationError = [];
});
});
it("triggers submit on enter key", async () => {
render(
,
);
const input = document.querySelector("input")!;
await act(async () => {
fireEvent.keyDown(input, { key: "Enter", code: "Enter" });
});
await waitFor(() => {
expect(metalHubStoreSpies.patchServer).toHaveBeenCalledTimes(1);
});
expect(metalHubStoreSpies.validateServer).toHaveBeenCalledTimes(1);
});
it("highlights invalid fields", async () => {
const { getByText, getAllByText } = render(
,
);
await act(async () => {
fireEvent.click(getByText("Validate and save"));
});
expect(getAllByText("Required field").length).toBeGreaterThan(0);
});
it("adds new server", async () => {
const { getByText } = render();
const getInput = (label: string): HTMLInputElement =>
getByText(label).parentElement!.parentElement!.querySelector("input")!;
fireEvent.change(getInput("Host"), {
target: { value: "api.example.com" },
});
fireEvent.change(getInput("Port"), { target: { value: "5566" } });
await act(async () => {
fireEvent.click(getByText("Validate and save"));
});
await act(async () => {
expect(metalHubStoreSpies.addServer).toHaveBeenCalledWith(
"https://api.example.com:5566/api/v1",
);
});
expect(metalHubStoreSpies.validateServer).toHaveBeenCalledWith(
METALHUB_SERVER_MOCK.id,
);
});
});