Files
web-cad/backend/tests/ai.test.ts
T
Leopoldadmin 1bcfaffdd4 fix: replace hardcoded localhost:3001 with relative API URL + add canvas mock and integration test
- Fix frontend Network error: API_BASE now defaults to empty string (same-origin)
- Fix 3 files: api.ts, AuthContext.tsx, Dashboard.tsx
- Add Canvas 2D context mock in tests/setup.ts for jsdom
- Fix -0 vs +0 in ZoomPanController.getViewport()
- Add IntegrationWorkflow.test.ts (35 tests, full CAD workflow)
2026-06-26 17:48:24 +02:00

141 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* AI API Tests Auth guard, validation, and service availability checks
* Does NOT test actual OpenRouter API calls.
*/
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import type { FastifyInstance } from 'fastify';
import { SqliteAdapter } from '../src/database/SqliteAdapter.js';
import { createServer } from '../src/server.js';
describe('AI API', () => {
let app: FastifyInstance;
let db: SqliteAdapter;
let authToken: string;
beforeAll(async () => {
db = new SqliteAdapter(':memory:');
await db.init();
app = await createServer({ db, port: 0 });
await app.ready();
// Register a user to get an auth token
const registerRes = await app.inject({
method: 'POST',
url: '/api/auth/register',
payload: {
email: 'ai-test@example.com',
password: 'TestPass123!',
name: 'AI Test User',
role: 'planer',
},
});
const body = JSON.parse(registerRes.body);
authToken = body.session.token;
});
afterAll(async () => {
await app.close();
db.close();
});
// ─── Auth Guard ─────────────────────────────────────
describe('POST /api/ai/chat Authentication', () => {
it('should return 401 without authorization header', async () => {
const response = await app.inject({
method: 'POST',
url: '/api/ai/chat',
payload: { messages: [{ role: 'user', content: 'hello' }] },
});
expect(response.statusCode).toBe(401);
const body = JSON.parse(response.body);
expect(body.error).toContain('Authentication required');
});
it('should return 401 with invalid token', async () => {
const response = await app.inject({
method: 'POST',
url: '/api/ai/chat',
headers: { authorization: 'Bearer invalid-token-xxx' },
payload: { messages: [{ role: 'user', content: 'hello' }] },
});
expect(response.statusCode).toBe(401);
const body = JSON.parse(response.body);
expect(body.error).toContain('Invalid or expired session');
});
it('should return 401 with malformed authorization header', async () => {
const response = await app.inject({
method: 'POST',
url: '/api/ai/chat',
headers: { authorization: 'NotBearer sometoken' },
payload: { messages: [{ role: 'user', content: 'hello' }] },
});
expect(response.statusCode).toBe(401);
});
});
// ─── Validation ─────────────────────────────────────
describe('POST /api/ai/chat Validation', () => {
it('should return 400 when messages array is missing', async () => {
const response = await app.inject({
method: 'POST',
url: '/api/ai/chat',
headers: { authorization: `Bearer ${authToken}` },
payload: {},
});
expect(response.statusCode).toBe(400);
const body = JSON.parse(response.body);
expect(body.error).toContain('Messages array is required');
});
it('should return 400 when messages array is empty', async () => {
const response = await app.inject({
method: 'POST',
url: '/api/ai/chat',
headers: { authorization: `Bearer ${authToken}` },
payload: { messages: [] },
});
expect(response.statusCode).toBe(400);
const body = JSON.parse(response.body);
expect(body.error).toContain('Messages array is required');
});
it('should return 400 when messages is not an array', async () => {
const response = await app.inject({
method: 'POST',
url: '/api/ai/chat',
headers: { authorization: `Bearer ${authToken}` },
payload: { messages: 'not an array' },
});
expect(response.statusCode).toBe(400);
});
});
// ─── Service Availability ───────────────────────────
describe('POST /api/ai/chat Service availability', () => {
it('should return 503 when API_KEY_OPENROUTER is not set', async () => {
// Ensure env var is not set for this test
const originalValue = process.env.API_KEY_OPENROUTER;
delete process.env.API_KEY_OPENROUTER;
const response = await app.inject({
method: 'POST',
url: '/api/ai/chat',
headers: { authorization: `Bearer ${authToken}` },
payload: { messages: [{ role: 'user', content: 'hello' }] },
});
expect(response.statusCode).toBe(503);
const body = JSON.parse(response.body);
expect(body.error).toContain('AI service not configured');
// Restore original value if it existed
if (originalValue !== undefined) {
process.env.API_KEY_OPENROUTER = originalValue;
}
});
});
});