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>
This commit is contained in:
Ben Stull
2026-06-11 07:49:05 -07:00
parent e617f504e7
commit 15d1df0f4c
2 changed files with 85 additions and 40 deletions
@@ -28,8 +28,6 @@ suite("no-workspace activation (#8)", () => {
"cowriting.acceptProposal", "cowriting.acceptProposal",
"cowriting.rejectProposal", "cowriting.rejectProposal",
"cowriting.proposeAgentEdit", "cowriting.proposeAgentEdit",
"cowriting.toggleDiffView",
"cowriting.pinDiffBaseline",
]) { ]) {
assert.ok(all.includes(command), `${command} is registered`); assert.ok(all.includes(command), `${command} is registered`);
} }
@@ -39,4 +37,26 @@ suite("no-workspace activation (#8)", () => {
await vscode.commands.executeCommand("cowriting.editSelection"); await vscode.commands.executeCommand("cowriting.editSelection");
await vscode.commands.executeCommand("cowriting.createThread"); await vscode.commands.executeCommand("cowriting.createThread");
}); });
// F6 (#19) is workspace-INDEPENDENT: its commands are real (not stubs) even
// with no folder open, and the toggle works on an untitled buffer.
test("F6 toggle works with no folder open (untitled buffer)", async () => {
const all = await vscode.commands.getCommands(true);
assert.ok(all.includes("cowriting.toggleDiffView"), "toggleDiffView registered");
assert.ok(all.includes("cowriting.pinDiffBaseline"), "pinDiffBaseline registered");
const untitled = await vscode.workspace.openTextDocument({ content: "no-folder scratch\n", language: "markdown" });
await vscode.window.showTextDocument(untitled);
await new Promise((r) => setTimeout(r, 300));
await vscode.commands.executeCommand("cowriting.toggleDiffView");
await new Promise((r) => setTimeout(r, 300));
const opened = vscode.window.tabGroups.all.some((g) =>
g.tabs.some(
(t) =>
t.input instanceof vscode.TabInputTextDiff &&
t.input.original.scheme === "cowriting-baseline" &&
t.input.modified.toString() === untitled.uri.toString(),
),
);
assert.ok(opened, "a cowriting-baseline diff opened for the untitled buffer with no folder");
});
}); });
+63 -38
View File
@@ -1,11 +1,13 @@
import * as assert from "assert"; import * as assert from "assert";
import * as fs from "fs"; import * as fs from "fs";
import * as os from "os";
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";
const WS = process.env.E2E_WORKSPACE!; const WS = process.env.E2E_WORKSPACE!;
const DOC_REL = "docs/diffview.md"; const DOC_REL = "docs/diffview.md";
const docUri = () => vscode.Uri.file(path.join(WS, DOC_REL)).toString();
async function openDoc(): Promise<vscode.TextDocument> { async function openDoc(): Promise<vscode.TextDocument> {
const uri = vscode.Uri.file(path.join(WS, DOC_REL)); const uri = vscode.Uri.file(path.join(WS, DOC_REL));
@@ -22,16 +24,17 @@ async function getApi(): Promise<CowritingApi> {
const settle = () => new Promise((r) => setTimeout(r, 300)); const settle = () => new Promise((r) => setTimeout(r, 300));
// Order-dependent (F2F4 pattern): later tests consume earlier state. Owns // Order-dependent (F2F4 pattern): later tests consume earlier state. Owns
// docs/diffview.md exclusively. // docs/diffview.md exclusively. F6 works on ANY file (#19), so the last two
suite("F6 diff-view toggle (host E2E — programmatic seam ingress, no LLM)", () => { // 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 TARGET = "A target sentence Claude will rewrite via the seam.";
const REPLACEMENT = "A SENTENCE CLAUDE REWROTE 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 () => { test("opening a tracked doc captures an `opened` baseline equal to the buffer (INV-18)", async () => {
const doc = await openDoc(); const doc = await openDoc();
await getApi();
const api = await getApi(); const api = await getApi();
// renderIfOpen on open already called ensureBaseline; assert it captured. const baseline = api.diffViewController.getBaseline(docUri());
const baseline = api.diffViewController.getBaseline(DOC_REL);
assert.ok(baseline, "baseline captured on first sight"); assert.ok(baseline, "baseline captured on first sight");
assert.strictEqual(baseline!.reason, "opened"); assert.strictEqual(baseline!.reason, "opened");
assert.strictEqual(baseline!.text, doc.getText(), "baseline = open-time buffer"); assert.strictEqual(baseline!.text, doc.getText(), "baseline = open-time buffer");
@@ -39,11 +42,10 @@ suite("F6 diff-view toggle (host E2E — programmatic seam ingress, no LLM)", ()
test("toggle opens a diff tab (original scheme cowriting-baseline) over the live doc (PUC-1)", async () => { test("toggle opens a diff tab (original scheme cowriting-baseline) over the live doc (PUC-1)", async () => {
const api = await getApi(); const api = await getApi();
assert.strictEqual(api.diffViewController.isDiffOpen(DOC_REL), false, "no diff open yet"); assert.strictEqual(api.diffViewController.isDiffOpen(docUri()), false, "no diff open yet");
await vscode.commands.executeCommand("cowriting.toggleDiffView"); await vscode.commands.executeCommand("cowriting.toggleDiffView");
await settle(); await settle();
assert.strictEqual(api.diffViewController.isDiffOpen(DOC_REL), true, "diff tab open"); assert.strictEqual(api.diffViewController.isDiffOpen(docUri()), true, "diff tab open");
// The active tab is a TextDiff whose original is the baseline scheme.
const active = vscode.window.tabGroups.activeTabGroup.activeTab; const active = vscode.window.tabGroups.activeTabGroup.activeTab;
assert.ok(active && active.input instanceof vscode.TabInputTextDiff, "active tab is a diff"); assert.ok(active && active.input instanceof vscode.TabInputTextDiff, "active tab is a diff");
assert.strictEqual( assert.strictEqual(
@@ -56,12 +58,12 @@ suite("F6 diff-view toggle (host E2E — programmatic seam ingress, no LLM)", ()
test("typing leaves the baseline unchanged while the buffer diverges", async () => { test("typing leaves the baseline unchanged while the buffer diverges", async () => {
const doc = await openDoc(); const doc = await openDoc();
const api = await getApi(); const api = await getApi();
const before = api.diffViewController.getBaseline(DOC_REL)!.text; const before = api.diffViewController.getBaseline(docUri())!.text;
const edit = new vscode.WorkspaceEdit(); const edit = new vscode.WorkspaceEdit();
edit.insert(doc.uri, new vscode.Position(0, 0), "OPERATOR ADDED LINE\n"); edit.insert(doc.uri, new vscode.Position(0, 0), "OPERATOR ADDED LINE\n");
assert.ok(await vscode.workspace.applyEdit(edit), "operator edit applied"); assert.ok(await vscode.workspace.applyEdit(edit), "operator edit applied");
await settle(); await settle();
assert.strictEqual(api.diffViewController.getBaseline(DOC_REL)!.text, before, "baseline unchanged by typing"); assert.strictEqual(api.diffViewController.getBaseline(docUri())!.text, before, "baseline unchanged by typing");
assert.notStrictEqual(doc.getText(), before, "buffer diverged"); assert.notStrictEqual(doc.getText(), before, "buffer diverged");
}); });
@@ -82,7 +84,7 @@ suite("F6 diff-view toggle (host E2E — programmatic seam ingress, no LLM)", ()
assert.ok(id, "propose returns an id"); assert.ok(id, "propose returns an id");
assert.ok(await api.proposalController.acceptById(DOC_REL, id!), "accept applies via the seam"); assert.ok(await api.proposalController.acceptById(DOC_REL, id!), "accept applies via the seam");
await settle(); await settle();
const baseline = api.diffViewController.getBaseline(DOC_REL)!; const baseline = api.diffViewController.getBaseline(docUri())!;
assert.strictEqual(baseline.reason, "machine-landing", "baseline advanced on the landing"); 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(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.ok(!baseline.text.includes(TARGET), "old target gone from the baseline too");
@@ -97,7 +99,7 @@ suite("F6 diff-view toggle (host E2E — programmatic seam ingress, no LLM)", ()
assert.ok(await vscode.workspace.applyEdit(edit)); assert.ok(await vscode.workspace.applyEdit(edit));
await settle(); await settle();
assert.notStrictEqual( assert.notStrictEqual(
api.diffViewController.getBaseline(DOC_REL)!.text, api.diffViewController.getBaseline(docUri())!.text,
doc.getText(), doc.getText(),
"operator changes show against the advanced baseline", "operator changes show against the advanced baseline",
); );
@@ -108,59 +110,82 @@ suite("F6 diff-view toggle (host E2E — programmatic seam ingress, no LLM)", ()
const api = await getApi(); const api = await getApi();
await vscode.commands.executeCommand("cowriting.pinDiffBaseline"); await vscode.commands.executeCommand("cowriting.pinDiffBaseline");
await settle(); await settle();
const baseline = api.diffViewController.getBaseline(DOC_REL)!; const baseline = api.diffViewController.getBaseline(docUri())!;
assert.strictEqual(baseline.reason, "pinned"); assert.strictEqual(baseline.reason, "pinned");
assert.strictEqual(baseline.text, doc.getText(), "pinned baseline == current buffer (diff empties)"); assert.strictEqual(baseline.text, doc.getText(), "pinned baseline == current buffer (diff empties)");
}); });
test("the baseline is persisted on disk under the storage dir with the expected content (PUC-4)", async () => { test("the baseline is persisted in GLOBAL storage, never the repo (PUC-4, INV-19)", async () => {
await openDoc();
const api = await getApi(); const api = await getApi();
const p = api.diffViewController.baselineFilePath(DOC_REL); const p = api.diffViewController.baselineFilePath(docUri());
assert.ok(p, "storage-backed baseline path is available"); assert.ok(p, "storage-backed baseline path is available for a file: doc");
assert.ok(fs.existsSync(p!), `baseline file exists at ${p}`); assert.ok(fs.existsSync(p!), `baseline file exists at ${p}`);
const onDisk = JSON.parse(fs.readFileSync(p!, "utf8")); const onDisk = JSON.parse(fs.readFileSync(p!, "utf8"));
assert.strictEqual(onDisk.docPath, DOC_REL); assert.strictEqual(onDisk.uri, docUri(), "baseline records the document URI");
assert.strictEqual(onDisk.reason, "pinned", "last epoch (pin) persisted"); assert.strictEqual(onDisk.reason, "pinned", "last epoch (pin) persisted");
assert.strictEqual(onDisk.text, api.diffViewController.getBaseline(DOC_REL)!.text, "on-disk == in-memory"); assert.strictEqual(onDisk.text, api.diffViewController.getBaseline(docUri())!.text, "on-disk == in-memory");
// INV-19: nothing leaked into the repo's .threads sidecar tree. // 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!.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 () => { test("toggle again closes the diff tab and reveals the normal editor (PUC-1)", async () => {
const api = await getApi(); const api = await getApi();
if (!api.diffViewController.isDiffOpen(DOC_REL)) { if (!api.diffViewController.isDiffOpen(docUri())) {
await openDoc();
await vscode.commands.executeCommand("cowriting.toggleDiffView"); await vscode.commands.executeCommand("cowriting.toggleDiffView");
await settle(); await settle();
} }
assert.strictEqual(api.diffViewController.isDiffOpen(DOC_REL), true, "diff open before close"); assert.strictEqual(api.diffViewController.isDiffOpen(docUri()), true, "diff open before close");
await vscode.commands.executeCommand("cowriting.toggleDiffView"); await vscode.commands.executeCommand("cowriting.toggleDiffView");
await settle(); await settle();
assert.strictEqual(api.diffViewController.isDiffOpen(DOC_REL), false, "diff tab closed"); assert.strictEqual(api.diffViewController.isDiffOpen(docUri()), false, "diff tab closed");
// "Normal editor is back": the file is the active text editor, and no
// baseline-diff tab for it remains in any group.
assert.strictEqual( assert.strictEqual(
vscode.window.activeTextEditor?.document.uri.toString(), vscode.window.activeTextEditor?.document.uri.toString(),
vscode.Uri.file(path.join(WS, DOC_REL)).toString(), docUri(),
"the normal editor for the doc is active after closing the diff", "the normal editor for the doc is active after closing the diff",
); );
}); });
test("toggling on an untracked doc warns and opens no diff (PUC-5)", async () => { test("toggle works on a file OUTSIDE the workspace folder, persisted in global storage (#19)", async () => {
await getApi(); const api = await getApi();
const untracked = await vscode.workspace.openTextDocument({ content: "scratch", language: "markdown" }); const outsideDir = fs.mkdtempSync(path.join(os.tmpdir(), "cowriting-outside-"));
await vscode.window.showTextDocument(untracked); 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(); 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 vscode.commands.executeCommand("cowriting.toggleDiffView");
await settle(); await settle();
// No baseline-diff tab for an untitled doc anywhere. assert.strictEqual(api.diffViewController.isDiffOpen(outsideUri.toString()), true, "diff opens for the outside file");
const anyDiff = vscode.window.tabGroups.all.some((g) => const fp = api.diffViewController.baselineFilePath(outsideUri.toString());
g.tabs.some( assert.ok(fp && fs.existsSync(fp), "outside-file baseline persisted in global storage");
(t) => assert.ok(!fp!.startsWith(WS + path.sep), "not under the workspace folder");
t.input instanceof vscode.TabInputTextDiff && // close it so it doesn't bleed into the untitled test's active-tab checks
t.input.original.scheme === "cowriting-baseline" && await vscode.commands.executeCommand("cowriting.toggleDiffView");
t.input.modified.toString() === untracked.uri.toString(), await settle();
), fs.rmSync(outsideDir, { recursive: true, force: true });
); });
assert.strictEqual(anyDiff, false, "no diff opened for the untracked doc");
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");
}); });
}); });