Fix blocklist-import bantime, unify filter bar, and improve config navigation
This commit is contained in:
@@ -6,7 +6,11 @@ import { ConfigPage } from "../ConfigPage";
|
||||
|
||||
// Mock all tab components to avoid deep render trees and API calls.
|
||||
vi.mock("../../components/config", () => ({
|
||||
JailsTab: () => <div data-testid="jails-tab">JailsTab</div>,
|
||||
JailsTab: ({ initialJail }: { initialJail?: string }) => (
|
||||
<div data-testid="jails-tab" data-initial-jail={initialJail}>
|
||||
JailsTab
|
||||
</div>
|
||||
),
|
||||
FiltersTab: () => <div data-testid="filters-tab">FiltersTab</div>,
|
||||
ActionsTab: () => <div data-testid="actions-tab">ActionsTab</div>,
|
||||
ServerTab: () => <div data-testid="server-tab">ServerTab</div>,
|
||||
@@ -53,4 +57,22 @@ describe("ConfigPage", () => {
|
||||
renderPage();
|
||||
expect(screen.getByRole("heading", { name: /configuration/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("selects the Jails tab based on location state", () => {
|
||||
render(
|
||||
<MemoryRouter
|
||||
initialEntries={[
|
||||
{ pathname: "/config", state: { tab: "jails", jail: "sshd" } },
|
||||
]}
|
||||
>
|
||||
<FluentProvider theme={webLightTheme}>
|
||||
<ConfigPage />
|
||||
</FluentProvider>
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
const jailsTab = screen.getByTestId("jails-tab");
|
||||
expect(jailsTab).toBeInTheDocument();
|
||||
expect(jailsTab).toHaveAttribute("data-initial-jail", "sshd");
|
||||
});
|
||||
});
|
||||
|
||||
58
frontend/src/pages/__tests__/HistoryPage.test.tsx
Normal file
58
frontend/src/pages/__tests__/HistoryPage.test.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { FluentProvider, webLightTheme } from "@fluentui/react-components";
|
||||
import { HistoryPage } from "../HistoryPage";
|
||||
|
||||
let lastQuery: Record<string, unknown> | null = null;
|
||||
const mockUseHistory = vi.fn((query: Record<string, unknown>) => {
|
||||
lastQuery = query;
|
||||
return {
|
||||
items: [],
|
||||
total: 0,
|
||||
page: 1,
|
||||
loading: false,
|
||||
error: null,
|
||||
setPage: vi.fn(),
|
||||
refresh: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../hooks/useHistory", () => ({
|
||||
useHistory: (query: Record<string, unknown>) => mockUseHistory(query),
|
||||
useIpHistory: () => ({ detail: null, loading: false, error: null, refresh: vi.fn() }),
|
||||
}));
|
||||
|
||||
vi.mock("../components/WorldMap", () => ({
|
||||
WorldMap: () => <div data-testid="world-map" />,
|
||||
}));
|
||||
|
||||
vi.mock("../api/config", () => ({
|
||||
fetchMapColorThresholds: async () => ({
|
||||
threshold_low: 10,
|
||||
threshold_medium: 50,
|
||||
threshold_high: 100,
|
||||
}),
|
||||
}));
|
||||
|
||||
describe("HistoryPage", () => {
|
||||
it("renders DashboardFilterBar and applies origin+range filters", async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
render(
|
||||
<FluentProvider theme={webLightTheme}>
|
||||
<HistoryPage />
|
||||
</FluentProvider>,
|
||||
);
|
||||
|
||||
// Initial load should include the default query.
|
||||
expect(lastQuery).toEqual({ page_size: 50 });
|
||||
|
||||
// Change the time-range and origin filter, then apply.
|
||||
await user.click(screen.getByRole("button", { name: /Last 7 days/i }));
|
||||
await user.click(screen.getByRole("button", { name: /Blocklist/i }));
|
||||
await user.click(screen.getByRole("button", { name: /Apply/i }));
|
||||
|
||||
expect(lastQuery).toMatchObject({ range: "7d", origin: "blocklist" });
|
||||
});
|
||||
});
|
||||
74
frontend/src/pages/__tests__/JailsPage.test.tsx
Normal file
74
frontend/src/pages/__tests__/JailsPage.test.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { FluentProvider, webLightTheme } from "@fluentui/react-components";
|
||||
import { MemoryRouter } from "react-router-dom";
|
||||
import { JailsPage } from "../JailsPage";
|
||||
import type { JailSummary } from "../../types/jail";
|
||||
|
||||
const mockNavigate = vi.fn();
|
||||
|
||||
vi.mock("react-router-dom", async () => {
|
||||
const actual = (await vi.importActual<typeof import("react-router-dom")>(
|
||||
"react-router-dom",
|
||||
)) as unknown as Record<string, unknown>;
|
||||
return {
|
||||
...actual,
|
||||
useNavigate: () => mockNavigate,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../hooks/useJails", () => ({
|
||||
useJails: () => ({
|
||||
jails: [
|
||||
{
|
||||
name: "sshd",
|
||||
enabled: true,
|
||||
running: true,
|
||||
idle: false,
|
||||
backend: "systemd",
|
||||
find_time: 600,
|
||||
ban_time: 3600,
|
||||
max_retry: 5,
|
||||
status: {
|
||||
currently_banned: 1,
|
||||
total_banned: 10,
|
||||
currently_failed: 0,
|
||||
total_failed: 0,
|
||||
},
|
||||
},
|
||||
] as JailSummary[],
|
||||
total: 1,
|
||||
loading: false,
|
||||
error: null,
|
||||
refresh: vi.fn(),
|
||||
startJail: vi.fn().mockResolvedValue(undefined),
|
||||
stopJail: vi.fn().mockResolvedValue(undefined),
|
||||
setIdle: vi.fn().mockResolvedValue(undefined),
|
||||
reloadJail: vi.fn().mockResolvedValue(undefined),
|
||||
reloadAll: vi.fn().mockResolvedValue(undefined),
|
||||
}),
|
||||
}));
|
||||
|
||||
function renderPage() {
|
||||
return render(
|
||||
<MemoryRouter>
|
||||
<FluentProvider theme={webLightTheme}>
|
||||
<JailsPage />
|
||||
</FluentProvider>
|
||||
</MemoryRouter>,
|
||||
);
|
||||
}
|
||||
|
||||
describe("JailsPage", () => {
|
||||
it("navigates to Configuration → Jails when a jail is clicked", async () => {
|
||||
renderPage();
|
||||
const user = userEvent.setup();
|
||||
|
||||
await user.click(screen.getByText("sshd"));
|
||||
|
||||
expect(mockNavigate).toHaveBeenCalledWith("/config", {
|
||||
state: { tab: "jails", jail: "sshd" },
|
||||
});
|
||||
});
|
||||
});
|
||||
58
frontend/src/pages/__tests__/MapPage.test.tsx
Normal file
58
frontend/src/pages/__tests__/MapPage.test.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { FluentProvider, webLightTheme } from "@fluentui/react-components";
|
||||
import { MapPage } from "../MapPage";
|
||||
|
||||
const mockFetchMapColorThresholds = vi.fn(async () => ({
|
||||
threshold_low: 10,
|
||||
threshold_medium: 50,
|
||||
threshold_high: 100,
|
||||
}));
|
||||
|
||||
let lastArgs: { range: string; origin: string } = { range: "", origin: "" };
|
||||
const mockUseMapData = vi.fn((range: string, origin: string) => {
|
||||
lastArgs = { range, origin };
|
||||
return {
|
||||
countries: {},
|
||||
countryNames: {},
|
||||
bans: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
error: null,
|
||||
refresh: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../hooks/useMapData", () => ({
|
||||
useMapData: (range: string, origin: string) => mockUseMapData(range, origin),
|
||||
}));
|
||||
|
||||
vi.mock("../api/config", async () => ({
|
||||
fetchMapColorThresholds: mockFetchMapColorThresholds,
|
||||
}));
|
||||
|
||||
vi.mock("../components/WorldMap", () => ({
|
||||
WorldMap: () => <div data-testid="world-map" />,
|
||||
}));
|
||||
|
||||
describe("MapPage", () => {
|
||||
it("renders DashboardFilterBar and updates data when filters change", async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
render(
|
||||
<FluentProvider theme={webLightTheme}>
|
||||
<MapPage />
|
||||
</FluentProvider>,
|
||||
);
|
||||
|
||||
// Initial load should call useMapData with default filters.
|
||||
expect(lastArgs).toEqual({ range: "24h", origin: "all" });
|
||||
|
||||
await user.click(screen.getByRole("button", { name: /Last 7 days/i }));
|
||||
expect(lastArgs.range).toBe("7d");
|
||||
|
||||
await user.click(screen.getByRole("button", { name: /Blocklist/i }));
|
||||
expect(lastArgs.origin).toBe("blocklist");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user