import { afterEach, describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { addAccountByKey, removeAccount } from '../src/auth.js'; import { cacheClear, cacheKey, cacheSet } from '../src/cache.js'; import { handleChatCompletions } from '../src/handlers/chat.js'; const createdAccountIds = []; function fakeRes() { const listeners = new Map(); return { body: '', writableEnded: false, write(chunk) { this.body += String(chunk); return true; }, end(chunk) { if (chunk) this.write(chunk); this.writableEnded = true; for (const cb of listeners.get('close') || []) cb(); }, on(event, cb) { if (!listeners.has(event)) listeners.set(event, []); listeners.get(event).push(cb); return this; }, }; } function parseChatFrames(raw) { return raw .split('\n\n') .filter(Boolean) .filter(frame => !frame.startsWith(':')) .map(frame => { const dataLine = frame.split('\n').find(line => line.startsWith('data: ')); const payload = dataLine?.slice(6) || ''; return payload === '[DONE]' ? '[DONE]' : JSON.parse(payload); }); } afterEach(() => { cacheClear(); while (createdAccountIds.length) { removeAccount(createdAccountIds.pop()); } }); describe('chat cache-hit stream shape', () => { it('matches the live-stream finish chunk plus terminal usage chunk shape', async () => { const account = addAccountByKey(`cache-key-${Date.now()}`, 'cache-hit'); createdAccountIds.push(account.id); const body = { model: 'gemini-2.5-flash', stream: true, messages: [{ role: 'user', content: 'hi' }], }; cacheSet(cacheKey(body), { text: 'cached answer', thinking: 'cached thinking' }); const result = await handleChatCompletions(body); assert.equal(result.status, 200); assert.equal(result.stream, true); const res = fakeRes(); await result.handler(res); const frames = parseChatFrames(res.body); const finishChunk = frames.at(-3); const usageChunk = frames.at(-2); assert.equal(finishChunk.choices[0].finish_reason, 'stop'); assert.equal('usage' in finishChunk, false); assert.deepEqual(usageChunk.choices, []); assert.deepEqual(usageChunk.usage, { cached: true, prompt_tokens: 1, completion_tokens: 4, total_tokens: 5, input_tokens: 1, output_tokens: 4, prompt_tokens_details: { cached_tokens: 1 }, completion_tokens_details: { reasoning_tokens: 0 }, }); assert.equal(frames.at(-1), '[DONE]'); }); });