Files
beacon-web/tests/features/stats/analytics-navigation.test.tsx
T
n30nex d259be512e feat: observer monitoring, retained evidence and channel scopes (#75-#99)
Lands the stacked web PRs #75, #79, #80, #81, #83, #85, #87, #89, #92, #95 and #99 in one squash. Server counterparts #166-#176 are merged. Remaining review items follow in a fix PR.
2026-09-30 08:03:13 -04:00

60 lines
4.3 KiB
TypeScript

import { fireEvent, render, screen } from "@testing-library/react";
import { MemoryRouter, useLocation } from "react-router-dom";
import { expect, it, vi } from "vitest";
import { StatsOverview } from "../../../src/features/stats/StatsOverview";
import type { WsManager } from "../../../src/api/ws-manager";
vi.mock("../../../src/features/stats/TrafficTab", () => ({ TrafficTab: ({ range }: { range: string }) => <p>Traffic range {range}</p> }));
vi.mock("../../../src/features/stats/SignalTab", () => ({ SignalTab: ({ range }: { range: string }) => <p>Signal range {range}</p> }));
vi.mock("../../../src/features/stats/PathsTab", () => ({ PathsTab: ({ range }: { range: string }) => <p>Paths range {range}</p> }));
vi.mock("../../../src/features/stats/MeshTab", () => ({ MeshTab: () => <p>Mesh charts</p> }));
vi.mock("../../../src/features/stats/ScopesTab", () => ({ ScopesTab: () => <p>Scope charts</p> }));
function Location() { return <output aria-label="Analytics URL">{useLocation().search}</output>; }
it("normalizes old seven-day links without the removed retention banner", () => {
render(<MemoryRouter initialEntries={["/?tab=Analytics&statsTab=signal&range=7d"]}><StatsOverview wsManager={{} as WsManager} /></MemoryRouter>);
expect(screen.getByText("Signal range 3d")).toBeInTheDocument();
expect(screen.getByRole("button", { name: "3d" })).toHaveAttribute("aria-pressed", "true");
expect(screen.queryByRole("button", { name: "7d" })).not.toBeInTheDocument();
expect(screen.getByRole("button", { name: "30d" })).toBeInTheDocument();
expect(screen.queryByText(/Hourly analytics keep summaries for up to 30 days/)).not.toBeInTheDocument();
});
it("opens Paths & Hashes from a shared URL and retains the region while changing range", () => {
render(<MemoryRouter initialEntries={["/?tab=Analytics&statsTab=paths&range=24h&iata=YOW"]}><StatsOverview wsManager={{} as WsManager} /><Location /></MemoryRouter>);
expect(screen.getByText("Paths range 24h")).toBeInTheDocument();
expect(screen.getByRole("button", { name: "Paths & Hashes" })).toHaveAttribute("aria-pressed", "true");
fireEvent.click(screen.getByRole("button", { name: "30d" }));
expect(screen.getByText("Paths range 30d")).toBeInTheDocument();
expect(screen.getByLabelText("Analytics URL")).toHaveTextContent("iata=YOW");
});
it("opens Signal from a shared URL and retains regional state when changing range", () => {
render(<MemoryRouter initialEntries={["/?tab=Analytics&statsTab=signal&range=24h&iata=YOW"]}><StatsOverview wsManager={{} as WsManager} /><Location /></MemoryRouter>);
expect(screen.getByText("Signal range 24h")).toBeInTheDocument();
expect(screen.getByRole("button", { name: "RF / Signal" })).toHaveAttribute("aria-pressed", "true");
fireEvent.click(screen.getByRole("button", { name: "3d" }));
expect(screen.getByText("Signal range 3d")).toBeInTheDocument();
expect(screen.getByLabelText("Analytics URL")).toHaveTextContent("iata=YOW");
});
it("opens Traffic from a shared URL and keeps unrelated selections when changing the range", () => {
render(<MemoryRouter initialEntries={["/?tab=Analytics&statsTab=traffic&range=24h&observerId=kept"]}><StatsOverview wsManager={{} as WsManager} /><Location /></MemoryRouter>);
expect(screen.getByText("Traffic range 24h")).toBeInTheDocument();
expect(screen.getByRole("button", { name: "Traffic" })).toHaveAttribute("aria-pressed", "true");
fireEvent.click(screen.getByRole("button", { name: "30d" }));
expect(screen.getByText("Traffic range 30d")).toBeInTheDocument();
expect(screen.getByLabelText("Analytics URL")).toHaveTextContent("observerId=kept");
fireEvent.click(screen.getByRole("button", { name: "Mesh" }));
expect(screen.getByText("Mesh charts")).toBeInTheDocument();
});
it("opens Scopes without a misleading range control and preserves the chosen range for Traffic", () => {
render(<MemoryRouter initialEntries={["/?tab=Analytics&statsTab=scopes&range=30d&iata=YOW"]}><StatsOverview wsManager={{} as WsManager} /><Location /></MemoryRouter>);
expect(screen.getByText("Scope charts")).toBeInTheDocument();
expect(screen.queryByRole("group", { name: "Time range" })).not.toBeInTheDocument();
fireEvent.click(screen.getByRole("button", { name: "Traffic" }));
expect(screen.getByText("Traffic range 30d")).toBeInTheDocument();
expect(screen.getByLabelText("Analytics URL")).toHaveTextContent("iata=YOW");
});