Files
local-cal/tests/home-page-layout.test.ts
Dmytro Stanchiev 7df8419368 refactor(layout): promote AI capture above timeline on desktop
Give the composer full-width desktop space before the event timeline so capture stays prominent and the toolbar can keep its intended two-column composition. Add source-level regression tests to lock the new page hierarchy in place.
2026-04-22 11:34:37 -04:00

79 lines
3.3 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import { readFileSync } from "node:fs";
describe("home page hierarchy", () => {
test("desktop layout is selected with useIsMobile rather than Tailwind breakpoint classes", () => {
const source = readFileSync("src/app/page.tsx", "utf8");
expect(source).toContain("useIsMobile");
expect(source).toContain('const mainContentClasses = "space-y-4"');
expect(source).toContain('const timelineContentClasses = "space-y-4"');
expect(source).toContain('"items-center justify-between"');
expect(source).toContain("desktopUtilityActionsClasses");
expect(source).toContain("AI capture");
expect(source).toContain("Event timeline");
});
test("desktop layout promotes AI capture to a full-width top row before the timeline grid", () => {
const source = readFileSync("src/app/page.tsx", "utf8");
expect(source).toContain("<section className={appSectionSurfaceClasses}>");
expect(source).toContain("<section className={timelineContentClasses}>");
expect(source).not.toContain("grid-cols-[minmax(0,0.75fr)_minmax(0,1.25fr)]");
});
test("manual create is routed through a More menu instead of a primary mobile action", () => {
const source = readFileSync("src/app/page.tsx", "utf8");
expect(source).toContain("More");
expect(source).not.toContain("New Event</button>");
});
test("mobile layout keeps capture before timeline without order utility breakpoints", () => {
const source = readFileSync("src/app/page.tsx", "utf8");
expect(source).not.toContain("order-1 lg:order-none");
expect(source).toContain("Import");
expect(source).toContain("Manual create");
});
test("mobile header gives controls their own full-width row so the title is not squeezed by actions", () => {
const source = readFileSync("src/app/page.tsx", "utf8");
expect(source).toContain("isMobile ? \"w-full\" : undefined");
expect(source).toContain("headerActionsClasses");
expect(source).toContain('"flex w-full items-center justify-between gap-2"');
expect(source).toContain("flex flex-wrap items-center justify-end gap-2");
});
test("mobile header keeps export inside the More menu instead of a dedicated button", () => {
const source = readFileSync("src/app/page.tsx", "utf8");
expect(source).toContain("!isMobile && (");
expect(source).toContain("Export");
expect(source).toContain("onClick={handleExport}");
});
test("mobile More trigger collapses to an icon button so utility actions fit on one row", () => {
const source = readFileSync("src/app/page.tsx", "utf8");
expect(source).toContain('size={isMobile ? "icon" : "sm"}');
expect(source).toContain("moreTriggerLabel");
expect(source).toContain('isMobile ? null : "More"');
});
test("mobile header omits the theme toggle so auth and overflow actions have a stable hierarchy", () => {
const source = readFileSync("src/app/page.tsx", "utf8");
expect(source).not.toContain("<ModeToggle />");
});
test("mobile header uses a column layout with a dedicated action row instead of desktop justify-between framing", () => {
const source = readFileSync("src/app/page.tsx", "utf8");
expect(source).toContain("headerLayoutClasses");
expect(source).toContain('isMobile ? "flex-col items-start"');
expect(source).toContain('"flex w-full items-center justify-between gap-2"');
});
});