import { expect, test } from "bun:test"; import { generate, parse } from "../src/index.ts"; // A `{#each}` inside a COMPONENT emitted `data-wrn-loop-locals`, so a handler // could reference the loop variable. The same view inside a PAGE emitted the // handler text verbatim with no locals marker, so the loop variable was not // defined at click time and the handler threw ReferenceError -- with a green // build and green tests, because nothing renders the page in a browser during // a build. The runtime resolves locals with closest("[data-wrn-loop-locals]"), // so emitting the marker is all that is required. const view = ` {#each packs as pack} {/each} `; const body = ` state packs = [{ code: "small" }] functions { client async function buyPack(c) { console.log(c) } } view {${view}} `; test("a page {#each} exposes loop locals to an event handler", () => { const code = generate(parse(`page P {${body}}`)); expect(code).toContain("data-wrn-loop-locals"); // The item and the implicit index both have to travel, since a handler may // reference either. expect(code).toContain('"pack": pack'); }); test("a component {#each} still exposes loop locals to an event handler", () => { const code = generate(parse(`component C {${body}}`)); expect(code).toContain("data-wrn-loop-locals"); expect(code).toContain('"pack": pack'); }); test("a named loop index is exposed to a page event handler", () => { const code = generate( parse(`page P { state packs = [{ code: "small" }] functions { client async function pick(c) { console.log(c) } } view { {#each packs as pack, i} {/each} } }`), ); expect(code).toContain('"i": i'); }); // Only elements that actually bind an event need the marker; adding it to every // element in a loop body would bloat the HTML for no benefit. test("a page loop body element with no handler gets no locals marker", () => { const code = generate( parse(`page P { state packs = [{ code: "small" }] view { {#each packs as pack} {pack.code} {/each} } }`), ); expect(code).not.toContain("data-wrn-loop-locals"); }); // Emitting the marker without defining its encoder would turn a ReferenceError // on the loop variable into a ReferenceError on the encoder -- at render time // rather than click time, so strictly worse. test("a page that emits loop locals also defines the encoder", () => { const code = generate(parse(`page P {${body}}`)); expect(code).toContain("data-wrn-loop-locals"); expect(code).toContain("function __wrnexusEncodeLoopLocals"); }); test("a page with no loop-local markers does not define the encoder", () => { const code = generate( parse(`page P { state packs = [{ code: "small" }] view { {packs.length} } }`), ); expect(code).not.toContain("__wrnexusEncodeLoopLocals"); });