Files
plainleaf/e2e/baked-sections.test.ts

157 lines
5.2 KiB
TypeScript

import { expect, gotoSilverBulletPage, test } from "./fixtures.ts";
test.use({
spaceFiles: {
"Bake.md": `Before\n\n<!--#lua 3 + 4 -->\nstale\n<!--/lua-->\n\nAfter\n`,
"BakeButton.md": 'Table:\n\n${ { {name = "a"}, {name = "b"} } }\n',
// A Lua-registered code widget that renders its body as block markdown.
// Its rendered block gets a button bar, but it must NOT get a Bake button:
// baking rewrites the source to `<!--#lua EXPR -->` where EXPR is a Lua
// expression, and a fenced block's body (here "world") is not one.
"FencedNoBake.md":
'```space-lua\nconfig.set({"codeWidgets", "greet"}, {\n language = "greet",\n render = function(bodyText)\n return "## Hello " .. bodyText .. "\\n\\nA greeting block."\n end\n})\n```\n\n```greet\nworld\n```\n',
},
});
test("'Baked Sections: Update' rewrites a section body with the evaluated result", async ({
sbServer,
page,
}) => {
await gotoSilverBulletPage(page, sbServer, "Bake");
await page.waitForFunction(
() => !!(globalThis as any).client?.editorView,
undefined,
{ timeout: 10_000 },
);
await page.evaluate(() =>
(globalThis as any).client.runCommandByName("Baked Sections: Update"),
);
await page.waitForFunction(
() => {
const doc = (globalThis as any).client.editorView.state.doc.toString();
return doc.includes("<!--#lua 3 + 4 -->\n7\n<!--/lua-->");
},
undefined,
{ timeout: 10_000 },
);
const doc = await page.evaluate(() =>
(globalThis as any).client.editorView.state.doc.toString(),
);
expect(doc).toContain("<!--#lua 3 + 4 -->\n7\n<!--/lua-->");
expect(doc).not.toContain("stale");
});
test("'Baked Sections: Unbake Section At Cursor' restores the section to ${…} form", async ({
sbServer,
page,
}) => {
await gotoSilverBulletPage(page, sbServer, "Bake");
await page.waitForFunction(
() => !!(globalThis as any).client?.editorView,
undefined,
{ timeout: 10_000 },
);
// Place the cursor inside the baked section, then unbake it.
await page.evaluate(() => {
const view = (globalThis as any).client.editorView;
const idx = view.state.doc.toString().indexOf("<!--#lua");
view.dispatch({ selection: { anchor: idx + 2 } });
});
await page.evaluate(() =>
(globalThis as any).client.runCommandByName(
"Baked Sections: Unbake Section At Cursor",
),
);
await page.waitForFunction(
() => {
const doc = (globalThis as any).client.editorView.state.doc.toString();
return doc.includes("${3 + 4}");
},
undefined,
{ timeout: 10_000 },
);
const doc = await page.evaluate(() =>
(globalThis as any).client.editorView.state.doc.toString(),
);
expect(doc).toContain("${3 + 4}");
expect(doc).not.toContain("<!--#lua");
expect(doc).not.toContain("<!--/lua-->");
});
// A record-array result renders as a block table → block widget → button bar.
test("bake button converts a ${} directive to comment form", async ({
sbServer,
page,
}) => {
await gotoSilverBulletPage(page, sbServer, "BakeButton");
// The button bar is `display: none` until the widget is hovered
// (editor.scss: `.sb-lua-directive-block:hover .button-bar`). Hover the
// widget to reveal the bar, then click the Bake button.
const widget = page.locator("#sb-editor .sb-lua-directive-block").first();
await widget.waitFor({ state: "visible", timeout: 10_000 });
await widget.hover();
const btn = page
.locator('#sb-editor .button-bar button[data-button="bake"]')
.first();
await btn.click({ timeout: 10_000 });
await page.waitForFunction(
() => {
const doc = (globalThis as any).client.editorView.state.doc.toString();
return doc.includes("<!--#lua") && doc.includes("<!--/lua-->");
},
undefined,
{ timeout: 10_000 },
);
const doc = await page.evaluate(() =>
(globalThis as any).client.editorView.state.doc.toString(),
);
expect(doc).toContain("<!--#lua");
expect(doc).toContain("<!--/lua-->");
// The baked body is the clean GFM table, not an empty span.
expect(doc).toContain("|name|");
expect(doc).toContain("|a|");
expect(doc).not.toContain("${");
});
// Regression guard: the Bake button is for live `${…}` Lua directives only.
// Widgets that originate from fenced code blocks (e.g. ```mermaid, ```greet)
// must not get one — their body is not a Lua expression to re-evaluate.
test("fenced code block widgets do not get a Bake button", async ({
sbServer,
page,
}) => {
await gotoSilverBulletPage(page, sbServer, "FencedNoBake");
// Wait for the `greet` code widget to render as a block widget (this only
// happens once the space-lua `codeWidget.define` has loaded).
const widget = page
.locator("#sb-editor .sb-lua-directive-block")
.filter({ hasText: "Hello world" })
.first();
await widget.waitFor({ state: "visible", timeout: 15_000 });
await widget.hover();
// The button bar must have rendered (Reload is always present for a block
// widget), proving we're actually inspecting a real button bar...
await expect(
widget.locator('.button-bar button[data-button="reload"]'),
).toHaveCount(1);
// ...but there must be no Bake button.
await expect(
widget.locator('.button-bar button[data-button="bake"]'),
).toHaveCount(0);
});