Skip to content

Commit 8a2e09b

Browse files
committed
refactor: fully autonomous test runner — no manual server needed
- run-all.ts auto-starts sandbox server for phases 1-9 (shared, one start) - Each phase 1-9 can also run standalone (auto-starts/stops own server) - Phases 10-18 remain self-contained as before - Single command: npx tsx tests/run-all.ts (354 tests, ~65s)
1 parent 1d82517 commit 8a2e09b

11 files changed

Lines changed: 95 additions & 139 deletions

File tree

demo-projects/test-sandbox/tests/01-server-indexing.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
get, post,
1111
mcpCall,
1212
assert, assertEqual, assertExists, assertOk, assertStatus, assertMcpOk, assertIncludes,
13-
printSummary,
13+
printSummary, runStandalone,
1414
wait,
1515
} from './utils';
1616

@@ -338,8 +338,5 @@ export async function run() {
338338
}
339339

340340
if (process.argv[1]?.includes('01-')) {
341-
run().then(result => {
342-
printSummary([result]);
343-
process.exit(result.groups.some(g => g.tests.some(t => !t.passed)) ? 1 : 0);
344-
});
341+
runStandalone(run);
345342
}

demo-projects/test-sandbox/tests/02-knowledge.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
get, post, put, del,
1010
mcpCall,
1111
assert, assertEqual, assertExists, assertOk, assertStatus, assertMcpOk, assertIncludes,
12-
printSummary, wait,
12+
printSummary, runStandalone, wait,
1313
fileExists, readFile, projectPath,
1414
} from './utils';
1515
import { writeFileSync, unlinkSync } from 'fs';
@@ -379,8 +379,5 @@ export async function run() {
379379
}
380380

381381
if (process.argv[1]?.includes('02-')) {
382-
run().then(result => {
383-
printSummary([result]);
384-
process.exit(result.groups.some(g => g.tests.some(t => !t.passed)) ? 1 : 0);
385-
});
382+
runStandalone(run);
386383
}

demo-projects/test-sandbox/tests/03-tasks.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
get, post, put, del,
1111
mcpCall,
1212
assert, assertEqual, assertExists, assertOk, assertStatus, assertMcpOk, assertIncludes,
13-
printSummary, wait,
13+
printSummary, runStandalone, wait,
1414
fileExists, projectPath,
1515
} from './utils';
1616
import { writeFileSync, unlinkSync } from 'fs';
@@ -494,8 +494,5 @@ export async function run() {
494494
}
495495

496496
if (process.argv[1]?.includes('03-')) {
497-
run().then(result => {
498-
printSummary([result]);
499-
process.exit(result.groups.some(g => g.tests.some(t => !t.passed)) ? 1 : 0);
500-
});
497+
runStandalone(run);
501498
}

demo-projects/test-sandbox/tests/04-epics.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
get, post, put, del,
1010
mcpCall,
1111
assert, assertEqual, assertExists, assertOk, assertStatus, assertMcpOk, assertIncludes,
12-
printSummary, wait,
12+
printSummary, runStandalone, wait,
1313
} from './utils';
1414

1515
let restEpicId = '';
@@ -223,8 +223,5 @@ export async function run() {
223223
}
224224

225225
if (process.argv[1]?.includes('04-')) {
226-
run().then(result => {
227-
printSummary([result]);
228-
process.exit(result.groups.some(g => g.tests.some(t => !t.passed)) ? 1 : 0);
229-
});
226+
runStandalone(run);
230227
}

demo-projects/test-sandbox/tests/05-skills.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
get, post, put, del,
1111
mcpCall,
1212
assert, assertEqual, assertExists, assertOk, assertStatus, assertMcpOk, assertIncludes,
13-
printSummary, wait,
13+
printSummary, runStandalone, wait,
1414
fileExists, projectPath,
1515
} from './utils';
1616
import { writeFileSync, unlinkSync } from 'fs';
@@ -378,8 +378,5 @@ export async function run() {
378378
}
379379

380380
if (process.argv[1]?.includes('05-')) {
381-
run().then(result => {
382-
printSummary([result]);
383-
process.exit(result.groups.some(g => g.tests.some(t => !t.passed)) ? 1 : 0);
384-
});
381+
runStandalone(run);
385382
}

demo-projects/test-sandbox/tests/06-auth-oauth.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
group, test, runPhase,
1313
get, post,
1414
assert, assertEqual, assertExists, assertOk, assertStatus,
15-
printSummary,
15+
printSummary, runStandalone,
1616
BASE,
1717
} from './utils';
1818

@@ -142,8 +142,5 @@ export async function run() {
142142
}
143143

