Files

100 lines
4.4 KiB
TypeScript

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> = {}): 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(<ObservationTable observations={[obs(1), obs(2)]} selectedId={null} onSelect={() => {}} />);
expect(screen.getByText("Observer 1")).toBeInTheDocument();
expect(screen.getByText("Observer 2")).toBeInTheDocument();
});
it("selects an observation on click", () => {
const onSelect = vi.fn();
render(<ObservationTable observations={[obs(1)]} selectedId={null} onSelect={onSelect} />);
fireEvent.click(screen.getByText("Observer 1"));
expect(onSelect).toHaveBeenCalledWith(1);
});
it("marks the selected row", () => {
render(<ObservationTable observations={[obs(1)]} selectedId={1} onSelect={() => {}} />);
expect(screen.getByRole("row", { selected: true })).toBeInTheDocument();
});
it("leaves an unselected row's aria-selected false", () => {
render(<ObservationTable observations={[obs(1), obs(2)]} selectedId={1} onSelect={() => {}} />);
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(<ObservationTable observations={[obs(1, { observerName: undefined, observerId: "abcdefgh1234" })]} selectedId={null} onSelect={() => {}} />);
expect(screen.getByText("abcdefgh")).toBeInTheDocument();
});
it("renders em dashes for every absent optional field and no path row", () => {
render(<ObservationTable observations={[obs(1)]} selectedId={null} onSelect={() => {}} />);
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(
<ObservationTable
observations={[
obs(1, { rssi: -87, snr: 6.2, propagationTimeMs: 1234, pathBytes: "ab", pathLength: { raw: "41", hashSize: 1, hopCount: 1 } }),
]}
selectedId={null}
onSelect={() => {}}
/>,
);
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(<ObservationTable observations={[obs(1, { snr: 12 })]} selectedId={null} onSelect={() => {}} />);
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(<ObservationTable observations={[obs(1, { snr: 7 })]} selectedId={null} onSelect={() => {}} />);
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(<ObservationTable observations={[obs(1, { snr: 2 })]} selectedId={null} onSelect={() => {}} />);
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(<ObservationTable observations={[obs(1, { snr: undefined })]} selectedId={null} onSelect={() => {}} />);
const row = screen.getAllByRole("row")[1]!;
const cell = within(row).getAllByRole("cell")[3]!;
expect(cell.className).toContain("text-text-dim");
});
});