fix(ui): fix tests

This commit is contained in:
Lukasz Mierzwa
2026-04-29 10:14:47 +01:00
committed by Łukasz Mierzwa
parent 0be1fff69e
commit 0329093114
12 changed files with 69 additions and 31 deletions
@@ -2,9 +2,8 @@ import { act, createRef } from "react";
import { render, fireEvent } from "@testing-library/react";
import copy from "copy-to-clipboard";
import { MockAlertGroup, MockAlert } from "__fixtures__/Alerts";
import { mockClipboard } from "__fixtures__/Clipboard";
import type {
APIAlertGroupT,
APIAlertT,
@@ -22,6 +21,7 @@ let group: APIAlertGroupT;
let MockAfterClick: () => void;
let MockSetIsMenuOpen: () => void;
let writeText: jest.Mock;
const generateUpstreams = (): APIAlertsResponseUpstreamsT => ({
counters: { total: 1, healthy: 1, failed: 0 },
@@ -68,6 +68,7 @@ const generateUpstreams = (): APIAlertsResponseUpstreamsT => ({
beforeEach(() => {
jest.useFakeTimers();
writeText = mockClipboard();
alertStore = new AlertStore([]);
silenceFormStore = new SilenceFormStore();
@@ -286,7 +287,10 @@ describe("<MenuContent />", () => {
const { container } = renderMenuContent(group);
const buttons = container.querySelectorAll(".dropdown-item");
fireEvent.click(buttons[1]);
expect(copy).toHaveBeenCalledWith(
// flush async clipboard write from copy-to-clipboard
await act(() => jest.advanceTimersByTimeAsync(0));
expect(writeText).toHaveBeenCalledTimes(1);
expect(writeText).toHaveBeenCalledWith(
JSON.stringify(alertToJSON(group, alert)),
);
});
@@ -127,7 +127,7 @@ const MenuContent = observer(
<div
className="dropdown-item cursor-pointer"
onClick={() => {
copy(JSON.stringify(alertToJSON(group, alert)));
void copy(JSON.stringify(alertToJSON(group, alert)));
afterClick();
}}
>
@@ -2,9 +2,8 @@ import { act } from "react";
import { render, fireEvent } from "@testing-library/react";
import copy from "copy-to-clipboard";
import { MockAlertGroup } from "__fixtures__/Alerts";
import { mockClipboard } from "__fixtures__/Clipboard";
import type {
APIAlertGroupT,
APIAlertsResponseUpstreamsT,
@@ -18,6 +17,7 @@ let silenceFormStore: SilenceFormStore;
let MockAfterClick: () => void;
let MockSetIsMenuOpen: () => void;
let writeText: jest.Mock;
const generateUpstreams = (): APIAlertsResponseUpstreamsT => ({
counters: { total: 3, healthy: 3, failed: 0 },
@@ -68,6 +68,7 @@ beforeEach(() => {
jest.useFakeTimers();
jest.clearAllMocks();
writeText = mockClipboard();
MockAfterClick = jest.fn();
MockSetIsMenuOpen = jest.fn();
@@ -188,7 +189,7 @@ const renderMenuContent = (group: APIAlertGroupT) => {
};
describe("<MenuContent />", () => {
it("clicking on 'Copy' icon copies the link to clickboard", () => {
it("clicking on 'Copy' icon copies the link to clickboard", async () => {
const group = MockAlertGroup(
[{ name: "alertname", value: "Fake Alert" }],
[],
@@ -199,7 +200,9 @@ describe("<MenuContent />", () => {
const { container } = renderMenuContent(group);
const buttons = container.querySelectorAll(".dropdown-item");
fireEvent.click(buttons[0]);
expect(copy).toHaveBeenCalledTimes(1);
// flush async clipboard write from copy-to-clipboard
await act(() => jest.advanceTimersByTimeAsync(0));
expect(writeText).toHaveBeenCalledTimes(1);
});
it("clicking on 'Silence' icon opens the silence form modal", () => {
@@ -118,7 +118,7 @@ const MenuContent: FC<{
<div
className="dropdown-item cursor-pointer"
onClick={() => {
copy(groupLink);
void copy(groupLink);
afterClick();
}}
>
@@ -1,15 +1,18 @@
import { act } from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import copy from "copy-to-clipboard";
import { AlertStore, NewUnappliedFilter } from "Stores/AlertStore";
import { mockClipboard } from "__fixtures__/Clipboard";
import FilteringLabel from ".";
let alertStore: AlertStore;
let writeText: jest.Mock;
beforeEach(() => {
alertStore = new AlertStore([]);
writeText = mockClipboard();
});
const renderFilteringLabel = (name: string, value: string) => {
@@ -60,9 +63,12 @@ describe("<FilteringLabel />", () => {
);
});
it("calling onClick() while holding Shift key copies label value to clipboard", () => {
it("calling onClick() while holding Shift key copies label value to clipboard", async () => {
renderAndClick("foo", "bar", { shiftKey: true });
expect(copy).toHaveBeenCalledWith("bar");
// flush async clipboard write from copy-to-clipboard
await act(async () => {});
expect(writeText).toHaveBeenCalledTimes(1);
expect(writeText).toHaveBeenCalledWith("bar");
});
it("label with dark background color should have 'components-label-dark' class", () => {
@@ -23,7 +23,7 @@ const FilteringLabel: FC<{
event.preventDefault();
if (event.shiftKey) {
copy(value);
void copy(value);
return;
}
@@ -1,8 +1,9 @@
import { act } from "react";
import { render, fireEvent } from "@testing-library/react";
import copy from "copy-to-clipboard";
import { MockSilence } from "__fixtures__/Alerts";
import { mockClipboard } from "__fixtures__/Clipboard";
import type { APIAlertsResponseUpstreamsT, APISilenceT } from "Models/APITypes";
import { AlertStore } from "Stores/AlertStore";
import { SilenceFormStore } from "Stores/SilenceFormStore";
@@ -12,6 +13,7 @@ let alertStore: AlertStore;
let silenceFormStore: SilenceFormStore;
let cluster: string;
let silence: APISilenceT;
let writeText: jest.Mock;
const MockEditSilence = jest.fn();
@@ -43,6 +45,7 @@ beforeEach(() => {
alertStore.data.setUpstreams(generateUpstreams());
jest.restoreAllMocks();
writeText = mockClipboard();
jest.useFakeTimers();
});
@@ -86,12 +89,14 @@ describe("<SilenceDetails />", () => {
);
});
it("clicking on the copy button copies silence ID to the clipboard", () => {
it("clicking on the copy button copies silence ID to the clipboard", async () => {
const { container } = renderSilenceDetails();
const button = container.querySelector("span.badge.bg-secondary");
fireEvent.click(button!);
expect(copy).toHaveBeenCalledTimes(1);
expect(copy).toHaveBeenCalledWith(silence.id);
// flush async clipboard write from copy-to-clipboard
await act(() => jest.advanceTimersByTimeAsync(0));
expect(writeText).toHaveBeenCalledTimes(1);
expect(writeText).toHaveBeenCalledWith(silence.id);
});
it("Edit silence button is disabled when all alertmanager instances are read-only", () => {
@@ -39,7 +39,7 @@ const SilenceIDCopyButton: FC<{
ref={ref}
className="badge bg-secondary px-1 me-1 components-label cursor-pointer"
onClick={() => {
copy(id);
void copy(id);
setClickCount(clickCount + 1);
}}
>
@@ -1,7 +1,8 @@
import { act } from "react";
import { render, fireEvent } from "@testing-library/react";
import copy from "copy-to-clipboard";
import { mockClipboard } from "__fixtures__/Clipboard";
import { MockThemeContext } from "__fixtures__/Theme";
import { AlertStore, NewUnappliedFilter } from "Stores/AlertStore";
import { Settings } from "Stores/Settings";
@@ -14,6 +15,7 @@ import type { APIAlertsResponseUpstreamsT } from "Models/APITypes";
let alertStore: AlertStore;
let settingsStore: Settings;
let silenceFormStore: SilenceFormStore;
let writeText: jest.Mock;
const generateUpstreams = (
version = "0.24.0",
@@ -47,6 +49,7 @@ beforeEach(() => {
settingsStore = new Settings(null);
silenceFormStore = new SilenceFormStore();
alertStore.data.setUpstreams(generateUpstreams());
writeText = mockClipboard();
});
const renderSilenceForm = () => {
@@ -510,7 +513,7 @@ describe("<SilenceForm /> preview", () => {
expect(container.querySelector(".mt-4")).toBeNull();
});
it("clicking on the copy button copies form link to the clipboard", () => {
it("clicking on the copy button copies form link to the clipboard", async () => {
const matcher = NewEmptyMatcher();
matcher.name = "job";
matcher.values = [
@@ -531,7 +534,9 @@ describe("<SilenceForm /> preview", () => {
);
expect(button?.innerHTML).toMatch(/fa-copy/);
fireEvent.click(button!);
expect(copy).toHaveBeenCalledTimes(1);
// flush async clipboard write from copy-to-clipboard
await act(async () => {});
expect(writeText).toHaveBeenCalledTimes(1);
});
it("silence form share link doesn't change on new input", () => {
@@ -92,7 +92,7 @@ const ShareButton: FC<{
ref={ref}
className="input-group-text text-muted cursor-pointer"
onClick={() => {
copy(`${baseURL}?m=${silenceFormStore.data.toBase64}`);
void copy(`${baseURL}?m=${silenceFormStore.data.toBase64}`);
setClickCount(clickCount + 1);
}}
>
+21
View File
@@ -0,0 +1,21 @@
// jsdom lacks navigator.clipboard and window.isSecureContext,
// mock both so copy-to-clipboard uses the async clipboard API path.
const mockClipboard = (): jest.Mock => {
const writeText = jest.fn(() => Promise.resolve());
Object.defineProperty(window, "isSecureContext", {
value: true,
writable: true,
configurable: true,
});
Object.defineProperty(navigator, "clipboard", {
value: { writeText },
writable: true,
configurable: true,
});
return writeText;
};
export { mockClipboard };
-6
View File
@@ -1,6 +0,0 @@
// mock copy-to-clipboard since it throws errors in tests
// and we don't really need to copy anything, only ensure we're calling it
const copy = jest.fn();
export default copy;