fix(config): stabilize config hook callbacks to prevent action/filter flicker
This commit is contained in:
74
frontend/src/hooks/__tests__/useActionConfig.test.ts
Normal file
74
frontend/src/hooks/__tests__/useActionConfig.test.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { renderHook, act } from "@testing-library/react";
|
||||
import * as configApi from "../../api/config";
|
||||
import { useActionConfig } from "../useActionConfig";
|
||||
|
||||
vi.mock("../../api/config");
|
||||
|
||||
describe("useActionConfig", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.mocked(configApi.fetchAction).mockResolvedValue({
|
||||
name: "iptables",
|
||||
filename: "iptables.conf",
|
||||
source_file: "/etc/fail2ban/action.d/iptables.conf",
|
||||
active: false,
|
||||
used_by_jails: [],
|
||||
before: null,
|
||||
after: null,
|
||||
actionstart: "",
|
||||
actionstop: "",
|
||||
actioncheck: "",
|
||||
actionban: "",
|
||||
actionunban: "",
|
||||
actionflush: "",
|
||||
definition_vars: {},
|
||||
init_vars: {},
|
||||
has_local_override: false,
|
||||
});
|
||||
vi.mocked(configApi.updateAction).mockResolvedValue(undefined);
|
||||
});
|
||||
|
||||
it("calls fetchAction exactly once for stable name and rerenders", async () => {
|
||||
const { rerender } = renderHook(
|
||||
({ name }) => useActionConfig(name),
|
||||
{ initialProps: { name: "iptables" } },
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
});
|
||||
|
||||
expect(configApi.fetchAction).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Rerender with the same action name; fetch should not be called again.
|
||||
rerender({ name: "iptables" });
|
||||
|
||||
await act(async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
});
|
||||
|
||||
expect(configApi.fetchAction).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("calls fetchAction again when name changes", async () => {
|
||||
const { rerender } = renderHook(
|
||||
({ name }) => useActionConfig(name),
|
||||
{ initialProps: { name: "iptables" } },
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
});
|
||||
|
||||
expect(configApi.fetchAction).toHaveBeenCalledTimes(1);
|
||||
|
||||
rerender({ name: "ssh" });
|
||||
|
||||
await act(async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
});
|
||||
|
||||
expect(configApi.fetchAction).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user