import { describe, expect, it } from "vitest"; import { defaultViewConfig, viewData, validateButtonConfig, resolveTemplate, describeAction, VIEW_TYPES, } from "./index.js"; import type { RecordRow, PropertyInfo, PropertyValue } from "../values/types.js"; const props: PropertyInfo[] = [ { id: "p-title", name: "Title", type: "title", config: {} }, { id: "p-status", name: "Status", type: "select", config: { options: [ { id: "done", name: "Done", color: "green" }, { id: "todo", name: "To Do", color: "gray" }, ], }, }, { id: "p-date", name: "Due", type: "date", config: {} }, { id: "p-num", name: "N", type: "number", config: {} }, ]; const row = (id: string, values: Record): RecordRow => ({ id, pageId: id, position: `a${id}`, createdTime: 1, lastEditedTime: 1, values, }); describe("defaultViewConfig (TASK-0069 R5)", () => { it("all 9 types produce stable defaults", () => { for (const t of VIEW_TYPES) { const c = defaultViewConfig(t, { properties: props }); expect(c["visiblePropertyIds"]).toEqual(["p-title", "p-status", "p-date", "p-num"]); expect(typeof c["pageSize"]).toBe("number"); } }); it("board defaults group by the first STATUS/SELECT", () => { const c = defaultViewConfig("board", { properties: props }) as { group: Array<{ propertyId: string }>; }; expect(c.group).toEqual([{ propertyId: "p-status", direction: "asc" }]); }); it("calendar defaults to the first DATE/DATE_RANGE; empty group when absent", () => { const c = defaultViewConfig("calendar", { properties: props }) as { group: Array<{ propertyId: string }>; }; expect(c.group[0]!.propertyId).toBe("p-date"); const none = defaultViewConfig("calendar", { properties: [props[0]!, props[3]!] }) as { group: unknown[]; }; expect(none.group).toEqual([]); }); }); describe("viewData — the 9 render resolvers", () => { const rows = [ row("r1", { "p-status": "todo", "p-date": "2025-06-01" }), row("r2", { "p-status": "done", "p-date": "2025-06-02" }), ]; it("board groups by option order with (Empty) last", () => { // option order is [Done, To Do] → done group first const v = viewData("board", rows, { group: [{ propertyId: "p-status" }] }, props); expect(v.board!.groups.map((g) => g.key)).toEqual(["done", "todo"]); }); it("calendar extracts events with dates", () => { const v = viewData("calendar", rows, { group: [{ propertyId: "p-date" }] }, props); expect(v.calendar!.events.map((e) => e.date)).toEqual(["2025-06-01", "2025-06-02"]); }); it("chart/dashboard pass through their ids", () => { expect(viewData("chart", [], { chartId: "ch1" }, props).chart!.chartId).toBe("ch1"); expect(viewData("dashboard", [], { dashboardId: "dash1" }, props).dashboard!.dashboardId).toBe( "dash1", ); }); it("form is disabled (Phase 10)", () => { const v = viewData("form", [], {}, props); expect(v.form!.disabled).toBe(true); expect(v.form!.reason).toBe("form_view_phase_10"); }); }); describe("buttons (TASK-0087 pure half)", () => { it("validates config: name 1–50, 1–5 actions, per-action fields", () => { expect( validateButtonConfig({ name: "Run", icon: "▶️", actions: [{ type: "set_property", propertyId: "p", value: 1 }], }), ).toEqual([]); expect(validateButtonConfig({ name: "", actions: [] })).toHaveLength(2); expect( validateButtonConfig({ name: "x", actions: Array.from({ length: 6 }, () => ({ type: "set_property", propertyId: "p" })), }), ).toHaveLength(1); const badType = validateButtonConfig({ name: "x", actions: [{ type: "explode" }] }); expect(badType[0]!.field).toBe("actions[0].type"); }); it("resolveTemplate expands {tokens} case-insensitively; unknown → ''", () => { const out = resolveTemplate("Task: {title} due {Due}", "Ship it", { due: { display: "Jun 15" }, }); expect(out).toBe("Task: Ship it due Jun 15"); expect(resolveTemplate("{Nope}", "t", {})).toBe(""); }); it("describeAction renders the confirm-popover lines", () => { const names = new Map([["p", "Status"]]); expect(describeAction({ type: "set_property", propertyId: "p", value: "x" }, names)).toBe( "Set Status", ); expect(describeAction({ type: "set_property", propertyId: "p", setTo: "empty" }, names)).toBe( "Clear Status", ); expect(describeAction({ type: "create_page", databaseId: "db" }, names)).toBe( "Create a record", ); expect(describeAction({ type: "archive_page", target: "self" }, names)).toBe( "Archive this record", ); expect(describeAction({ type: "send_webhook", webhookId: "w" }, names)).toBe("Send webhook"); }); });