import { describe, expect, test } from "bun:test"; import { renderToStaticMarkup } from "react-dom/server"; import { EventForm } from "../src/client/components/CustomForms.tsx"; import { YourOwn } from "../src/client/components/YourOwn.tsx"; import { EventRow } from "../src/client/components/EventRow.tsx"; import { AUTHOR, Colophon, REPO_URL } from "../src/client/components/Colophon.tsx"; import { GameMetaProvider } from "../src/client/state/gameMeta.tsx"; import { asDisplayEvent, CustomEvent, type CustomEvents, type CustomGames, } from "../src/shared/custom.ts"; import { metaFor } from "../src/shared/games.ts"; import { clockFor } from "../src/shared/time.ts"; /** * Static-render checks on the F13 surfaces. * * Not a substitute for using the thing, but they pin the two claims the feature * makes to a reader: their event is marked as theirs, and the end date is * allowed to be unknown. */ const AT = "2026-08-17T12:00:00.000Z"; const GAMES: CustomGames = { "mygame:limbus-company": { id: "mygame:limbus-company", name: "Limbus Company", hue: "#C74B50", at: AT, }, }; const OWN = CustomEvent.parse({ id: "myevent:k3f9qa2m01", game: "mygame:limbus-company", title: "Walpurgisnacht", type: "banner", summary: null, startsAt: "2026-08-20T00:00:00.000Z", startPrecision: "day", endsAt: "2026-09-03T00:00:00.000Z", endPrecision: "day", at: AT, updatedAt: AT, }); const EVENTS: CustomEvents = { [OWN.id]: OWN }; function render(node: React.ReactElement): string { return renderToStaticMarkup( metaFor(id, GAMES)}>{node}, ); } describe("YourOwn", () => { const noop = () => {}; const props = { games: GAMES, events: EVENTS, lanes: ["genshin", "mygame:limbus-company"], onAddGame: noop, onEditGame: noop, onRemoveGame: () => ({ removed: true, blockedBy: 0 }), onAddEvent: noop, }; test("lists a reader's game with the events it holds", () => { const html = render(); expect(html).toContain("Limbus Company"); expect(html).toContain("1 event"); expect(html).toContain("#C74B50"); }); test("shows a game with nothing in it rather than hiding it", () => { // A game they just made has to appear before it holds anything, or adding // one looks like it did nothing. const html = render(); expect(html).toContain("no events yet"); }); }); describe("EventForm", () => { test("offers an unknown end rather than demanding a date", () => { // The whole point: a form that made the end mandatory would push the reader // into inventing one, which is the failure the parsers are forbidden from. const html = render( {}} onCancel={() => {}} />, ); expect(html).toContain("I don't know when it ends"); }); test("puts the reader's own games at the top of the picker, and defaults to one", () => { // Someone entering an event by hand is usually doing it because the game // isn't tracked. Two of theirs to prove the group order, not just a swap. const twoOfMine: CustomGames = { ...GAMES, "mygame:silver-palace": { id: "mygame:silver-palace", name: "Silver Palace", hue: "#5C7CE0", at: AT, }, }; const html = renderToStaticMarkup( metaFor(id, twoOfMine)}> {}} onCancel={() => {}} /> , ); // The game picker is the first select; the second is the event kind. const picker = html.slice(0, html.indexOf("")); const order = [...picker.matchAll(/