Skip to content

Commit 6f0cb48

Browse files
committed
test: add e2e latency tests for completion mode
Spawns the actual CLI binary with __complete args and measures wall-clock latency. Catches regressions that would re-introduce heavy imports into the completion fast-path. Tests: - Completion is faster than a normal command (--version) - Completion exits under 500ms budget (pre-fix was ~530ms) - Completion exits cleanly with no stderr - Empty args handled gracefully
1 parent 2b4fd24 commit 6f0cb48

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed

test/e2e/completion.test.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/**
2+
* Completion Latency E2E Tests
3+
*
4+
* Spawns the actual CLI binary with `__complete` args and measures
5+
* wall-clock latency. The completion fast-path skips @sentry/bun,
6+
* Stricli, and middleware — these tests catch regressions that would
7+
* re-introduce heavy imports into the completion path.
8+
*
9+
* Pre-optimization baseline: ~530ms (dev), ~320ms (binary)
10+
* Post-optimization target: ~60ms (dev), ~190ms (binary)
11+
*/
12+
13+
import { describe, expect, test } from "bun:test";
14+
import { join } from "node:path";
15+
import { getCliCommand } from "../fixture.js";
16+
17+
const cliDir = join(import.meta.dir, "../..");
18+
19+
/** Spawn a CLI process and measure wall-clock duration. */
20+
async function measureCommand(
21+
args: string[],
22+
env?: Record<string, string | undefined>
23+
): Promise<{
24+
duration: number;
25+
exitCode: number;
26+
stdout: string;
27+
stderr: string;
28+
}> {
29+
const cmd = getCliCommand();
30+
const start = performance.now();
31+
const proc = Bun.spawn([...cmd, ...args], {
32+
cwd: cliDir,
33+
env: { ...process.env, ...env },
34+
stdout: "pipe",
35+
stderr: "pipe",
36+
});
37+
38+
const [stdout, stderr] = await Promise.all([
39+
new Response(proc.stdout).text(),
40+
new Response(proc.stderr).text(),
41+
]);
42+
await proc.exited;
43+
44+
return {
45+
duration: performance.now() - start,
46+
exitCode: proc.exitCode ?? 1,
47+
stdout,
48+
stderr,
49+
};
50+
}
51+
52+
describe("completion latency", () => {
53+
test("completion is faster than a normal command", async () => {
54+
// Normal command loads telemetry, Stricli, all commands
55+
const normal = await measureCommand(["--version"]);
56+
57+
// Completion skips all heavy imports
58+
const completion = await measureCommand([
59+
"__complete",
60+
"issue",
61+
"list",
62+
"",
63+
]);
64+
65+
expect(normal.exitCode).toBe(0);
66+
expect(completion.exitCode).toBe(0);
67+
68+
// Completion should not be slower than a normal command
69+
expect(completion.duration).toBeLessThan(normal.duration);
70+
});
71+
72+
test("completion exits under latency budget", async () => {
73+
const result = await measureCommand(["__complete", "issue", "list", ""]);
74+
75+
expect(result.exitCode).toBe(0);
76+
77+
// 500ms budget — generous for CI (dev is ~60ms, binary ~190ms),
78+
// but catches regressions from the pre-fix ~530ms baseline.
79+
expect(result.duration).toBeLessThan(500);
80+
});
81+
82+
test("completion exits cleanly with no stderr", async () => {
83+
const result = await measureCommand(["__complete", "org", "view", ""]);
84+
85+
expect(result.exitCode).toBe(0);
86+
// No error output — completions should be silent on stderr
87+
expect(result.stderr).toBe("");
88+
});
89+
90+
test("completion with empty args exits cleanly", async () => {
91+
const result = await measureCommand(["__complete", ""]);
92+
93+
expect(result.exitCode).toBe(0);
94+
expect(result.stderr).toBe("");
95+
});
96+
});

0 commit comments

Comments
 (0)