Files
vscode-cowriting-plugin/test/e2e/suite/diffView.test.ts
T
Ben Stull 15d1df0f4c test(f6): E2E for any-file + untitled diff-view (#19)
Migrate test surface to URI-string keys; add out-of-workspace file (persisted
in global storage) + untitled-buffer (in-memory, not persisted) cases; assert
F6 toggle works with no folder open. No LLM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 07:49:05 -07:00

192 lines
9.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import * as assert from "assert";
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import * as vscode from "vscode";
import type { CowritingApi } from "../../../src/extension";
const WS = process.env.E2E_WORKSPACE!;
const DOC_REL = "docs/diffview.md";
const docUri = () => vscode.Uri.file(path.join(WS, DOC_REL)).toString();
async function openDoc(): Promise<vscode.TextDocument> {
const uri = vscode.Uri.file(path.join(WS, DOC_REL));
const doc = await vscode.workspace.openTextDocument(uri);
await vscode.window.showTextDocument(doc);
return doc;
}
async function getApi(): Promise<CowritingApi> {
const ext = vscode.extensions.getExtension("benstull.vscode-cowriting-plugin")!;
const api = (await ext.activate()) as CowritingApi;
assert.ok(api?.diffViewController, "extension exports diffViewController");
return api;
}
const settle = () => new Promise((r) => setTimeout(r, 300));
// Order-dependent (F2F4 pattern): later tests consume earlier state. Owns
// docs/diffview.md exclusively. F6 works on ANY file (#19), so the last two
// tests use an out-of-workspace file and an untitled buffer.
suite("F6 diff-view toggle (host E2E — any file, programmatic seam ingress, no LLM)", () => {
const TARGET = "A target sentence Claude will rewrite via the seam.";
const REPLACEMENT = "A SENTENCE CLAUDE REWROTE via the seam.";
test("opening a tracked doc captures an `opened` baseline equal to the buffer (INV-18)", async () => {
const doc = await openDoc();
await getApi();
const api = await getApi();
const baseline = api.diffViewController.getBaseline(docUri());
assert.ok(baseline, "baseline captured on first sight");
assert.strictEqual(baseline!.reason, "opened");
assert.strictEqual(baseline!.text, doc.getText(), "baseline = open-time buffer");
});
test("toggle opens a diff tab (original scheme cowriting-baseline) over the live doc (PUC-1)", async () => {
const api = await getApi();
assert.strictEqual(api.diffViewController.isDiffOpen(docUri()), false, "no diff open yet");
await vscode.commands.executeCommand("cowriting.toggleDiffView");
await settle();
assert.strictEqual(api.diffViewController.isDiffOpen(docUri()), true, "diff tab open");
const active = vscode.window.tabGroups.activeTabGroup.activeTab;
assert.ok(active && active.input instanceof vscode.TabInputTextDiff, "active tab is a diff");
assert.strictEqual(
(active!.input as vscode.TabInputTextDiff).original.scheme,
"cowriting-baseline",
"left side served by the baseline provider",
);
});
test("typing leaves the baseline unchanged while the buffer diverges", async () => {
const doc = await openDoc();
const api = await getApi();
const before = api.diffViewController.getBaseline(docUri())!.text;
const edit = new vscode.WorkspaceEdit();
edit.insert(doc.uri, new vscode.Position(0, 0), "OPERATOR ADDED LINE\n");
assert.ok(await vscode.workspace.applyEdit(edit), "operator edit applied");
await settle();
assert.strictEqual(api.diffViewController.getBaseline(docUri())!.text, before, "baseline unchanged by typing");
assert.notStrictEqual(doc.getText(), before, "buffer diverged");
});
test("accepting a proposal advances the baseline past the landed text (PUC-2, INV-18)", async () => {
const doc = await openDoc();
const api = await getApi();
const start = doc.getText().indexOf(TARGET);
assert.ok(start >= 0, "fixture contains the target");
const id = await vscode.commands.executeCommand<string>("cowriting.proposeAgentEdit", {
uri: doc.uri.toString(),
start,
end: start + TARGET.length,
newText: REPLACEMENT,
model: "sonnet",
sessionId: "e2e-diff",
turnId: "turn-d1",
});
assert.ok(id, "propose returns an id");
assert.ok(await api.proposalController.acceptById(DOC_REL, id!), "accept applies via the seam");
await settle();
const baseline = api.diffViewController.getBaseline(docUri())!;
assert.strictEqual(baseline.reason, "machine-landing", "baseline advanced on the landing");
assert.ok(baseline.text.includes(REPLACEMENT), "landed text is in the baseline (won't show as a change)");
assert.ok(!baseline.text.includes(TARGET), "old target gone from the baseline too");
assert.strictEqual(baseline.text, doc.getText(), "baseline == buffer right after the landing");
});
test("an operator edit after the landing makes baseline ≠ buffer (the operator delta)", async () => {
const doc = await openDoc();
const api = await getApi();
const edit = new vscode.WorkspaceEdit();
edit.insert(doc.uri, new vscode.Position(0, 0), "POST-LANDING OPERATOR LINE\n");
assert.ok(await vscode.workspace.applyEdit(edit));
await settle();
assert.notStrictEqual(
api.diffViewController.getBaseline(docUri())!.text,
doc.getText(),
"operator changes show against the advanced baseline",
);
});
test("pin resets the baseline to now: baseline == buffer, reason pinned (PUC-3)", async () => {
const doc = await openDoc();
const api = await getApi();
await vscode.commands.executeCommand("cowriting.pinDiffBaseline");
await settle();
const baseline = api.diffViewController.getBaseline(docUri())!;
assert.strictEqual(baseline.reason, "pinned");
assert.strictEqual(baseline.text, doc.getText(), "pinned baseline == current buffer (diff empties)");
});
test("the baseline is persisted in GLOBAL storage, never the repo (PUC-4, INV-19)", async () => {
await openDoc();
const api = await getApi();
const p = api.diffViewController.baselineFilePath(docUri());
assert.ok(p, "storage-backed baseline path is available for a file: doc");
assert.ok(fs.existsSync(p!), `baseline file exists at ${p}`);
const onDisk = JSON.parse(fs.readFileSync(p!, "utf8"));
assert.strictEqual(onDisk.uri, docUri(), "baseline records the document URI");
assert.strictEqual(onDisk.reason, "pinned", "last epoch (pin) persisted");
assert.strictEqual(onDisk.text, api.diffViewController.getBaseline(docUri())!.text, "on-disk == in-memory");
// INV-19: baseline lives under the extension's storage dir, not the repo.
assert.ok(!p!.includes(`${path.sep}.threads${path.sep}`), "baseline is NOT in the sidecar tree");
assert.ok(!p!.startsWith(WS + path.sep), "baseline is NOT under the workspace folder");
assert.ok(p!.includes(`${path.sep}baselines${path.sep}`), "baseline lives under <globalStorage>/baselines/");
});
test("toggle again closes the diff tab and reveals the normal editor (PUC-1)", async () => {
const api = await getApi();
if (!api.diffViewController.isDiffOpen(docUri())) {
await openDoc();
await vscode.commands.executeCommand("cowriting.toggleDiffView");
await settle();
}
assert.strictEqual(api.diffViewController.isDiffOpen(docUri()), true, "diff open before close");
await vscode.commands.executeCommand("cowriting.toggleDiffView");
await settle();
assert.strictEqual(api.diffViewController.isDiffOpen(docUri()), false, "diff tab closed");
assert.strictEqual(
vscode.window.activeTextEditor?.document.uri.toString(),
docUri(),
"the normal editor for the doc is active after closing the diff",
);
});
test("toggle works on a file OUTSIDE the workspace folder, persisted in global storage (#19)", async () => {
const api = await getApi();
const outsideDir = fs.mkdtempSync(path.join(os.tmpdir(), "cowriting-outside-"));
const outsidePath = path.join(outsideDir, "outside.md");
fs.writeFileSync(outsidePath, "# Outside the workspace\n\nThe operator edits this too.\n", "utf8");
const outsideUri = vscode.Uri.file(outsidePath);
const doc = await vscode.workspace.openTextDocument(outsideUri);
await vscode.window.showTextDocument(doc);
await settle();
// Captured on open even though it is NOT under the workspace folder.
const baseline = api.diffViewController.getBaseline(outsideUri.toString());
assert.ok(baseline, "baseline captured for an out-of-folder file");
assert.strictEqual(baseline!.reason, "opened");
await vscode.commands.executeCommand("cowriting.toggleDiffView");
await settle();
assert.strictEqual(api.diffViewController.isDiffOpen(outsideUri.toString()), true, "diff opens for the outside file");
const fp = api.diffViewController.baselineFilePath(outsideUri.toString());
assert.ok(fp && fs.existsSync(fp), "outside-file baseline persisted in global storage");
assert.ok(!fp!.startsWith(WS + path.sep), "not under the workspace folder");
// close it so it doesn't bleed into the untitled test's active-tab checks
await vscode.commands.executeCommand("cowriting.toggleDiffView");
await settle();
fs.rmSync(outsideDir, { recursive: true, force: true });
});
test("toggle works on an UNTITLED buffer, baseline in-memory only (#19)", async () => {
const api = await getApi();
const untitled = await vscode.workspace.openTextDocument({ content: "scratch line\n", language: "markdown" });
await vscode.window.showTextDocument(untitled);
await settle();
const key = untitled.uri.toString();
assert.strictEqual(untitled.uri.scheme, "untitled", "it really is an untitled buffer");
const baseline = api.diffViewController.getBaseline(key);
assert.ok(baseline, "untitled buffer got an in-memory baseline");
assert.strictEqual(api.diffViewController.baselineFilePath(key), undefined, "untitled is NOT persisted to disk");
await vscode.commands.executeCommand("cowriting.toggleDiffView");
await settle();
assert.strictEqual(api.diffViewController.isDiffOpen(key), true, "diff opens for the untitled buffer");
});
});