Merge pull request '#54: resilient undo E2E (preflight skip-guard) — fixes main E2E red' (#55) from s54-undo-e2e-resilience into main

This commit was merged in pull request #55.
This commit is contained in:
2026-06-13 16:17:02 +00:00
2 changed files with 50 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
import * as fs from "fs";
import * as path from "path";
import * as vscode from "vscode";
/**
* #54: `vscode.commands.executeCommand("undo")` is non-functional in some headless
* `.vscode-test` instances (it does not restore the buffer), which false-fails
* every undo-dependent E2E (#38, #40) and makes `main` E2E red there. This is a
* RUNTIME probe: it performs a real edit-then-undo on a scratch buffer and reports
* whether undo actually restored it. Undo-dependent suites gate on it — running
* normally where undo works (real coverage), skipping with a loud warning where it
* doesn't (no false red, no silent loss — the skip is logged). Memoized per run.
*/
let cached: boolean | undefined;
export async function undoWorks(): Promise<boolean> {
if (cached !== undefined) return cached;
const abs = path.join(process.env.E2E_WORKSPACE!, "docs/.undo-probe.md");
fs.mkdirSync(path.dirname(abs), { recursive: true });
fs.writeFileSync(abs, "undo probe baseline\n", "utf8");
const doc = await vscode.workspace.openTextDocument(vscode.Uri.file(abs));
await vscode.window.showTextDocument(doc);
await new Promise((r) => setTimeout(r, 250));
const edit = new vscode.WorkspaceEdit();
edit.insert(doc.uri, doc.positionAt(doc.getText().length), "PROBE-EDIT-MARKER");
await vscode.workspace.applyEdit(edit);
await new Promise((r) => setTimeout(r, 250));
if (!doc.getText().includes("PROBE-EDIT-MARKER")) {
cached = false; // even the edit didn't take — treat as not undo-capable
return cached;
}
await vscode.commands.executeCommand("undo");
await new Promise((r) => setTimeout(r, 250));
cached = !doc.getText().includes("PROBE-EDIT-MARKER"); // undo removed the marker → undo works
return cached;
}
/** Loud, single-line reason logged when an undo suite skips (no silent loss — #54). */
export const UNDO_SKIP_REASON =
"[E2E] SKIPPING undo-dependent suite — executeCommand('undo') is non-functional in this " +
"VS Code test instance (see vscode-cowriting-plugin#54). These tests run where undo works.";
+9
View File
@@ -3,6 +3,7 @@ import * as fs from "fs";
import * as path from "path"; import * as path from "path";
import * as vscode from "vscode"; import * as vscode from "vscode";
import type { CowritingApi } from "../../../src/extension"; import type { CowritingApi } from "../../../src/extension";
import { undoWorks, UNDO_SKIP_REASON } from "./undoCapable";
const WS = process.env.E2E_WORKSPACE!; const WS = process.env.E2E_WORKSPACE!;
const settle = () => new Promise((r) => setTimeout(r, 400)); const settle = () => new Promise((r) => setTimeout(r, 400));
@@ -34,6 +35,14 @@ suite("F10 #38 — undo does not mis-attribute restored text (host E2E, no LLM)"
const DOC_REL = "docs/undo38.md"; const DOC_REL = "docs/undo38.md";
const BASE = "Alpha bravo charlie.\n"; const BASE = "Alpha bravo charlie.\n";
// #54: skip (loudly) where executeCommand("undo") is non-functional; run where it works.
suiteSetup(async function () {
if (!(await undoWorks())) {
console.warn(UNDO_SKIP_REASON);
this.skip();
}
});
test("undo of a deletion of baseline text leaves it unattributed (not human)", async () => { test("undo of a deletion of baseline text leaves it unattributed (not human)", async () => {
const { doc, key } = await freshDoc(DOC_REL, BASE); const { doc, key } = await freshDoc(DOC_REL, BASE);
const api = await getApi(); const api = await getApi();