/** * @license * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import assert from 'node:assert'; import crypto from 'node:crypto'; import {existsSync, rmSync} from 'node:fs'; import {dirname} from 'node:path'; import {describe, it, afterEach, beforeEach} from 'node:test'; import { handleResponse, startDaemon, stopDaemon, } from '../../src/daemon/client.js'; import {isDaemonRunning} from '../../src/daemon/utils.js'; describe('daemon client', () => { describe('start/stop', () => { let sessionId: string; beforeEach(async () => { sessionId = crypto.randomUUID(); await stopDaemon(sessionId); }); afterEach(async () => { await stopDaemon(sessionId); }); it('should start and stop daemon', async () => { assert.ok( !isDaemonRunning(sessionId), 'Daemon should not be running initially', ); await startDaemon([], sessionId); assert.ok( isDaemonRunning(sessionId), 'Daemon should be running after start', ); await stopDaemon(sessionId); assert.ok( !isDaemonRunning(sessionId), 'Daemon should not be running after stop', ); }); it('should handle starting daemon when already running', async () => { await startDaemon([], sessionId); assert.ok(isDaemonRunning(sessionId), 'Daemon should be running'); // Starting again should be a no-op await startDaemon([], sessionId); assert.ok(isDaemonRunning(sessionId), 'Daemon should still be running'); }); it('should handle stopping daemon when not running', async () => { assert.ok( !isDaemonRunning(sessionId), 'Daemon should not be running initially', ); // Stopping when not running should be a no-op await stopDaemon(sessionId); assert.ok( !isDaemonRunning(sessionId), 'Daemon should still not be running', ); }); }); describe('parsing', () => { it('handles MCP response with text format', async () => { const textResponse = {content: [{type: 'text' as const, text: 'test'}]}; assert.strictEqual(await handleResponse(textResponse, 'md'), 'test'); }); it('handles JSON response', async () => { const jsonResponse = { content: [], structuredContent: { test: 'data', number: 123, }, }; assert.strictEqual( await handleResponse(jsonResponse, 'json'), JSON.stringify(jsonResponse.structuredContent), ); }); it('handles error response when isError is true', async () => { const errorResponse = { isError: true, content: [{type: 'text' as const, text: 'Something went wrong'}], }; assert.strictEqual( await handleResponse(errorResponse, 'md'), JSON.stringify(errorResponse.content), ); }); it('handles text response when json format is requested but no structured content', async () => { const textResponse = { content: [{type: 'text' as const, text: 'Fall through text'}], }; assert.deepStrictEqual( await handleResponse(textResponse, 'json'), JSON.stringify(['Fall through text']), ); }); it('supports images', async () => { const unsupportedContentResponse = { content: [ { type: 'image' as const, data: 'base64data', mimeType: 'image/png', }, ], structuredContent: {}, }; const response = await handleResponse(unsupportedContentResponse, 'md'); assert.ok(response.includes('.png')); }); it('includes saved image file paths in structured JSON responses', async () => { const imageContentResponse = { content: [ { type: 'text' as const, text: 'Took a screenshot.', }, { type: 'image' as const, data: Buffer.from('image data').toString('base64'), mimeType: 'image/png', }, ], structuredContent: { message: 'Took a screenshot.', }, }; let filePath: string | undefined; try { const response = await handleResponse(imageContentResponse, 'json'); const parsed = JSON.parse(response) as { message: string; images: Array<{filePath: string; mimeType: string}>; }; assert.strictEqual(parsed.message, 'Took a screenshot.'); assert.strictEqual(parsed.images.length, 1); assert.strictEqual(parsed.images[0].mimeType, 'image/png'); filePath = parsed.images[0].filePath; assert.ok(filePath.endsWith('.png')); assert.ok(existsSync(filePath)); } finally { if (filePath) { rmSync(dirname(filePath), {recursive: true, force: true}); } } }); it('uses the webp extension for WebP images', async () => { const webpContentResponse = { content: [ { type: 'image' as const, data: 'base64data', mimeType: 'image/webp', }, ], structuredContent: {}, }; const response = await handleResponse(webpContentResponse, 'md'); assert.ok(response.includes('.webp')); }); }); });