import * as assert from "assert"; import * as fs from "fs"; import * as path from "path"; import * as vscode from "vscode"; import type { CowritingApi } from "../../../src/extension"; const WS = process.env.E2E_WORKSPACE!; const settle = () => new Promise((r) => setTimeout(r, 400)); async function getApi(): Promise { const ext = vscode.extensions.getExtension("benstull.vscode-cowriting-plugin")!; const api = (await ext.activate()) as CowritingApi; assert.ok(api?.trackChangesPreviewController && api?.diffViewController, "exports preview + diffView"); return api; } /** Create + open a fresh markdown doc under WS, returning the doc + its uri key. */ async function freshDoc(rel: string, body: string): Promise<{ doc: vscode.TextDocument; key: string }> { const abs = path.join(WS, rel); fs.mkdirSync(path.dirname(abs), { recursive: true }); fs.writeFileSync(abs, body, "utf8"); const uri = vscode.Uri.file(abs); const doc = await vscode.workspace.openTextDocument(uri); await vscode.window.showTextDocument(doc); await settle(); return { doc, key: uri.toString() }; } // F11 host E2E (no LLM): the preview toolbar is the primary interaction surface. // The webview posts intent messages; the host routes them through the existing // F4/F6/F3 seams (INV-35). The webview DOM (real button clicks) is sealed and // manual-smoke only; here we simulate the inbound messages via `receiveMessage`. suite("F11 preview toolbar (host E2E — message → seam wiring, no LLM)", () => { // SLICE-1: the Pin baseline button. test("pinBaseline message pins the PREVIEWED doc → marks clear, baseline reason is pinned (PUC-5, INV-35)", async () => { const { doc, key } = await freshDoc("docs/f11pin.md", "# F11 pin\n\nA baseline paragraph that will diverge.\n"); const api = await getApi(); await vscode.commands.executeCommand("cowriting.showTrackChangesPreview"); await settle(); assert.strictEqual(api.trackChangesPreviewController.isOpen(key), true, "panel open"); // Diverge from the opened baseline so the preview carries a real change-mark. const edit = new vscode.WorkspaceEdit(); edit.insert(doc.uri, doc.positionAt(doc.getText().length), "\n\nA freshly typed paragraph that diverges.\n"); assert.ok(await vscode.workspace.applyEdit(edit), "operator edit applied"); await settle(); const marked = (api.trackChangesPreviewController.getLastModel(key) ?? []).some((o) => o.kind !== "unchanged"); assert.ok(marked, "the typed paragraph shows as a change before pinning"); // Simulate the webview's Pin baseline button posting its intent. api.trackChangesPreviewController.receiveMessage(key, { type: "pinBaseline" }); await settle(); const model = api.trackChangesPreviewController.getLastModel(key) ?? []; assert.ok(model.length > 0 && model.every((o) => o.kind === "unchanged"), "after pin, every block is unchanged"); assert.strictEqual(api.diffViewController.getBaseline(key)?.reason, "pinned", "baseline reason advanced to pinned"); }); // SLICE-1 reachability: the orphaned pin command gets a real palette `when`. test("pinDiffBaseline is reachable from the command palette (when: editorLangId == markdown)", async () => { const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "../../../../package.json"), "utf8")); const entry = (pkg.contributes.menus.commandPalette as Array<{ command: string; when?: string }>).find( (m) => m.command === "cowriting.pinDiffBaseline", ); assert.ok(entry, "pinDiffBaseline has a commandPalette entry"); assert.notStrictEqual(entry!.when, "false", "it is no longer hidden (when:false)"); assert.match(entry!.when ?? "", /editorLangId == markdown/, "guarded on markdown"); }); });