Files
ocas/packages/cli/tests/variable-history.test.ts
T
xiaoju 0c0491ea17 chore: 测试框架从 bun:test 迁移到 vitest
- 36 个 test 文件 bun:test → vitest
- Bun.spawn() → execFileSync('tsx', ...)
- Bun.file() → readFileSync
- import.meta.dir → import.meta.dirname (tests) / __dirname (CLI source)
- 删除 bun-types devDep
- 添加 vitest + tsx devDep
- CLI shebang bun → node
- 30/36 test files pass, 558/617 tests pass

Refs #62
2026-06-03 03:13:53 +00:00

110 lines
3.5 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, test } from "vitest";
import { mkdirSync, rmSync } from "node:fs";
import { execFileSync } from "node:child_process";
import { tmpdir } from "node:os";
import { join } from "node:path";
import type { Hash, Store } from "@ocas/core";
import { bootstrap } from "@ocas/core";
import { openStore as openFsStore } from "@ocas/fs";
let testDir: string;
let storePath: string;
let cliPath: string;
beforeEach(() => {
testDir = join(
tmpdir(),
`ocas-history-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
);
storePath = join(testDir, "store");
cliPath = join(import.meta.dirname, "../src/index.ts");
mkdirSync(testDir, { recursive: true });
mkdirSync(storePath, { recursive: true });
});
afterEach(() => {
try {
rmSync(testDir, { recursive: true, force: true });
} catch {
// Ignore
}
});
function runCli(...args: string[]): { stdout: string; stderr: string; exitCode: number } {
try {
const stdout = execFileSync("tsx", [cliPath, "--home", storePath, ...args], {
encoding: "utf-8",
timeout: 10000,
});
return { stdout: stdout.trim(), stderr: "", exitCode: 0 };
} catch (e: unknown) {
const err = e as { stdout?: string; stderr?: string; status?: number };
return { stdout: (err.stdout ?? "").trim(), stderr: (err.stderr ?? "").trim(), exitCode: err.status ?? 1 };
}
}
async function setupSchemaAndValues(): Promise<{
schema: Hash;
values: Hash[];
}> {
const store: Store = await openFsStore(storePath);
const aliases = bootstrap(store);
const numberHash = aliases["@ocas/number"] as Hash;
const values: Hash[] = [];
for (let i = 0; i < 4; i++) {
values.push(store.cas.put(numberHash, i) as Hash);
}
return { schema: numberHash, values };
}
describe("var history", () => {
test("returns single entry after first set", async () => {
const { schema, values } = await setupSchemaAndValues();
const v1 = values[0] as Hash;
let r = await runCli("var", "set", "@test/x", v1);
expect(r.exitCode).toBe(0);
r = await runCli("var", "history", "@test/x", "--schema", schema);
expect(r.exitCode).toBe(0);
const envelope = JSON.parse(r.stdout);
expect(envelope.value.name).toBe("@test/x");
expect(envelope.value.schema).toBe(schema);
expect(envelope.value.values).toEqual([v1]);
});
test("history grows with new sets, current is index 0", async () => {
const { schema, values } = await setupSchemaAndValues();
const [v1, v2, v3] = values as [Hash, Hash, Hash, Hash];
await runCli("var", "set", "@test/x", v1);
await runCli("var", "set", "@test/x", v2);
await runCli("var", "set", "@test/x", v3);
const r = await runCli("var", "history", "@test/x", "--schema", schema);
expect(r.exitCode).toBe(0);
const envelope = JSON.parse(r.stdout);
expect(envelope.value.values).toEqual([v3, v2, v1]);
});
test("history works without --schema when only one variant", async () => {
const { schema: _schema, values } = await setupSchemaAndValues();
const [v1, v2] = values as [Hash, Hash, Hash, Hash];
await runCli("var", "set", "@test/x", v1);
await runCli("var", "set", "@test/x", v2);
const r = await runCli("var", "history", "@test/x");
expect(r.exitCode).toBe(0);
const envelope = JSON.parse(r.stdout);
expect(envelope.value.values).toEqual([v2, v1]);
});
test("history fails for non-existent variable", async () => {
const r = await runCli("var", "history", "missing");
expect(r.exitCode).toBe(1);
expect(r.stderr).toContain("Variable not found");
});
});