fix(ui): upgrade react to v19

This commit is contained in:
Lukasz Mierzwa
2026-02-24 12:14:19 +00:00
committed by Łukasz Mierzwa
parent b94fcbf028
commit e372b7da64
81 changed files with 1816 additions and 1174 deletions

View File

@@ -25,16 +25,26 @@ const AlertGroupConfiguration: FC<{
values={defaultRenderCount}
onChange={(values) => setDefaultRenderCount(values)}
onFinalChange={(values) => onChangeComplete(values[0])}
renderTrack={({ props, children }) => (
<div className="input-range-track" {...props}>
{children}
</div>
)}
renderThumb={({ props }) => (
<div className="input-range-thumb" {...props}>
{defaultRenderCount}
</div>
)}
renderTrack={({ props, children }) => {
const { key, ...restProps } = props as typeof props & {
key?: string;
};
return (
<div key={key} className="input-range-track" {...restProps}>
{children}
</div>
);
}}
renderThumb={({ props }) => {
const { key, ...restProps } = props as typeof props & {
key?: string;
};
return (
<div key={key} className="input-range-thumb" {...restProps}>
{defaultRenderCount}
</div>
);
}}
/>
</div>
);

View File

@@ -1,4 +1,7 @@
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { act } from "react";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Settings } from "Stores/Settings";
import { AlertGroupTitleBarColor } from "./AlertGroupTitleBarColor";
@@ -14,33 +17,43 @@ const renderConfiguration = () => {
describe("<AlertGroupTitleBarColor />", () => {
it("matches snapshot with default values", () => {
// Verifies component renders correctly with default settings
const { asFragment } = renderConfiguration();
expect(asFragment()).toMatchSnapshot();
});
it("colorTitleBar is 'false' by default", () => {
// Verifies default value of colorTitleBar setting
expect(settingsStore.alertGroupConfig.config.colorTitleBar).toBe(false);
});
it("unchecking the checkbox sets stored colorTitleBar value to 'false'", async () => {
// Verifies clicking checkbox when checked sets store value to false
const user = userEvent.setup();
renderConfiguration();
const checkbox = screen.getByRole("checkbox");
settingsStore.alertGroupConfig.setColorTitleBar(true);
act(() => {
settingsStore.alertGroupConfig.setColorTitleBar(true);
});
expect(settingsStore.alertGroupConfig.config.colorTitleBar).toBe(true);
fireEvent.click(checkbox);
await user.click(checkbox);
await waitFor(() => {
expect(settingsStore.alertGroupConfig.config.colorTitleBar).toBe(false);
});
});
it("checking the checkbox sets stored colorTitleBar value to 'true'", async () => {
// Verifies clicking checkbox when unchecked sets store value to true
const user = userEvent.setup();
renderConfiguration();
const checkbox = screen.getByRole("checkbox");
settingsStore.alertGroupConfig.setColorTitleBar(false);
act(() => {
settingsStore.alertGroupConfig.setColorTitleBar(false);
});
expect(settingsStore.alertGroupConfig.config.colorTitleBar).toBe(false);
fireEvent.click(checkbox);
await user.click(checkbox);
await waitFor(() => {
expect(settingsStore.alertGroupConfig.config.colorTitleBar).toBe(true);
});

View File

@@ -27,16 +27,26 @@ const AlertGroupWidthConfiguration: FC<{
values={groupWidth}
onChange={(values) => setGroupWidth(values)}
onFinalChange={(values) => onChangeComplete(values[0])}
renderTrack={({ props, children }) => (
<div className="input-range-track" {...props}>
{children}
</div>
)}
renderThumb={({ props }) => (
<div className="input-range-thumb" {...props}>
{groupWidth}
</div>
)}
renderTrack={({ props, children }) => {
const { key, ...restProps } = props as typeof props & {
key?: string;
};
return (
<div key={key} className="input-range-track" {...restProps}>
{children}
</div>
);
}}
renderThumb={({ props }) => {
const { key, ...restProps } = props as typeof props & {
key?: string;
};
return (
<div key={key} className="input-range-thumb" {...restProps}>
{groupWidth}
</div>
);
}}
/>
</div>
);

View File

@@ -25,16 +25,26 @@ const FetchConfiguration: FC<{
values={fetchInterval}
onChange={(values) => setFetchInterval(values)}
onFinalChange={(values) => onChangeComplete(values[0])}
renderTrack={({ props, children }) => (
<div className="input-range-track" {...props}>
{children}
</div>
)}
renderThumb={({ props }) => (
<div className="input-range-thumb" {...props}>
{fetchInterval}s
</div>
)}
renderTrack={({ props, children }) => {
const { key, ...restProps } = props as typeof props & {
key?: string;
};
return (
<div key={key} className="input-range-track" {...restProps}>
{children}
</div>
);
}}
renderThumb={({ props }) => {
const { key, ...restProps } = props as typeof props & {
key?: string;
};
return (
<div key={key} className="input-range-thumb" {...restProps}>
{fetchInterval}s
</div>
);
}}
/>
</div>
);

View File

@@ -1,4 +1,7 @@
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { act } from "react";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Settings } from "Stores/Settings";
import { FilterBarConfiguration } from "./FilterBarConfiguration";
@@ -14,28 +17,35 @@ const renderConfiguration = () => {
describe("<FilterBarConfiguration />", () => {
it("matches snapshot with default values", () => {
// Verifies component renders correctly with default settings
const { asFragment } = renderConfiguration();
expect(asFragment()).toMatchSnapshot();
});
it("unchecking the checkbox sets stored autohide value to 'false'", async () => {
// Verifies clicking checkbox when checked sets store value to false
const user = userEvent.setup();
renderConfiguration();
const checkbox = screen.getByRole("checkbox");
expect(settingsStore.filterBarConfig.config.autohide).toBe(true);
fireEvent.click(checkbox);
await user.click(checkbox);
await waitFor(() => {
expect(settingsStore.filterBarConfig.config.autohide).toBe(false);
});
});
it("checking the checkbox sets stored autohide value to 'true'", async () => {
// Verifies clicking checkbox when unchecked sets store value to true
const user = userEvent.setup();
renderConfiguration();
const checkbox = screen.getByRole("checkbox");
settingsStore.filterBarConfig.setAutohide(false);
act(() => {
settingsStore.filterBarConfig.setAutohide(false);
});
expect(settingsStore.filterBarConfig.config.autohide).toBe(false);
fireEvent.click(checkbox);
await user.click(checkbox);
await waitFor(() => {
expect(settingsStore.filterBarConfig.config.autohide).toBe(true);
});

View File

@@ -8,6 +8,7 @@ import { Accordion, AccordionItem } from "Components/Accordion";
const FilterOperatorHelp: FC<{
operator: string;
description: string;
children?: ReactNode;
}> = ({ operator, description, children }) => (
<>
<dt>
@@ -31,6 +32,7 @@ const QueryHelp: FC<{
title: string;
operators: string[];
warning?: ReactNode;
children: ReactNode;
}> = ({ title, operators, warning, children }) => (
<>
<dt>{title}</dt>
@@ -57,6 +59,7 @@ const QueryHelp: FC<{
const FilterExample: FC<{
example: string;
children: ReactNode;
}> = ({ example, children }) => (
<li>
<div>

View File

@@ -1,4 +1,16 @@
import { act } from "react-dom/test-utils";
// Mock react-cool-dimensions to avoid ResizeObserver console.error
jest.mock("react-cool-dimensions", () => ({
__esModule: true,
default: () => ({
observe: jest.fn(),
unobserve: jest.fn(),
width: 1000,
height: 500,
entry: undefined,
}),
}));
import { act } from "react";
import { render, screen, fireEvent } from "@testing-library/react";
@@ -30,23 +42,29 @@ afterEach(() => {
document.body.className = "";
});
const renderMainModal = () => {
return render(
<ThemeContext.Provider value={MockThemeContext}>
<MainModal alertStore={alertStore} settingsStore={settingsStore} />
</ThemeContext.Provider>,
);
const renderMainModal = async () => {
let result: ReturnType<typeof render>;
await act(async () => {
result = render(
<ThemeContext.Provider value={MockThemeContext}>
<MainModal alertStore={alertStore} settingsStore={settingsStore} />
</ThemeContext.Provider>,
);
});
return result!;
};
describe("<MainModal />", () => {
it("only renders FontAwesomeIcon when modal is not shown", () => {
const { container } = renderMainModal();
it("only renders FontAwesomeIcon when modal is not shown", async () => {
// Verifies only toggle icon is rendered when modal is closed
const { container } = await renderMainModal();
expect(container.querySelectorAll("svg")).toHaveLength(1);
expect(screen.queryByText("Configuration")).not.toBeInTheDocument();
});
it("renders a spinner placeholder while modal content is loading", () => {
const { container } = renderMainModal();
it("renders a spinner placeholder while modal content is loading", async () => {
// Verifies spinner is shown while lazy content loads
const { container } = await renderMainModal();
const toggle = container.querySelector(".nav-link");
fireEvent.click(toggle!);
expect(
@@ -54,15 +72,19 @@ describe("<MainModal />", () => {
).toBeInTheDocument();
});
it("renders modal content if fallback is not used", () => {
const { container } = renderMainModal();
it("renders modal content if fallback is not used", async () => {
// Verifies modal content is rendered after lazy loading
const { container } = await renderMainModal();
const toggle = container.querySelector(".nav-link");
fireEvent.click(toggle!);
await act(async () => {
fireEvent.click(toggle!);
});
expect(screen.getByText("Configuration")).toBeInTheDocument();
});
it("hides the modal when toggle() is called twice", () => {
const { container } = renderMainModal();
it("hides the modal when toggle() is called twice", async () => {
// Verifies modal closes when toggle is clicked twice
const { container } = await renderMainModal();
const toggle = container.querySelector(".nav-link");
fireEvent.click(toggle!);
@@ -78,8 +100,9 @@ describe("<MainModal />", () => {
expect(screen.queryByText("Configuration")).not.toBeInTheDocument();
});
it("hides the modal when button.btn-close is clicked", () => {
const { container } = renderMainModal();
it("hides the modal when button.btn-close is clicked", async () => {
// Verifies modal closes when close button is clicked
const { container } = await renderMainModal();
const toggle = container.querySelector(".nav-link");
fireEvent.click(toggle!);
@@ -93,15 +116,17 @@ describe("<MainModal />", () => {
expect(screen.queryByText("Configuration")).not.toBeInTheDocument();
});
it("'modal-open' class is appended to body node when modal is visible", () => {
const { container } = renderMainModal();
it("'modal-open' class is appended to body node when modal is visible", async () => {
// Verifies modal-open class is added to body when modal opens
const { container } = await renderMainModal();
const toggle = container.querySelector(".nav-link");
fireEvent.click(toggle!);
expect(document.body.className.split(" ")).toContain("modal-open");
});
it("'modal-open' class is removed from body node after modal is hidden", () => {
const { container } = renderMainModal();
it("'modal-open' class is removed from body node after modal is hidden", async () => {
// Verifies modal-open class is removed from body when modal closes
const { container } = await renderMainModal();
const toggle = container.querySelector(".nav-link");
fireEvent.click(toggle!);
@@ -114,8 +139,9 @@ describe("<MainModal />", () => {
expect(document.body.className.split(" ")).not.toContain("modal-open");
});
it("'modal-open' class is removed from body node after modal is unmounted", () => {
const { container, unmount } = renderMainModal();
it("'modal-open' class is removed from body node after modal is unmounted", async () => {
// Verifies modal-open class is removed from body when component unmounts
const { container, unmount } = await renderMainModal();
const toggle = container.querySelector(".nav-link");
fireEvent.click(toggle!);
unmount();