import { describe, expect, it, vi, beforeEach } from 'vitest'; const createServiceAppMock = vi.fn(); const registerOptionalJwtContextMock = vi.fn(async () => undefined); const startServiceMock = vi.fn(async () => undefined); const appMock = { register: vi.fn(async () => undefined), inject: vi.fn(), get: vi.fn(), log: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() }, addHook: vi.fn(), }; vi.mock('@bytelyst/fastify-core', () => ({ createServiceApp: createServiceAppMock, registerOptionalJwtContext: registerOptionalJwtContextMock, startService: startServiceMock, })); vi.mock('jose', () => ({ jwtVerify: vi.fn() })); vi.mock('./modules/health/routes.js', () => ({ healthRoutes: vi.fn() })); vi.mock('./modules/tasks/routes.js', () => ({ taskRoutes: vi.fn() })); vi.mock('./lib/config.js', () => ({ config: { PORT: 4009, HOST: '0.0.0.0', CORS_ORIGIN: undefined, SERVICE_NAME: 'cowork-service', PLATFORM_SERVICE_URL: 'http://localhost:4003', RUST_RUNTIME_BIN: 'cowork-orchestrator', RUST_RUNTIME_TIMEOUT_MS: 300_000, JWT_SECRET: 'test-secret', ANTHROPIC_API_KEY: undefined, OLLAMA_URL: 'http://localhost:11434/v1', OLLAMA_MODELS: undefined, EXTRACTION_SERVICE_URL: 'http://localhost:4005', }, })); vi.mock('./lib/product-config.js', () => ({ PRODUCT_ID: 'clawcowork', productConfig: { productId: 'clawcowork', displayName: 'Claw Cowork', platforms: ['macos', 'linux', 'windows'], backendPort: 4009, }, })); vi.mock('./lib/request-context.js', () => ({ getUserId: vi.fn(() => 'demo-user'), getRequestProductId: vi.fn(() => 'clawcowork'), })); vi.mock('./lib/ipc-bridge.js', () => ({ getIpcBridge: vi.fn(() => ({ isRunning: false, start: vi.fn(async () => { throw new Error('no binary in test'); }), shutdown: vi.fn(async () => undefined), onIncomingRequest: vi.fn(), })), })); vi.mock('./lib/flush-scheduler.js', () => ({ getFlushScheduler: vi.fn(() => ({ isRunning: false, start: vi.fn(), stop: vi.fn(), finalFlush: vi.fn(async () => undefined), })), })); vi.mock('./lib/llm-router.js', () => ({ initLlmRouter: vi.fn(() => ({ getProviders: vi.fn(() => []) })), getLlmRouter: vi.fn(() => ({ getProviders: vi.fn(() => []) })), isLlmRouterReady: vi.fn(() => false), })); vi.mock('./modules/llm/routes.js', () => ({ llmRoutes: vi.fn() })); vi.mock('./modules/audit/routes.js', () => ({ auditRoutes: vi.fn() })); vi.mock('./modules/usage/routes.js', () => ({ usageRoutes: vi.fn() })); vi.mock('./modules/notifications/routes.js', () => ({ notificationRoutes: vi.fn() })); vi.mock('./modules/extraction/routes.js', () => ({ extractionRoutes: vi.fn() })); vi.mock('./modules/marketplace/routes.js', () => ({ marketplaceRoutes: vi.fn() })); vi.mock('./modules/sessions/routes.js', () => ({ sessionRoutes: vi.fn() })); vi.mock('./modules/plugins/routes.js', () => ({ pluginRoutes: vi.fn() })); vi.mock('./modules/schedule/routes.js', () => ({ scheduleRoutes: vi.fn() })); vi.mock('./modules/push/routes.js', () => ({ pushRoutes: vi.fn() })); vi.mock('./modules/agent-runtime/routes.js', () => ({ agentRuntimeRoutes: vi.fn() })); describe('cowork-service bootstrap', () => { beforeEach(() => { vi.resetModules(); vi.clearAllMocks(); createServiceAppMock.mockResolvedValue(appMock); appMock.register.mockReset(); appMock.register.mockResolvedValue(undefined); }); it('creates app, registers JWT + routes, and starts on port 4009', async () => { await import('./server.js'); expect(createServiceAppMock).toHaveBeenCalledOnce(); const opts = createServiceAppMock.mock.calls[0][0]; expect(opts.name).toBe('cowork-service'); expect(opts.version).toBe('0.1.0'); expect(opts.readiness).toBe(true); // health + task + llm + audit + usage + notifications + extraction + marketplace + sessions + plugins + schedule + push + agent-runtime = 13 register calls + 1 JWT expect(registerOptionalJwtContextMock).toHaveBeenCalledOnce(); expect(appMock.register).toHaveBeenCalledTimes(13); expect(startServiceMock).toHaveBeenCalledWith(appMock, { port: 4009, host: '0.0.0.0' }); }); });