fix(web): adapt steer/session-url tests and stub daemon to snapshot sync

The snapshot-based session resync (51743345) replaced listMessages with
GET /sessions/{id}/snapshot as the initial sync path. Update the two
test suites that predate it (mock getSessionSnapshot + seedSnapshot,
assert on the snapshot call) and teach the dev stub daemon the
/snapshot route so pnpm dev:stub keeps working.
This commit is contained in:
qer 2026-06-11 14:49:21 +08:00
parent b3161a08ad
commit cef4664e35
3 changed files with 42 additions and 6 deletions

View file

@ -1072,6 +1072,21 @@ const server = http.createServer((req, res) => {
}
}
// ---- snapshot (v2 initial sync: GET /sessions/{id}/snapshot) ----
if (seg[0] === 'sessions' && seg[2] === 'snapshot' && seg.length === 3 && method === 'GET') {
const session = sessions.find((s) => s.id === sid);
if (!session) return res.end(fail(40401, `session ${sid} does not exist`));
return res.end(ok({
as_of_seq: seqBySession[sid] || 0,
epoch: 'ep_stub',
session,
messages: { items: messages[sid] || [], has_more: false },
in_flight_turn: null,
pending_approvals: [],
pending_questions: [],
}));
}
// ---- messages ----
if (seg[0] === 'sessions' && seg[2] === 'messages' && seg.length === 3 && method === 'GET') {
const sp = new URLSearchParams(url.split('?')[1] || '');

View file

@ -57,6 +57,7 @@ async function setup(opts: {
subscribe: vi.fn(),
unsubscribe: vi.fn(),
bindNextPromptId: vi.fn(),
seedSnapshot: vi.fn(),
abort: vi.fn(),
close: vi.fn(),
};
@ -74,11 +75,21 @@ async function setup(opts: {
return found;
}),
deleteSession: vi.fn(async () => ({ deleted: true })),
listMessages: vi.fn(async (id: string) => {
getSessionSnapshot: vi.fn(async (id: string) => {
if (messageMissingSessions.has(id)) {
throw { name: 'DaemonApiError', code: 40401, message: `session ${id} does not exist` };
}
return { items: [], hasMore: false };
const found = extras.find((s) => s.id === id) ?? listed.find((s) => s.id === id) ?? session(id);
return {
asOfSeq: 0,
epoch: 'ep_test',
session: found,
messages: [],
hasMoreMessages: false,
inFlightTurn: null,
pendingApprovals: [],
pendingQuestions: [],
};
}),
listTasks: vi.fn(async () => []),
getGitStatus: vi.fn(async () => ({ branch: 'main', ahead: 0, behind: 0, entries: {} })),
@ -196,7 +207,7 @@ describe('session ↔ URL binding', () => {
expect(window.location.pathname).toBe('/sessions/sess_1');
});
it('load() repairs a deep link when the listed session vanishes before messages load', async () => {
it('load() repairs a deep link when the listed session vanishes before its snapshot loads', async () => {
const { api, client } = await setup({
sessions: [session('sess_gone'), session('sess_1')],
messageMissingSessions: ['sess_gone'],
@ -204,11 +215,11 @@ describe('session ↔ URL binding', () => {
});
await client.load();
expect(api.listMessages).toHaveBeenCalledWith('sess_gone', { pageSize: 100 });
expect(api.getSessionSnapshot).toHaveBeenCalledWith('sess_gone');
expect(client.activeSessionId.value).toBe('sess_1');
expect(client.sessions.value.map((s) => s.id)).toEqual(['sess_1']);
expect(window.location.pathname).toBe('/sessions/sess_1');
expect(client.warnings.value.some((w) => w.includes('Failed to load messages'))).toBe(false);
expect(client.warnings.value.some((w) => w.includes('Failed to load session snapshot'))).toBe(false);
});
it('popstate selects the session from the URL without writing the URL again', async () => {

View file

@ -43,6 +43,7 @@ async function setup(opts?: { submitStatuses?: ('running' | 'queued')[] }) {
subscribe: vi.fn(),
unsubscribe: vi.fn(),
bindNextPromptId: vi.fn(),
seedSnapshot: vi.fn(),
abort: vi.fn(),
close: vi.fn(),
};
@ -51,7 +52,16 @@ async function setup(opts?: { submitStatuses?: ('running' | 'queued')[] }) {
const created = session('sess_1');
const api = {
createSession: vi.fn(async () => created),
listMessages: vi.fn(async () => ({ items: [], hasMore: false })),
getSessionSnapshot: vi.fn(async () => ({
asOfSeq: 0,
epoch: 'ep_test',
session: created,
messages: [],
hasMoreMessages: false,
inFlightTurn: null,
pendingApprovals: [],
pendingQuestions: [],
})),
submitPrompt: vi.fn(async () => {
promptN += 1;
return {