144144
if (process.argv[1]?.includes('06-')) {
145-
run().then(result => {
146-
printSummary([result]);
147-
process.exit(result.groups.some(g => g.tests.some(t => !t.passed)) ? 1 : 0);
148-
});
145+
runStandalone(run);
149146
}

demo-projects/test-sandbox/tests/07-embedding.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
group, test, runPhase,
1010
post, get,
1111
assert, assertOk, assertStatus,
12-
printSummary,
12+
printSummary, runStandalone,
1313
BASE,
1414
} from './utils';
1515

@@ -65,8 +65,5 @@ export async function run() {
6565
}
6666

6767
if (process.argv[1]?.includes('07-')) {
68-
run().then(result => {
69-
printSummary([result]);
70-
process.exit(result.groups.some(g => g.tests.some(t => !t.passed)) ? 1 : 0);
71-
});
68+
runStandalone(run);
7269
}

demo-projects/test-sandbox/tests/08-edge-cases.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
get, post, put, del,
1010
mcpCall,
1111
assert, assertEqual, assertExists, assertOk, assertStatus, assertMcpOk,
12-
printSummary, wait,
12+
printSummary, runStandalone, wait,
1313
} from './utils';
1414

1515
// ─── 8.1 Validation ─────────────────────────────────────────────
@@ -237,8 +237,5 @@ export async function run() {
237237
}
238238

239239
if (process.argv[1]?.includes('08-')) {
240-
run().then(result => {
241-
printSummary([result]);
242-
process.exit(result.groups.some(g => g.tests.some(t => !t.passed)) ? 1 : 0);
243-
});
240+
runStandalone(run);
244241
}

demo-projects/test-sandbox/tests/09-db-filesystem.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
get, post, del,
1010
mcpCall,
1111
assert, assertEqual, assertExists, assertOk, assertMcpOk,
12-
printSummary, wait,
12+
printSummary, runStandalone, wait,
1313
fileExists, readFile, projectPath,
1414
} from './utils';
1515
import { readdirSync, existsSync } from 'fs';
@@ -185,8 +185,5 @@ export async function run() {
185185
}
186186

187187
if (process.argv[1]?.includes('09-')) {
188-
run().then(result => {
189-
printSummary([result]);
190-
process.exit(result.groups.some(g => g.tests.some(t => !t.passed)) ? 1 : 0);
191-
});
188+
runStandalone(run);
192189
}

demo-projects/test-sandbox/tests/run-all.ts

Lines changed: 61 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,48 @@
11
/**
2-
* Test runner — executes all phases in order and prints combined summary.
2+
* Test runner — fully autonomous, starts/stops servers as needed.
33
*
44
* Usage:
5-
* npx tsx tests/run-all.ts # run all phases
6-
* npx tsx tests/run-all.ts --phase 1 3 # run specific phases
7-
* npx tsx tests/run-all.ts --phase 10 11 # run auth + oauth only
5+
* npx tsx tests/run-all.ts # run all 18 phases
6+
* npx tsx tests/run-all.ts --phase 1 3 # run specific phases
7+
* npx tsx tests/run-all.ts --phase 10 # run auth only
88
*
9-
* Phases 1-9 require a running server on port 3737 (default sandbox).
10-
* Phases 10-18 start/stop their own servers with different configs.
9+
* Lifecycle:
10+
* Phases 1-9: share one sandbox server (port 3737) — started once, stopped after phase 9
11+
* Phases 10-18: each starts/stops its own server with a dedicated config
1112
*/
1213

13-
import { PhaseResult, printSummary } from './utils';
14+
import { PhaseResult, printSummary, startServer, stopServer } from './utils';
15+
16+
// ─── Phase registry ──────────────────────────────────────────────
17+
18+
interface PhaseEntry {
19+
id: number;
20+
file: string;
21+
group: 'sandbox' | 'self'; // sandbox = needs shared server, self = manages own
22+
}
23+
24+
const PHASES: PhaseEntry[] = [
25+
{ id: 1, file: './01-server-indexing', group: 'sandbox' },
26+
{ id: 2, file: './02-knowledge', group: 'sandbox' },
27+
{ id: 3, file: './03-tasks', group: 'sandbox' },
28+
{ id: 4, file: './04-epics', group: 'sandbox' },
29+
{ id: 5, file: './05-skills', group: 'sandbox' },
30+
{ id: 6, file: './06-auth-oauth', group: 'sandbox' },
31+
{ id: 7, file: './07-embedding', group: 'sandbox' },
32+
{ id: 8, file: './08-edge-cases', group: 'sandbox' },
33+
{ id: 9, file: './09-db-filesystem', group: 'sandbox' },
34+
{ id: 10, file: './10-auth', group: 'self' },
35+
{ id: 11, file: './11-oauth', group: 'self' },
36+
{ id: 12, file: './12-embedding-api', group: 'self' },
37+
{ id: 13, file: './13-websocket', group: 'self' },
38+
{ id: 14, file: './14-watcher', group: 'self' },
39+
{ id: 15, file: './15-workspace', group: 'self' },
40+
{ id: 16, file: './16-ratelimit', group: 'self' },
41+
{ id: 17, file: './17-concurrent', group: 'self' },
42+
{ id: 18, file: './18-mirror-import', group: 'self' },
43+
];
44+
45+
// ─── Main ────────────────────────────────────────────────────────
1446

