Files
rea/tests/acceptance/setup/repeatedClientSetup.test.ts
morluto 9a95db6819 test(uninstall): verify current recovery snapshots through the CLI
Plan and approve Cursor setup in an isolated home, edit an unrelated server, then uninstall and verify both the historical backup and exact pre-uninstall recovery bytes. Related: #4581, PR #4580.

The new real CLI control fails on f9ccacca2 with a missing recovery file and passes with the recovery owner fix. Verified on macOS; native Windows/Linux runs remain unverified.
2026-10-17 05:01:57 +08:00

135 lines
4.2 KiB
TypeScript

import { createHash } from "node:crypto";
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect } from "vitest";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
cliTest(
"repeated client flags plan and configure each selected client once",
async ({ cli }) => {
const directory = await createTestTempDirectory("rea-repeated-clients-");
const arguments_ = [
"setup",
"--client",
"cursor",
"--client",
"codex",
"--client",
"cursor",
"--skill=false",
"--json",
];
const run = (mode: string) =>
cli.run({
arguments: [...arguments_, mode],
cwd: directory,
environment: {
HOME: directory,
USERPROFILE: directory,
TMPDIR: directory,
},
});
const configurations = [
join(directory, ".cursor/mcp.json"),
join(directory, ".codex/config.toml"),
];
const preview = await run("--dry-run");
expect(preview.exitCode, preview.stdout).toBe(0);
expect(preview.json).toMatchObject({
status: "planned",
plannedActions: [
{ id: "configure_client:cursor" },
{ id: "configure_client:codex" },
],
appliedActions: [],
});
for (const path of configurations)
await expect(access(path)).rejects.toMatchObject({ code: "ENOENT" });
const applied = await run("--yes");
expect(applied.exitCode, applied.stdout).toBe(0);
expect(applied.json).toMatchObject({
status: "ready",
plannedActions: [
{ id: "configure_client:cursor" },
{ id: "configure_client:codex" },
],
appliedActions: ["configured_cursor", "configured_codex"],
clients: {
cursor: { status: "configured" },
codex: { status: "configured" },
},
});
const configured = await Promise.all(
configurations.map((path) => readFile(path, "utf8")),
);
const repeated = await run("--yes");
expect(repeated.exitCode, repeated.stdout).toBe(0);
expect(repeated.json).toMatchObject({
status: "ready",
plannedActions: [],
appliedActions: [],
});
expect(
await Promise.all(configurations.map((path) => readFile(path, "utf8"))),
).toEqual(configured);
},
);
cliTest(
"uninstall preserves user edits made after an earlier setup",
async ({ cli }) => {
const home = await createTestTempDirectory("rea-current-uninstall-backup-");
const config = join(home, ".cursor", "mcp.json");
const original = '{"mcpServers":{"other":{"command":"other-server"}}}\n';
await mkdir(join(home, ".cursor"), { recursive: true });
await writeFile(config, original);
const run = (arguments_: readonly string[]) =>
cli.run({
arguments: [...arguments_, "--json"],
cwd: home,
environment: { HOME: home, USERPROFILE: home, TMPDIR: home },
});
const planned = await run([
"setup",
"--client",
"cursor",
"--skill=false",
"--dry-run",
]);
expect(planned.exitCode, planned.stderr).toBe(0);
expect(planned.json).toMatchObject({ status: "planned" });
expect(await readFile(config, "utf8")).toBe(original);
const installed = await run([
"setup",
"--client",
"cursor",
"--skill=false",
"--yes",
]);
expect(installed.exitCode, installed.stderr).toBe(0);
expect(installed.json).toMatchObject({ status: "ready" });
const current = (await readFile(config, "utf8")).replace(
"other-server",
"edited-server",
);
expect(current).toContain("edited-server");
await writeFile(config, current);
const removed = await run(["uninstall"]);
expect(removed.exitCode, removed.stderr).toBe(0);
expect(removed.json).toMatchObject({ status: "complete" });
const recovery = `${config}.rea.backup.${createHash("sha256").update(current).digest("hex")}.recovery`;
expect(await readFile(recovery, "utf8")).toBe(current);
expect(await readFile(`${config}.rea.backup`, "utf8")).toBe(original);
expect(JSON.parse(await readFile(config, "utf8"))).toEqual({
mcpServers: { other: { command: "edited-server" } },
});
},
);