- A press that begins while a field in the row is edited only ends the editing (rowOpen latches it at pointerdown); the card layout's row press is now tested. - A related video reset in the player forgets the session's stored position. - Removing the playing video passes over known-dead items and steps the way it went. - Prev/Next off only because of dead items stay focusable and say why (HU/EN). - The docked bar's scroller leaves room for focus rings. - A focus-opened About card is not closed by its own scroll into view. - EN "Clear watch progress" for the video reset, distinct from a page's "Reset view". - The signed-out title read goes to the page yt-dlp read; the retitle writes are conditional. - Tests: the cap of three errors, the bar's own Fullscreen, the group glyph, the backfill's reads.
64 lines
2.2 KiB
TypeScript
64 lines
2.2 KiB
TypeScript
// @vitest-environment jsdom
|
|
//
|
|
// Below `md` a table is a list of cards, its columns flowing one after another. A column marked
|
|
// `cardRow` takes a line of its own there — a row's lone "…" otherwise landed at the end of one
|
|
// card's line and on the next line of another. A card is its row's press surface too, as the row is.
|
|
import { describe, it, expect, afterEach, vi } from "vitest";
|
|
import { render, cleanup, screen, fireEvent } from "@testing-library/react";
|
|
import DataTable, { type Column } from "./DataTable";
|
|
|
|
vi.mock("react-i18next", async (importOriginal) => ({
|
|
...(await importOriginal<typeof import("react-i18next")>()),
|
|
useTranslation: () => ({ i18n: { language: "en" }, t: (key: string) => key }),
|
|
}));
|
|
|
|
const narrow = (matches: boolean) =>
|
|
vi.stubGlobal(
|
|
"matchMedia",
|
|
(query: string) =>
|
|
({
|
|
matches,
|
|
media: query,
|
|
addEventListener: () => {},
|
|
removeEventListener: () => {},
|
|
}) as unknown as MediaQueryList,
|
|
);
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
type Row = { id: string };
|
|
const columns: Column<Row>[] = [
|
|
{ key: "name", header: "Name", cardPrimary: true, render: (r) => r.id },
|
|
{ key: "size", header: "Size", render: () => "1 MB" },
|
|
{ key: "menu", header: "", cardLabel: false, cardRow: true, render: () => <button>more</button> },
|
|
];
|
|
|
|
describe("DataTable cards", () => {
|
|
it("gives a cardRow column a line of its own; the others flow", () => {
|
|
narrow(false);
|
|
render(<DataTable rows={[{ id: "a" }]} columns={columns} rowKey={(r) => r.id} />);
|
|
expect(screen.getByText("more").parentElement!.className).toContain("basis-full");
|
|
expect(screen.getByText("1 MB").parentElement!.className).not.toContain("basis-full");
|
|
});
|
|
|
|
it("opens its object from a tap on the card, and leaves its control's tap to the control", () => {
|
|
narrow(false);
|
|
const open = vi.fn();
|
|
render(
|
|
<DataTable
|
|
rows={[{ id: "a" }]}
|
|
columns={columns}
|
|
rowKey={(r) => r.id}
|
|
rowOpen={() => open}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByText("1 MB"), { detail: 1 });
|
|
expect(open).toHaveBeenCalledTimes(1);
|
|
fireEvent.click(screen.getByText("more"), { detail: 1 });
|
|
expect(open).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|