Skip to content

Commit b971016

Browse files
committed
test: generate minimal-repo fixture at runtime; remove fixtures/ from git
Adds ensureMinimalRepoFixture() (one per package, to avoid cross-package tsconfig rootDir issues); the 6 tests that used fixtures/minimal-repo now materialize it via top-level await before use. fixtures/ is untracked and gitignored. Verified: deleting the on-disk folder and running the suite regenerates it — 109 tests pass.
1 parent 348e03d commit b971016

13 files changed

Lines changed: 145 additions & 37 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,6 @@ fixtures/minimal-repo/
4646

4747
# Ephemeral npm auth (bin/publish-npm.ts)
4848
.npmrc
49+
50+
# Test fixtures are generated at test time (ensureMinimalRepoFixture)
51+
fixtures/

fixtures/minimal-repo/.opencode/loop_attempt.json

Lines changed: 0 additions & 6 deletions
This file was deleted.

fixtures/minimal-repo/.opencode/ralph.json

Lines changed: 0 additions & 8 deletions
This file was deleted.

fixtures/minimal-repo/package.json

Lines changed: 0 additions & 8 deletions
This file was deleted.

fixtures/minimal-repo/scripts/verify.mjs

Lines changed: 0 additions & 9 deletions
This file was deleted.

packages/engine/src/test/loop-engine.integration.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ import { loadPlanContext } from "../protocol-files.js";
99
import { stateFilePath } from "../plan-paths.js";
1010
import { fileExists } from "../fs.js";
1111
import { createMockRuntime, mockSubscribe } from "./mock-runtime.js";
12+
import { ensureMinimalRepoFixture } from "./minimal-repo-fixture.js";
1213

13-
const fixtureRoot = path.resolve(import.meta.dirname, "../../../../fixtures/minimal-repo");
14+
const fixtureRoot = await ensureMinimalRepoFixture(
15+
path.resolve(import.meta.dirname, "../../../../fixtures/minimal-repo")
16+
);
1417

