Files
WRNexusJS/packages/dev-server/test/nested-control-components.test.ts
T

190 lines
7.8 KiB
TypeScript

import { expect, test } from "bun:test";
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { basename, join } from "node:path";
import { tmpdir } from "node:os";
import { buildRouter } from "@wrnexus/router";
import { createHandlers } from "../src/runtime.ts";
import { encodeControlTemplate } from "@wrnexus/core";
test("nested encoded conditional and empty-list templates prepare shared controls", async () => {
const root = mkdtempSync(join(tmpdir(), "wrn-nested-controls-"));
const encode = (value: unknown) => Buffer.from(JSON.stringify(value)).toString("base64");
try {
const app = join(root, "app");
mkdirSync(join(app, "pages"), { recursive: true });
mkdirSync(join(app, "components"), { recursive: true });
writeFileSync(join(app, "pages/index.ts"), "export default () => '';");
writeFileSync(
join(app, "components/Button.wrn"),
"component Button { view { <button>Review</button> } }",
);
const mount = '<div data-component="Button"></div>';
const inner = encode([{ cond: "review.active", body: mount }]);
const list = encode({ list: "items", item: "item", body: "<p>Item</p>", empty: mount });
const outer = encode([
{
cond: "review",
body: `<template data-wrn-if="${inner}"></template><template data-wrn-control-end></template><template data-wrn-each="${list}"></template><template data-wrn-control-end></template>`,
},
]);
const handlers = createHandlers({
mode: "development",
hmr: false,
router: buildRouter(app),
loadModule: async (file) =>
basename(file) === "Button.wrn"
? { render: () => "<button>Review</button>" }
: {
default: () =>
`<template data-wrn-if="${encodeControlTemplate(JSON.parse(Buffer.from(outer, "base64").toString()))}"></template><template data-wrn-control-end></template>`,
},
getMiddleware: async () => [],
assets: { serve: async () => null },
});
const html = await (await handlers.fetch(new Request("https://example.test/"), {
upgrade: () => false,
}))!.text();
const registry = /data-wrn-controls[^>]*>(.*?)<\/script>/s.exec(html);
expect(registry).not.toBeNull();
const definitions = JSON.parse(registry![1]!);
const decode = (markup: string, kind: string) => {
const reference = new RegExp(`data-wrn-${kind}="(@[A-Za-z0-9-]+:[0-9]+)"`).exec(markup)![1]!;
return definitions[Number(reference.split(":")[1])];
};
const branch = definitions[0][0].body;
expect(decode(branch, "if")[0].body).toBe("<button>Review</button>");
expect(decode(branch, "each").empty).toBe("<button>Review</button>");
} finally {
rmSync(root, { recursive: true, force: true });
}
});
test("shared branch references are prepared once across a branching control graph", async () => {
const root = mkdtempSync(join(tmpdir(), "wrn-shared-controls-"));
try {
const app = join(root, "app");
mkdirSync(join(app, "pages"), { recursive: true });
writeFileSync(join(app, "pages/index.ts"), "export default () => ''; ");
let reads = 0;
const handlers = createHandlers({
mode: "development",
hmr: false,
router: buildRouter(app),
loadModule: async () => ({
default: () => {
let body = "<p>Leaf</p>";
for (let depth = 0; depth < 12; depth++) {
let storedBody = body;
const entry = {
cond: "open",
get body() {
reads++;
return storedBody;
},
set body(value: string) {
storedBody = value;
},
};
const reference = encodeControlTemplate([entry]);
body =
`<template data-wrn-if="${reference}"></template><template data-wrn-control-end></template>`.repeat(
2,
);
}
return body;
},
}),
getMiddleware: async () => [],
assets: { serve: async () => null },
});
const html = await (await handlers.fetch(new Request("https://example.test/"), {
upgrade: () => false,
}))!.text();
expect(reads).toBeLessThan(200);
const definitions = JSON.parse(/data-wrn-controls[^>]*>(.*?)<\/script>/s.exec(html)![1]!);
expect(definitions).toHaveLength(12);
expect(definitions[0][0].body).toBe("<p>Leaf</p>");
} finally {
rmSync(root, { recursive: true, force: true });
}
});
test("deep inline loop definitions stay bounded after shared component preparation", async () => {
const root = mkdtempSync(join(tmpdir(), "wrn-loop-size-"));
try {
const app = join(root, "app");
mkdirSync(join(app, "pages"), { recursive: true });
mkdirSync(join(app, "components"), { recursive: true });
writeFileSync(join(app, "pages/index.ts"), "export default () => ''; ");
writeFileSync(join(app, "components/Button.wrn"), "component Button { view { <button /> } }");
let body = '<div data-component="Button"></div>';
for (let depth = 0; depth < 12; depth++) {
const encoded = Buffer.from(
JSON.stringify({ list: "items", item: "item", body, empty: "" }),
).toString("base64");
body = `<template data-wrn-each="${encoded}"></template><template data-wrn-control-end></template>`;
}
const handlers = createHandlers({
mode: "development",
hmr: false,
router: buildRouter(app),
loadModule: async (file) =>
basename(file) === "Button.wrn"
? { render: () => `<button>${"Review".repeat(200)}</button>` }
: { default: () => body },
getMiddleware: async () => [],
assets: { serve: async () => null },
});
const html = await (await handlers.fetch(new Request("https://example.test/"), {
upgrade: () => false,
}))!.text();
const definitions = JSON.parse(/data-wrn-controls[^>]*>(.*?)<\/script>/s.exec(html)![1]!);
expect(definitions).toHaveLength(12);
expect(html.length).toBeLessThan(12000);
expect(
definitions.filter((definition: { body: string }) => definition.body.includes("<button>")),
).toHaveLength(1);
} finally {
rmSync(root, { recursive: true, force: true });
}
});
test("inert control nesting does not consume the component composition budget", async () => {
const root = mkdtempSync(join(tmpdir(), "wrn-control-budget-"));
try {
const app = join(root, "app");
mkdirSync(join(app, "pages"), { recursive: true });
mkdirSync(join(app, "components"), { recursive: true });
writeFileSync(join(app, "pages/index.ts"), "export default ()=>'';");
writeFileSync(
join(app, "components/Button.wrn"),
"component Button { view { <button>Nested field</button> } }",
);
let body = '<div data-component="Button"></div>';
for (let depth = 0; depth < 20; depth++) {
const encoded = Buffer.from(JSON.stringify([{ cond: "open", body }])).toString("base64");
body = `<template data-wrn-if="${encoded}"></template><template data-wrn-control-end></template>`;
}
const handlers = createHandlers({
mode: "development",
hmr: false,
router: buildRouter(app),
loadModule: async (file) =>
basename(file) === "Button.wrn"
? { render: () => "<button>Nested field</button>" }
: { default: () => body },
getMiddleware: async () => [],
assets: { serve: async () => null },
});
const html = await (await handlers.fetch(new Request("https://example.test/"), {
upgrade: () => false,
}))!.text();
const definitions = JSON.parse(/data-wrn-controls[^>]*>(.*?)<\/script>/s.exec(html)![1]!);
expect(JSON.stringify(definitions)).toContain("<button>Nested field</button>");
expect(JSON.stringify(definitions)).not.toContain("data-component");
expect(html.length).toBeLessThan(20000);
} finally {
rmSync(root, { recursive: true, force: true });
}
});