Adds src/app/camera-queries.ts: React Query hooks over our own routes, with each camera's queries keyed ['camera', id]. The camera card, snapshot polling, login form and network scan use these hooks instead of hand-rolled fetch/useEffect state (vrek iss-2fm6x2y, iss-ksxmctm, iss-m032zwq, iss-8hfq2y2). - Snapshot polling pauses in hidden tabs, never overlaps a slow frame, and stops after a failure until Retry. Each frame's object URL is created and revoked in one effect, so none leak under Strict Mode. - Saving or forgetting a login resets only that camera's queries. - New "Forget saved login" action, shown for stored logins. - Fix: a scan timeout typed below 1 s now clamps to 1 s instead of falling back to 5 s. Adds jsdom component tests (test/dom.tsx helpers): 93 tests, line coverage 54.3%. Refreshes the vrek export. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
28 lines
1.0 KiB
TypeScript
28 lines
1.0 KiB
TypeScript
// @vitest-environment jsdom
|
|
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import RefreshRateSelect from "./refresh-rate-select";
|
|
|
|
const replace = vi.fn();
|
|
vi.mock("next/navigation", () => ({
|
|
useRouter: () => ({ replace }),
|
|
usePathname: () => "/",
|
|
}));
|
|
|
|
afterEach(cleanup);
|
|
|
|
describe("RefreshRateSelect", () => {
|
|
it("shows the current rate and every option in seconds", () => {
|
|
render(<RefreshRateSelect value={500} />);
|
|
const select = screen.getByRole<HTMLSelectElement>("combobox");
|
|
expect(select.value).toBe("500");
|
|
expect([...select.options].map((o) => o.text)).toEqual(["0.25 s", "0.5 s", "1 s", "2 s", "5 s"]);
|
|
});
|
|
|
|
it("writes the chosen rate to the URL without scrolling", () => {
|
|
render(<RefreshRateSelect value={1000} />);
|
|
fireEvent.change(screen.getByRole("combobox"), { target: { value: "250" } });
|
|
expect(replace).toHaveBeenCalledWith("/?refresh=250", { scroll: false });
|
|
});
|
|
});
|