import express from 'express'; import type { AddressInfo } from 'node:net'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { createControlRouter } from '../src/web/routes/control.js'; const servers: Array> = []; afterEach(async () => { await Promise.all(servers.splice(0).map( (server) => new Promise((resolve) => server.close(() => resolve())), )); }); describe('bot control account authentication gate', () => { it('refuses to start the bot until full account authentication', async () => { const setBotRunning = vi.fn(); const app = express(); app.use(createControlRouter({ services: { accountAuth: { isFullyAuthenticated: () => false, ensureFullyAuthenticated: vi.fn(async () => false), }, }, setBotRunning, activity: { push: vi.fn() }, logger: { warn: vi.fn(), info: vi.fn() }, } as never)); const server = app.listen(0); servers.push(server); await new Promise((resolve) => server.once('listening', resolve)); const { port } = server.address() as AddressInfo; const response = await fetch(`http://127.0.0.1:${port}/start`, { method: 'POST' }); expect(response.status).toBe(409); expect(await response.json()).toMatchObject({ success: false, authenticated: false }); expect(setBotRunning).not.toHaveBeenCalled(); }); it('renews an expired authentication lease before starting the bot', async () => { let running = false; const ensureFullyAuthenticated = vi.fn(async () => true); const app = express(); app.use(createControlRouter({ config: { browser: { dryRun: false } }, services: { accountAuth: { isFullyAuthenticated: () => false, ensureFullyAuthenticated, }, }, getBotRunning: () => running, setBotRunning: (next: boolean) => { running = next; }, activity: { push: vi.fn() }, logger: { warn: vi.fn(), info: vi.fn() }, broadcaster: { dashboardEvents: { bot: vi.fn() } }, } as never)); const server = app.listen(0); servers.push(server); await new Promise((resolve) => server.once('listening', resolve)); const { port } = server.address() as AddressInfo; const response = await fetch(`http://127.0.0.1:${port}/start`, { method: 'POST' }); expect(response.status).toBe(200); expect(await response.json()).toMatchObject({ success: true, running: true }); expect(ensureFullyAuthenticated).toHaveBeenCalledOnce(); expect(running).toBe(true); }); it('renews a running account runtime when the legacy auth context is unavailable', async () => { let running = false; const ensureFullyAuthenticated = vi.fn(async () => true); const runtime = { resources: { accountAuth: { isFullyAuthenticated: () => false, ensureFullyAuthenticated }, }, }; const app = express(); app.use(createControlRouter({ config: { browser: { dryRun: false } }, services: { accountRuntimes: { list: () => [{ accountId: '@t2_account:reddit.com', state: 'running' }], get: () => runtime, }, }, getBotRunning: () => running, setBotRunning: (next: boolean) => { running = next; }, activity: { push: vi.fn() }, logger: { warn: vi.fn(), info: vi.fn() }, broadcaster: { dashboardEvents: { bot: vi.fn() } }, } as never)); const server = app.listen(0); servers.push(server); await new Promise((resolve) => server.once('listening', resolve)); const { port } = server.address() as AddressInfo; const response = await fetch(`http://127.0.0.1:${port}/start`, { method: 'POST' }); expect(response.status).toBe(200); expect(ensureFullyAuthenticated).toHaveBeenCalledOnce(); expect(running).toBe(true); }); });