1547
async function main() {
1648
const args = process.argv.slice(2);
@@ -27,100 +59,35 @@ async function main() {
2759

2860
const shouldRun = (n: number) => phaseFilter.size === 0 || phaseFilter.has(n);
2961
const results: PhaseResult[] = [];
62+
const startTime = Date.now();
63+
64+
// ── Sandbox phases (1-9): shared server ──────────────────────
65+
const sandboxPhases = PHASES.filter(p => p.group === 'sandbox' && shouldRun(p.id));
66+
if (sandboxPhases.length > 0) {
67+
console.log('\n Starting sandbox server (port 3737)...');
68+
await startServer({ config: 'graph-memory.yaml', port: 3737 });
69+
console.log(' Server ready.\n');
70+
71+
for (const phase of sandboxPhases) {
72+
const { run } = require(phase.file);
73+
results.push(await run());
74+
}
3075

31-
// Phases 1-9: require external server on port 3737
32-
if (shouldRun(1)) {
33-
const { run } = require('./01-server-indexing');
34-
results.push(await run());
35-
}
36-
37-
if (shouldRun(2)) {
38-
const { run } = require('./02-knowledge');
39-
results.push(await run());
40-
}
41-
42-
if (shouldRun(3)) {
43-
const { run } = require('./03-tasks');
44-
results.push(await run());
45-
}
46-
47-
if (shouldRun(4)) {
48-
const { run } = require('./04-epics');
49-
results.push(await run());
50-
}
51-
52-
if (shouldRun(5)) {
53-
const { run } = require('./05-skills');
54-
results.push(await run());
55-
}
56-
57-
if (shouldRun(6)) {
58-
const { run } = require('./06-auth-oauth');
59-
results.push(await run());
60-
}
61-
62-
if (shouldRun(7)) {
63-
const { run } = require('./07-embedding');
64-
results.push(await run());
65-
}
66-
67-
if (shouldRun(8)) {
68-
const { run } = require('./08-edge-cases');
69-
results.push(await run());
70-
}
71-
72-
if (shouldRun(9)) {
73-
const { run } = require('./09-db-filesystem');
74-
results.push(await run());
75-
}
76-
77-
// Phases 10-18: self-contained (start/stop own servers)
78-
if (shouldRun(10)) {
79-
const { run } = require('./10-auth');
80-
results.push(await run());
81-
}
82-
83-
if (shouldRun(11)) {
84-
const { run } = require('./11-oauth');
85-
results.push(await run());
86-
}
87-
88-
if (shouldRun(12)) {
89-
const { run } = require('./12-embedding-api');
90-
results.push(await run());
91-
}
92-
93-
if (shouldRun(13)) {
94-
const { run } = require('./13-websocket');
95-
results.push(await run());
96-
}
97-
98-
if (shouldRun(14)) {
99-
const { run } = require('./14-watcher');
100-
results.push(await run());
101-
}
102-
103-
if (shouldRun(15)) {
104-
const { run } = require('./15-workspace');
105-
results.push(await run());
106-
}
107-
108-
if (shouldRun(16)) {
109-
const { run } = require('./16-ratelimit');
110-
results.push(await run());
111-
}
112-
113-
if (shouldRun(17)) {
114-
const { run } = require('./17-concurrent');
115-
results.push(await run());
76+
stopServer();
77+
console.log('\n Sandbox server stopped.\n');
11678
}
11779

118-
if (shouldRun(18)) {
119-
const { run } = require('./18-mirror-import');
80+
// ── Self-contained phases (10-18): each manages own server ───
81+
const selfPhases = PHASES.filter(p => p.group === 'self' && shouldRun(p.id));
82+
for (const phase of selfPhases) {
83+
const { run } = require(phase.file);
12084
results.push(await run());
12185
}
12286

87+
// ── Summary ──────────────────────────────────────────────────
88+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
12389
printSummary(results);
90+
console.log(` Duration: ${elapsed}s\n`);
12491

12592
const hasFails = results.some(r =>
12693
r.groups.some(g => g.tests.some(t => !t.passed)),

0 commit comments

Comments
 (0)