1518
async function makeFixtureCopy(): Promise<string> {
1619
const root = await mkdtemp(path.join(tmpdir(), "ralph-loop-"));

packages/engine/src/test/loop-registry.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ import { tmpdir } from "node:os";
44
import { describe, expect, test } from "bun:test";
55
import { LoopRegistry } from "../loop-registry.js";
66
import { createMockRuntime, mockSubscribe } from "./mock-runtime.js";
7+
import { ensureMinimalRepoFixture } from "./minimal-repo-fixture.js";
78

8-
const fixtureRoot = path.resolve(import.meta.dirname, "../../../../fixtures/minimal-repo");
9+
const fixtureRoot = await ensureMinimalRepoFixture(
10+
path.resolve(import.meta.dirname, "../../../../fixtures/minimal-repo")
11+
);
912

1013
describe("LoopRegistry", () => {
1114
test("list returns synchronous snapshots", async () => {
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { mkdir, writeFile } from "node:fs/promises";
2+
import path from "node:path";
3+
4+
/**
5+
* The minimal fixture repo used by the loop/verify tests. Materialized at test
6+
* time (and git-ignored) so it doesn't live in version control. `verify.mjs`
7+
* passes only once `.ralph-pass-marker` exists, which drives fail→pass tests.
8+
*/
9+
const FILES: Record<string, string> = {
10+
"package.json": `${JSON.stringify(
11+
{
12+
name: "ralph-minimal-fixture",
13+
private: true,
14+
type: "module",
15+
scripts: { verify: "node scripts/verify.mjs" },
16+
},
17+
null,
18+
2
19+
)}\n`,
20+
".opencode/ralph.json": `${JSON.stringify(
21+
{
22+
enabled: true,
23+
maxAttempts: 5,
24+
verify: { command: ["node", "scripts/verify.mjs"], cwd: "." },
25+
},
26+
null,
27+
2
28+
)}\n`,
29+
".opencode/loop_attempt.json": `${JSON.stringify(
30+
{
31+
attempt: 1,
32+
sessionId: "smoke-session-b",
33+
updatedAt: "2026-06-15T17:02:22.249Z",
34+
workerSessionId: "worker-1781542942245",
35+
},
36+
null,
37+
2
38+
)}\n`,
39+
"scripts/verify.mjs": `import { existsSync } from "node:fs";
40+
41+
if (existsSync(".ralph-pass-marker")) {
42+
console.log("PASS");
43+
process.exit(0);
44+
}
45+
46+
console.error("FAIL: .ralph-pass-marker missing");
47+
process.exit(1);
48+
`,
49+
};
50+
51+
/** Write the minimal fixture repo into `root` (idempotent). Returns `root`. */
52+
export async function ensureMinimalRepoFixture(root: string): Promise<string> {
53+
for (const [rel, content] of Object.entries(FILES)) {
54+
const dest = path.join(root, rel);
55+
await mkdir(path.dirname(dest), { recursive: true });
56+
await writeFile(dest, content);
57+
}
58+
return root;
59+
}

packages/engine/src/test/verify.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ import path from "node:path";
22
import { describe, expect, test } from "bun:test";
33
import { loadConfig } from "../config.js";
44
import { runAndParseVerify } from "../verify.js";
5+
import { ensureMinimalRepoFixture } from "./minimal-repo-fixture.js";
56

6-
const fixtureRoot = path.resolve(import.meta.dirname, "../../../../fixtures/minimal-repo");
7+
const fixtureRoot = await ensureMinimalRepoFixture(
8+
path.resolve(import.meta.dirname, "../../../../fixtures/minimal-repo")
9+
);
710

811
describe("runAndParseVerify", () => {
912
test("fails when pass marker is missing", async () => {
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { mkdir, writeFile } from "node:fs/promises";
2+
import path from "node:path";
3+
4+
/**
5+
* The minimal fixture repo used by the loop/verify tests. Materialized at test
6+
* time (and git-ignored) so it doesn't live in version control. `verify.mjs`
7+
* passes only once `.ralph-pass-marker` exists, which drives fail→pass tests.
8+
*/
9+
const FILES: Record<string, string> = {
10+
"package.json": `${JSON.stringify(
11+
{
12+
name: "ralph-minimal-fixture",
13+
private: true,
14+
type: "module",
15+
scripts: { verify: "node scripts/verify.mjs" },
16+
},
17+
null,
18+
2
19+
)}\n`,
20+
".opencode/ralph.json": `${JSON.stringify(
21+
{
22+
enabled: true,
23+
maxAttempts: 5,
24+
verify: { command: ["node", "scripts/verify.mjs"], cwd: "." },
25+
},
26+
null,
27+
2
28+
)}\n`,
29+
".opencode/loop_attempt.json": `${JSON.stringify(
30+
{
31+
attempt: 1,
32+
sessionId: "smoke-session-b",
33+
updatedAt: "2026-06-15T17:02:22.249Z",
34+
workerSessionId: "worker-1781542942245",
35+
},
36+
null,
37+
2
38+
)}\n`,
39+
"scripts/verify.mjs": `import { existsSync } from "node:fs";
40+
41+
if (existsSync(".ralph-pass-marker")) {
42+
console.log("PASS");
43+
process.exit(0);
44+
}
45+
46+
console.error("FAIL: .ralph-pass-marker missing");
47+
process.exit(1);
48+
`,
49+
};
50+
51+
/** Write the minimal fixture repo into `root` (idempotent). Returns `root`. */
52+
export async function ensureMinimalRepoFixture(root: string): Promise<string> {
53+
for (const [rel, content] of Object.entries(FILES)) {
54+
const dest = path.join(root, rel);
55+
await mkdir(path.dirname(dest), { recursive: true });
56+
await writeFile(dest, content);
57+
}
58+
return root;
59+
}

0 commit comments

Comments
 (0)