test(channels): cover applySyncFilter + DataTable fixedLayout

- applySyncFilter: the fully/needsFull/all predicate the top chips drive
  (moved off the retired Sync column) — guards which channels show.
- DataTable fixedLayout: asserts the colgroup + table-fixed appear only
  when opted in, with widths on fixed columns and none on fluid ones.
This commit is contained in:
2026-08-15 05:30:40 +02:00
parent 7ee0e9cd02
commit b4dae04631
2 changed files with 102 additions and 0 deletions
@@ -0,0 +1,46 @@
// @vitest-environment jsdom
//
// The R14 zoom-fit foundation: DataTable's opt-in `fixedLayout` renders a <colgroup> and puts the
// table into `table-layout: fixed`, so columns with a width keep it and the rest (fluid text columns)
// split the remainder + truncate instead of pushing the table wider than its container. Off by
// default so existing content-sized tables are untouched.
import { describe, it, expect, afterEach, vi } from "vitest";
import { render, cleanup } from "@testing-library/react";
import DataTable, { type Column } from "./DataTable";
vi.mock("react-i18next", async (importOriginal) => {
const actual = await importOriginal<typeof import("react-i18next")>();
return { ...actual, useTranslation: () => ({ t: (key: string) => key }) };
});
afterEach(cleanup);
type Row = { a: string; b: string };
const columns: Column<Row>[] = [
{ key: "a", header: "A", width: "5rem", render: (r) => r.a },
{ key: "b", header: "B", render: (r) => r.b }, // fluid — no width
];
const rows: Row[] = [{ a: "1", b: "hello" }];
describe("DataTable fixedLayout", () => {
it("renders a width-bearing colgroup and table-fixed only when fixedLayout is set", () => {
const { container } = render(
<DataTable rows={rows} columns={columns} rowKey={(r) => r.a} fixedLayout />,
);
const table = container.querySelector("table");
expect(table?.className).toContain("table-fixed");
const cols = container.querySelectorAll("colgroup col");
expect(cols).toHaveLength(2);
expect((cols[0] as HTMLElement).style.width).toBe("5rem"); // fixed column keeps its width
expect((cols[1] as HTMLElement).style.width).toBe(""); // fluid column: no width, splits remainder
});
it("omits the colgroup and stays auto-layout by default", () => {
const { container } = render(
<DataTable rows={rows} columns={columns} rowKey={(r) => r.a} />,
);
expect(container.querySelector("colgroup")).toBeNull();
expect(container.querySelector("table")?.className).not.toContain("table-fixed");
});
});
@@ -0,0 +1,56 @@
// @vitest-environment jsdom
//
// applySyncFilter is the sync-status pre-filter the top chips drive (R14 retired the Sync column and
// folded its status into a Stored charm). It replaced a column `filter.test`, so it carries the exact
// "fully" | "needsFull" | "" vocab + predicate — asserted here so a regression can't silently change
// which channels the top chips show.
import { describe, it, expect } from "vitest";
import { applySyncFilter } from "./channelColumns";
import { type ManagedChannel } from "../lib/api";
const ch = (over: Partial<ManagedChannel>): ManagedChannel => ({
id: "c",
title: null,
handle: null,
thumbnail_url: null,
subscriber_count: null,
video_count: null,
description: null,
stored_videos: 0,
last_video_at: null,
total_duration_seconds: 0,
count_normal: 0,
count_short: 0,
count_live: 0,
priority: 0,
hidden: false,
deep_requested: false,
deep_in_queue: false,
tag_ids: [],
details_synced: false,
recent_synced: false,
backfill_done: false,
...over,
});
const rows = [
ch({ id: "fully", recent_synced: true, backfill_done: true }),
ch({ id: "recentOnly", recent_synced: true, backfill_done: false }),
ch({ id: "none", recent_synced: false, backfill_done: false }),
];
describe("applySyncFilter", () => {
it("returns every row for the empty/all value (and unknown values)", () => {
expect(applySyncFilter(rows, "").map((r) => r.id)).toEqual(["fully", "recentOnly", "none"]);
expect(applySyncFilter(rows, undefined)).toHaveLength(3);
expect(applySyncFilter(rows, "bogus")).toHaveLength(3);
});
it("'fully' keeps only channels with recent uploads AND full history in", () => {
expect(applySyncFilter(rows, "fully").map((r) => r.id)).toEqual(["fully"]);
});
it("'needsFull' keeps every channel whose back-catalogue is not done", () => {
expect(applySyncFilter(rows, "needsFull").map((r) => r.id)).toEqual(["recentOnly", "none"]);
});
});