Files
wursor/api/__tests__/routes/chat.test.ts
T
SinachPat 060b181e71
Mirror to GitHub / mirror (push) Canceled after 0s
feat: wire chat to the agent loop (POST /chat)
- api: /chat route runs runAgent (session-required, 503 when unconfigured)
- api: index.ts builds OpenRouterLlmClient + WpRestExecutor from env; loads .env
- web: useChat calls /chat with mock fallback; proxy /chat+/sites+/health
- .env.example: DATABASE_URL empty by default (in-memory dev)
- 111 unit tests green; smoke-tested signup+chat
2026-08-17 17:19:33 +01:00

78 lines
2.3 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import type { FastifyInstance } from 'fastify';
import { buildApp } from '../../src/app.ts';
import type { LlmClient, LlmResponse } from '../../src/agents/llm-client.ts';
import type { ToolExecutor } from '../../src/agents/tool-executor.ts';
class FakeLlm implements LlmClient {
async complete(): Promise<LlmResponse> {
return { choices: [{ message: { role: 'assistant', content: 'Done', tool_calls: undefined } }] };
}
}
class FakeExecutor implements ToolExecutor {
async execute() {
return { result: 'ok' };
}
}
async function signup(app: FastifyInstance): Promise<string> {
const res = await app.inject({
method: 'POST',
url: '/auth/signup',
payload: { email: `a-${Date.now()}@example.com`, password: 'password123' },
});
return res.json().sessionToken as string;
}
describe('POST /chat', () => {
it('requires a session', async () => {
const app = await buildApp({ llmClient: new FakeLlm(), toolExecutor: new FakeExecutor() });
const res = await app.inject({ method: 'POST', url: '/chat', payload: { message: 'hi' } });
expect(res.statusCode).toBe(401);
});
it('runs the agent and returns the reply', async () => {
const app = await buildApp({ llmClient: new FakeLlm(), toolExecutor: new FakeExecutor() });
const token = await signup(app);
const res = await app.inject({
method: 'POST',
url: '/chat',
headers: { authorization: `Bearer ${token}` },
payload: { message: 'Change the heading' },
});
expect(res.statusCode).toBe(200);
expect(res.json().reply).toBe('Done');
});
it('returns 503 when the agent is not configured', async () => {
const app = await buildApp();
const token = await signup(app);
const res = await app.inject({
method: 'POST',
url: '/chat',
headers: { authorization: `Bearer ${token}` },
payload: { message: 'hi' },
});
expect(res.statusCode).toBe(503);
});
it('returns 400 for an empty message', async () => {
const app = await buildApp({ llmClient: new FakeLlm(), toolExecutor: new FakeExecutor() });
const token = await signup(app);
const res = await app.inject({
method: 'POST',
url: '/chat',
headers: { authorization: `Bearer ${token}` },
payload: { message: ' ' },
});
expect(res.statusCode).toBe(400);
});
});