import { describe, it, expect, vi } from "vitest"; import { render, screen, fireEvent, within } from "@testing-library/react"; import { ObservationTable } from "../../../src/features/packets/ObservationTable"; import type { Observation } from "../../../src/types/api"; const obs = (id: number, over: Partial = {}): Observation => ({ id, observerId: `o${id}`, observerName: `Observer ${id}`, iata: "YVR", heardAt: 1700000000 + id, pathLength: { raw: "41", hashSize: 1, hopCount: 1 }, sourceBroker: "b1", resolvedPath: [], ...over, }); describe("ObservationTable", () => { it("renders one row per observation in the given order", () => { render( {}} />); expect(screen.getByText("Observer 1")).toBeInTheDocument(); expect(screen.getByText("Observer 2")).toBeInTheDocument(); }); it("selects an observation on click", () => { const onSelect = vi.fn(); render(); fireEvent.click(screen.getByText("Observer 1")); expect(onSelect).toHaveBeenCalledWith(1); }); it("marks the selected row", () => { render( {}} />); expect(screen.getByRole("row", { selected: true })).toBeInTheDocument(); }); it("leaves an unselected row's aria-selected false", () => { render( {}} />); const rows = screen.getAllByRole("row").slice(1); // drop the header row expect(rows[0]).toHaveAttribute("aria-selected", "true"); expect(rows[1]).toHaveAttribute("aria-selected", "false"); }); it("falls back to a truncated observer id when the name is missing", () => { render( {}} />); expect(screen.getByText("abcdefgh")).toBeInTheDocument(); }); it("renders em dashes for every absent optional field and no path row", () => { render( {}} />); const row = screen.getAllByRole("row")[1]!; const cells = within(row).getAllByRole("cell"); expect(cells[3]).toHaveTextContent("—"); // SNR expect(cells[4]).toHaveTextContent("—"); // RSSI expect(cells[5]).toHaveTextContent("—"); // Prop expect(cells[7]).toHaveTextContent("—"); // Path }); it("renders every field when all optional data is present", () => { render( {}} />, ); const row = screen.getAllByRole("row")[1]!; const cells = within(row).getAllByRole("cell"); expect(cells[3]).toHaveTextContent("6.20"); expect(cells[4]).toHaveTextContent("-87"); expect(cells[5]).toHaveTextContent("1.234s"); expect(cells[6]).toHaveTextContent("1"); expect(within(cells[7]!).getByText("AB")).toBeInTheDocument(); }); it("colors a good SNR", () => { render( {}} />); const row = screen.getAllByRole("row")[1]!; const cell = within(row).getAllByRole("cell")[3]!; expect(cell.className).toContain("text-green"); }); it("colors a mid SNR", () => { render( {}} />); const row = screen.getAllByRole("row")[1]!; const cell = within(row).getAllByRole("cell")[3]!; expect(cell.className).toContain("text-warn"); }); it("colors a bad SNR", () => { render( {}} />); const row = screen.getAllByRole("row")[1]!; const cell = within(row).getAllByRole("cell")[3]!; expect(cell.className).toContain("text-danger"); }); it("colors a null SNR as dim", () => { render( {}} />); const row = screen.getAllByRole("row")[1]!; const cell = within(row).getAllByRole("cell")[3]!; expect(cell.className).toContain("text-text-dim"); }); });