testChangesInEditor
The Changes view's data: this branch's history, newest first, what an entry changed (an edit with its code before and after as documents, what was re-hashed because of it, a rename), and the branches with how many names differ.
import { plainEnv, tcmBin, tempDir, withChildren } from "#codebase/tcmts/cli/test/e2e/harness"; import { client } from "#codebase/tcmts/cli/test/e2e/lsp"; import assert from "node:assert/strict"; import { spawnSync } from "node:child_process"; import fs from "node:fs"; import path from "node:path"; import { pathToFileURL } from "node:url"; export const testChangesInEditor = () => withChildren(async (keep) => { const dir = tempDir("lsp changes"); const tcm = (...args: string[]) => spawnSync(process.execPath, [tcmBin(), ...args], { cwd: dir, env: plainEnv(), encoding: "utf8", }); tcm("init"); fs.writeFileSync( path.join(dir, "scratch.ts"), `// tcm: namespace lib\nexport const square = (x: number): number => x * x;\nexport const area = (s: number): number => square(s);\n`, ); assert.equal(tcm("add").status, 0); fs.writeFileSync( path.join(dir, "scratch.ts"), `// tcm: namespace lib\nexport const square = (x: number): number => x ** 2;\n`, ); assert.equal(tcm("update").status, 0); assert.equal(tcm("mv", "lib.area", "lib.areaOf").status, 0); assert.equal(tcm("branch", "idea").status, 0); const c = client(keep); await c.request("initialize", { processId: null, rootUri: pathToFileURL(dir).href, capabilities: {}, clientInfo: { name: "Visual Studio Code" }, }); c.notify("initialized", {}); const history = await c.request("tcm/history", { limit: 10 }); assert.deepEqual( history.map((h: any) => [h.command, h.back]), [ ["mv lib.area lib.areaOf", 0], ["update lib.square", 1], ["add lib.square, lib.area", 2], ], ); const update = await c.request("tcm/historyEntry", { hash: history[1].hash }); assert.deepEqual( update.map((x: any) => [x.change, x.path]), [ ["edited", "lib.square"], ["propagated", "lib.area"], ], ); assert.deepEqual(update[1].because, ["lib.square"]); // the code before and after, to diff: documents rendered when the editor asks for them assert.match(update[0].oldUri, /^tcm:\/@\w+\.ts\?at=\w+$/); const text = async (uri: string) => (await c.request("tcm/source", { uri })).text as string; assert.match(await text(update[0].oldUri), /x \* x/); assert.match(await text(update[0].uri), /x \*\* 2/); const mv = await c.request("tcm/historyEntry", { hash: history[0].hash }); assert.deepEqual( mv.map((x: any) => [x.change, x.path, x.from]), [["renamed", "lib.areaOf", "lib.area"]], ); // a branch, created from this one: nothing differs until this one moves on assert.deepEqual( (await c.request("tcm/branches", {})).map((b: any) => [b.name, b.current, b.differs]), [ ["main", true, 0], ["idea", false, 0], ], ); assert.equal(tcm("rm", "lib.areaOf").status, 0); assert.deepEqual( (await c.request("tcm/branches", {})).map((b: any) => [b.name, b.differs]), [ ["main", 0], ["idea", 1], ], ); // what it has that this one doesn't, name by name, to open as diffs const toIdea = await c.request("tcm/branchChanges", { branch: "idea" }); assert.deepEqual( toIdea.map((x: any) => [x.change, x.path]), [["added", "lib.areaOf"]], ); // (its code, with that branch's names) assert.match(toIdea[0].uri, /\?branch=idea$/); assert.match( await text(toIdea[0].uri), // (a renamed function keeps its runtime name, part of its hash, until it's edited) /^\/\/ lib\.areaOf [\s\S]*export const area = \(s: number\): number => square\(s\)/, ); })