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, "exports preview controller"); return api; } /** Write a markdown file under WS and return its uri (without opening it). */ function writeFile(rel: string, body: string): vscode.Uri { const abs = path.join(WS, rel); fs.mkdirSync(path.dirname(abs), { recursive: true }); fs.writeFileSync(abs, body, "utf8"); return vscode.Uri.file(abs); } function pkg(): any { return JSON.parse(fs.readFileSync(path.join(__dirname, "../../../../package.json"), "utf8")); } // #41 (story): "Open Cowriting Review Panel" reachable from the markdown // file/tab right-click menu. The review surface (showTrackChangesPreview) is the // plugin's central affordance; this adds explorer/context + editor/title/context // entry points and makes the command open the *clicked* document — not merely // the active editor — so the explorer right-click works even when the file is // not already open. suite("#41 review-panel right-click entry (host E2E — menu wiring + clicked-doc resolution)", () => { test("command with a Uri previews the CLICKED doc, not the active editor", async () => { // Two markdown docs; A is the active editor, B is the right-clicked target. const aUri = writeFile("docs/menu-active.md", "# Active\n\nThe active editor's document.\n"); const bUri = writeFile("docs/menu-clicked.md", "# Clicked\n\nThe right-clicked document.\n"); const aDoc = await vscode.workspace.openTextDocument(aUri); await vscode.window.showTextDocument(aDoc); const bDoc = await vscode.workspace.openTextDocument(bUri); // open but NOT active await settle(); const api = await getApi(); await vscode.commands.executeCommand("cowriting.showTrackChangesPreview", bUri); await settle(); assert.strictEqual(api.trackChangesPreviewController.isOpen(bUri.toString()), true, "preview opened for the clicked doc"); assert.strictEqual( api.trackChangesPreviewController.isOpen(aUri.toString()), false, "the active editor's doc did NOT get a preview", ); assert.ok(bDoc, "clicked doc handle held"); }); test("command with a Uri for a not-yet-open file opens it and previews (explorer case)", async () => { // Write a file but do not openTextDocument it — mimics an Explorer right-click. const uri = writeFile("docs/menu-unopened.md", "# Unopened\n\nNever opened before the right-click.\n"); const key = uri.toString(); const api = await getApi(); assert.ok( !vscode.workspace.textDocuments.some((d) => d.uri.toString() === key), "precondition: the file is not an open document", ); await vscode.commands.executeCommand("cowriting.showTrackChangesPreview", uri); await settle(); assert.strictEqual(api.trackChangesPreviewController.isOpen(key), true, "the clicked-but-unopened file got a preview"); }); test("no-arg invocation still falls back to the active editor (palette / keybinding unchanged)", async () => { const uri = writeFile("docs/menu-noarg.md", "# No-arg\n\nActive editor for the no-arg path.\n"); const doc = await vscode.workspace.openTextDocument(uri); await vscode.window.showTextDocument(doc); await settle(); const api = await getApi(); await vscode.commands.executeCommand("cowriting.showTrackChangesPreview"); await settle(); assert.strictEqual(api.trackChangesPreviewController.isOpen(uri.toString()), true, "no-arg previews the active editor"); }); test("explorer/context contributes the review-panel item for markdown only", () => { const items = (pkg().contributes.menus["explorer/context"] ?? []) as Array<{ command: string; when?: string }>; const entry = items.find((m) => m.command === "cowriting.showTrackChangesPreview"); assert.ok(entry, "explorer/context has a showTrackChangesPreview entry"); assert.match(entry!.when ?? "", /resourceLangId == markdown/, "gated on markdown resources"); }); test("editor/title/context (tab right-click) contributes the review-panel item for markdown only", () => { const items = (pkg().contributes.menus["editor/title/context"] ?? []) as Array<{ command: string; when?: string }>; const entry = items.find((m) => m.command === "cowriting.showTrackChangesPreview"); assert.ok(entry, "editor/title/context has a showTrackChangesPreview entry"); assert.match(entry!.when ?? "", /resourceLangId == markdown/, "gated on markdown tabs"); }); test("the command title reads 'Open Cowriting Review Panel'", () => { const cmd = (pkg().contributes.commands as Array<{ command: string; title: string }>).find( (c) => c.command === "cowriting.showTrackChangesPreview", ); assert.ok(cmd, "command is contributed"); assert.strictEqual(cmd!.title, "Open Cowriting Review Panel", "menus render this title"); }); test("the ctrl+alt+r keybinding still targets the command (unchanged)", () => { const kb = (pkg().contributes.keybindings as Array<{ command: string; key: string; when?: string }>).find( (k) => k.command === "cowriting.showTrackChangesPreview", ); assert.ok(kb, "keybinding still present"); assert.strictEqual(kb!.key, "ctrl+alt+r", "key unchanged"); }); });