Skip to content

Commit a3388f8

Browse files
committed
test: pin the replay handler's routing decisions
session-replay.ts is a router now, so it gets a focused test of its own (AGENTS.md 1:1 source/test topology): replay reaches the script-source runtime, test reaches the suite command with the whole parameter set, and an unrelated command is declined. Both destinations are mocked so a wrong edge shows up as the wrong marker; each case was proven red by mutating the routing it pins.
1 parent d3ec226 commit a3388f8

1 file changed

Lines changed: 92 additions & 0 deletions

File tree

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/**
2+
* `session-replay.ts` is a routing decision and nothing else: `replay` is one script run, `test` is
3+
* a suite of them, and any other command belongs to a different handler family. Both arms'
4+
* orchestration lives in its own module, so what is left to pin here is the routing itself —
5+
* which arm each command reaches, that the other arm is NOT reached, and that an unrelated command
6+
* is declined rather than swallowed.
7+
*
8+
* Both destinations are mocked, so a wrong edge is observable as the wrong marker rather than as a
9+
* device-level failure: swapping the two delegations flips the first two cases red.
10+
*/
11+
import { beforeEach, expect, test, vi } from 'vitest';
12+
import path from 'node:path';
13+
import type { DaemonRequest } from '../../types.ts';
14+
import { SessionStore } from '../../session-store.ts';
15+
import { LeaseRegistry } from '../../lease-registry.ts';
16+
import { mkdtempForTestSync } from '../../../__tests__/test-utils/tmp-dir.ts';
17+
18+
vi.mock('../session-replay-runtime.ts', () => ({
19+
runReplayScriptSource: vi.fn(async () => ({ ok: true, data: { reached: 'replay-runtime' } })),
20+
}));
21+
22+
vi.mock('../session-test-suite-command.ts', () => ({
23+
runReplayTestSuiteCommand: vi.fn(async () => ({ ok: true, data: { reached: 'test-suite' } })),
24+
}));
25+
26+
import { handleSessionReplayCommands } from '../session-replay.ts';
27+
import { runReplayScriptSource } from '../session-replay-runtime.ts';
28+
import { runReplayTestSuiteCommand } from '../session-test-suite-command.ts';
29+
30+
const mockRunReplayScriptSource = vi.mocked(runReplayScriptSource);
31+
const mockRunReplayTestSuiteCommand = vi.mocked(runReplayTestSuiteCommand);
32+
33+
beforeEach(() => {
34+
mockRunReplayScriptSource.mockClear();
35+
mockRunReplayTestSuiteCommand.mockClear();
36+
});
37+
38+
function routerParams(command: string) {
39+
const root = mkdtempForTestSync('agent-device-replay-router-');
40+
const req: DaemonRequest = {
41+
token: 'token',
42+
session: 'default',
43+
command,
44+
positionals: [],
45+
flags: {},
46+
};
47+
return {
48+
req,
49+
sessionName: 'default',
50+
logPath: path.join(root, 'daemon.log'),
51+
sessionStore: new SessionStore(path.join(root, 'sessions')),
52+
leaseRegistry: new LeaseRegistry(),
53+
invoke: async () => ({ ok: true as const, data: {} }),
54+
};
55+
}
56+
57+
test('a replay request routes to the script-source runtime, not the suite command', async () => {
58+
const params = routerParams('replay');
59+
60+
const response = await handleSessionReplayCommands(params);
61+
62+
expect(response).toMatchObject({ ok: true, data: { reached: 'replay-runtime' } });
63+
expect(mockRunReplayTestSuiteCommand).not.toHaveBeenCalled();
64+
// The replay arm narrows the params rather than forwarding the suite's own shape.
65+
expect(mockRunReplayScriptSource).toHaveBeenCalledWith({
66+
req: params.req,
67+
sessionName: params.sessionName,
68+
logPath: params.logPath,
69+
sessionStore: params.sessionStore,
70+
invoke: params.invoke,
71+
});
72+
});
73+
74+
test('a test request routes to the suite command with the whole parameter set', async () => {
75+
const params = routerParams('test');
76+
77+
const response = await handleSessionReplayCommands(params);
78+
79+
expect(response).toMatchObject({ ok: true, data: { reached: 'test-suite' } });
80+
expect(mockRunReplayScriptSource).not.toHaveBeenCalled();
81+
// The suite owns video recording, sharding and device binding, so it receives `params` whole —
82+
// narrowing here is what would silently drop those capabilities.
83+
expect(mockRunReplayTestSuiteCommand).toHaveBeenCalledWith(params);
84+
});
85+
86+
test('an unrelated command is declined so another handler family can claim it', async () => {
87+
const response = await handleSessionReplayCommands(routerParams('snapshot'));
88+
89+
expect(response).toBeNull();
90+
expect(mockRunReplayScriptSource).not.toHaveBeenCalled();
91+
expect(mockRunReplayTestSuiteCommand).not.toHaveBeenCalled();
92+
});

0 commit comments

Comments
 (0)