/** * Drawings API Tests – CRUD (List / Get / Create / Update / Delete) */ 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('Drawings API', () => { let app: FastifyInstance; let db: SqliteAdapter; let projectId: string; let createdDrawingId: string; beforeAll(async () => { db = new SqliteAdapter(':memory:'); await db.init(); app = await createServer({ db, port: 0 }); await app.ready(); // Create a project first (drawings belong to projects) const projectRes = await app.inject({ method: 'POST', url: '/api/projects', payload: { name: 'Drawings Test Project' }, }); projectId = JSON.parse(projectRes.body).id; }); afterAll(async () => { await app.close(); db.close(); }); // ─── Create ───────────────────────────────────────── describe('POST /api/projects/:projectId/drawings', () => { it('should create a drawing with 201', async () => { const response = await app.inject({ method: 'POST', url: `/api/projects/${projectId}/drawings`, payload: { name: 'Ground Floor' }, }); expect(response.statusCode).toBe(201); const body = JSON.parse(response.body); expect(body.id).toBeDefined(); expect(body.name).toBe('Ground Floor'); expect(body.project_id).toBe(projectId); createdDrawingId = body.id; }); it('should create a drawing with default name', async () => { const response = await app.inject({ method: 'POST', url: `/api/projects/${projectId}/drawings`, payload: {}, }); expect(response.statusCode).toBe(201); const body = JSON.parse(response.body); expect(body.name).toBe('Unbenannt'); expect(body.project_id).toBe(projectId); }); }); // ─── List ─────────────────────────────────────────── describe('GET /api/projects/:projectId/drawings', () => { it('should list drawings for a project', async () => { const response = await app.inject({ method: 'GET', url: `/api/projects/${projectId}/drawings`, }); expect(response.statusCode).toBe(200); const body = JSON.parse(response.body); expect(Array.isArray(body)).toBe(true); expect(body.length).toBeGreaterThanOrEqual(2); }); it('should return empty array for project with no drawings', async () => { // Create a new empty project const projRes = await app.inject({ method: 'POST', url: '/api/projects', payload: { name: 'Empty Project' }, }); const emptyProjId = JSON.parse(projRes.body).id; const response = await app.inject({ method: 'GET', url: `/api/projects/${emptyProjId}/drawings`, }); expect(response.statusCode).toBe(200); const body = JSON.parse(response.body); expect(Array.isArray(body)).toBe(true); expect(body.length).toBe(0); }); }); // ─── Get ──────────────────────────────────────────── describe('GET /api/drawings/:id', () => { it('should get a single drawing', async () => { const response = await app.inject({ method: 'GET', url: `/api/drawings/${createdDrawingId}`, }); expect(response.statusCode).toBe(200); const body = JSON.parse(response.body); expect(body.id).toBe(createdDrawingId); expect(body.name).toBe('Ground Floor'); }); it('should return 404 for non-existent drawing', async () => { const response = await app.inject({ method: 'GET', url: '/api/drawings/non-existent-id', }); expect(response.statusCode).toBe(404); }); }); // ─── Update ───────────────────────────────────────── describe('PATCH /api/drawings/:id', () => { it('should update drawing name', async () => { const response = await app.inject({ method: 'PATCH', url: `/api/drawings/${createdDrawingId}`, payload: { name: 'First Floor' }, }); expect(response.statusCode).toBe(200); const body = JSON.parse(response.body); expect(body.name).toBe('First Floor'); }); it('should update drawing data_json', async () => { const response = await app.inject({ method: 'PATCH', url: `/api/drawings/${createdDrawingId}`, payload: { data_json: '{"layers":[]}' }, }); expect(response.statusCode).toBe(200); const body = JSON.parse(response.body); expect(body.data_json).toBe('{"layers":[]}'); }); it('should return 404 for non-existent drawing update', async () => { const response = await app.inject({ method: 'PATCH', url: '/api/drawings/non-existent-id', payload: { name: 'New Name' }, }); expect(response.statusCode).toBe(404); }); }); // ─── Delete ───────────────────────────────────────── describe('DELETE /api/drawings/:id', () => { it('should delete a drawing', async () => { // Create a drawing to delete const createRes = await app.inject({ method: 'POST', url: `/api/projects/${projectId}/drawings`, payload: { name: 'To Be Deleted' }, }); const drawingId = JSON.parse(createRes.body).id; const response = await app.inject({ method: 'DELETE', url: `/api/drawings/${drawingId}`, }); expect(response.statusCode).toBe(204); // Verify it's gone const getRes = await app.inject({ method: 'GET', url: `/api/drawings/${drawingId}`, }); expect(getRes.statusCode).toBe(404); }); it('should return 404 for non-existent drawing delete', async () => { const response = await app.inject({ method: 'DELETE', url: '/api/drawings/non-existent-id', }); expect(response.statusCode).toBe(404); }); }); });