Files
plainleaf/e2e/lua-completion.test.ts
T

162 lines
5.0 KiB
TypeScript

import { expect, gotoSilverBulletPage, mod, test } from "./fixtures.ts";
test.use({
spaceFiles: {
"LuaCompletion.md": `# Lua completion
\`\`\`space-lua
lua.parseB
string.gs
editor.setT
editor.getT
system.invokeF
jumpdemo.target()
\`\`\`
`,
"LuaDefinitions.md": `#meta
\`\`\`space-lua
jumpdemo = {}
function jumpdemo.target()
return "definition"
end
\`\`\`
`,
},
});
test("Lua API completion shows signatures and documentation", async ({
sbServer,
page,
}) => {
await gotoSilverBulletPage(page, sbServer, "LuaCompletion");
const startCompletionAt = async (prefix: string) => {
await page.evaluate(async (prefix) => {
const client = (globalThis as any).client;
const view = client.editorView;
const text = view.state.doc.toString();
const cursor = text.indexOf(prefix) + prefix.length;
view.dispatch({ selection: { anchor: cursor } });
view.focus();
await client.clientSystem.localSyscall("editor.startCompletion", []);
}, prefix);
};
await startCompletionAt("lua.parseB");
const luaOption = page.locator(".cm-tooltip-autocomplete li", {
hasText: "parseBlock(code)",
});
await expect(luaOption).toBeVisible();
await expect(luaOption.locator(".cm-completionDetail")).toHaveText(
"Parses a Space Lua chunk and returns its AST. Blocks retain comments in source order with their exact text, kind, and source range.",
);
const documentation = page.locator(
".cm-completionInfo .sb-completion-documentation",
);
await expect(documentation).toBeVisible();
await expect(documentation.locator(":scope > h3")).toBeHidden();
await expect(documentation).toContainText("lua.parseBlock(code)");
await expect(documentation).toContainText(
"Parses a Space Lua chunk and returns its AST.",
);
await expect(documentation).toContainText("Parameters:");
await expect(documentation).toContainText("code");
await expect(documentation).toContainText("Lua code to parse.");
await luaOption.click({ force: true });
const appliedCompletion = await page.evaluate(() => {
const view = (globalThis as any).client.editorView;
const selection = view.state.selection.main;
const line = view.state.doc.lineAt(selection.head);
return {
line: line.text,
cursorOffset: selection.head - line.from,
selectionEmpty: selection.empty,
};
});
expect(appliedCompletion).toEqual({
line: "lua.parseBlock()",
cursorOffset: "lua.parseBlock(".length,
selectionEmpty: true,
});
await page.keyboard.press("Escape");
await startCompletionAt("string.gs");
const builtinOption = page.locator(".cm-tooltip-autocomplete li", {
hasText: "gsub(s, pattern, replacement, n?)",
});
await expect(builtinOption).toBeVisible();
await expect(builtinOption.locator(".cm-completionDetail")).toHaveText(
"Replaces Lua-pattern matches using a string, table, or function replacement.",
);
await page.keyboard.press("Escape");
await startCompletionAt("editor.setT");
const syscallWithParameters = page.locator(".cm-tooltip-autocomplete li", {
hasText: "setText(newText, shouldIsolateHistory?)",
});
await expect(syscallWithParameters).toBeVisible();
await expect(
syscallWithParameters.locator(".cm-completionDetail"),
).toHaveText(
"Updates the editor text with a minimal diff while preserving the cursor when possible.",
);
await page.keyboard.press("Escape");
await startCompletionAt("editor.getT");
const syscallWithoutParameters = page.locator(".cm-tooltip-autocomplete li", {
hasText: "getText()",
});
await expect(syscallWithoutParameters).toBeVisible();
await expect(
syscallWithoutParameters.locator(".cm-completionDetail"),
).toHaveText("Returns the full text of the currently open page or document.");
await page.keyboard.press("Escape");
await startCompletionAt("system.invokeF");
const signatureFallback = page.locator(".cm-tooltip-autocomplete li", {
hasText: "invokeFunction(name, ...)",
});
await expect(signatureFallback).toBeVisible();
await expect(signatureFallback.locator(".cm-completionDetail")).toHaveText(
"Invokes a loaded plug function by its plug-qualified name.",
);
});
test("modifier-click navigates to Lua function definitions", async ({
sbServer,
page,
}) => {
await gotoSilverBulletPage(page, sbServer, "LuaCompletion");
const coordinates = await page.evaluate(() => {
const view = (globalThis as any).client.editorView;
const text = view.state.doc.toString();
const symbol = "jumpdemo.target";
const position = text.indexOf(symbol) + "jumpdemo.".length + 2;
const coordinates = view.coordsAtPos(position);
if (!coordinates) throw new Error("Could not resolve symbol coordinates");
return {
x: coordinates.left + 2,
y: (coordinates.top + coordinates.bottom) / 2,
};
});
await page.keyboard.down(mod);
await page.mouse.click(coordinates.x, coordinates.y);
await page.keyboard.up(mod);
await expect(page.locator("#sb-current-page input.sb-input")).toHaveValue(
"LuaDefinitions",
);
await page.waitForURL(/\/LuaDefinitions$/);
});