Files
web-cad/backend/tests/SqliteAdapter.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

384 lines
14 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.
/**
* SqliteAdapter Unit Tests init, CRUD for all entities, close
*/
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { SqliteAdapter } from '../src/database/SqliteAdapter.js';
let idCounter = 0;
function uniqueId(prefix: string): string {
idCounter++;
return `${prefix}-${Date.now()}-${idCounter}`;
}
describe('SqliteAdapter', () => {
let db: SqliteAdapter;
beforeAll(async () => {
db = new SqliteAdapter(':memory:');
await db.init();
});
afterAll(() => {
db.close();
});
// ─── Init & Close ───────────────────────────────────
describe('init() and close()', () => {
it('should initialize the database without errors', async () => {
const testDb = new SqliteAdapter(':memory:');
await testDb.init();
const users = testDb.listUsers();
expect(Array.isArray(users)).toBe(true);
testDb.close();
});
it('should seed a default user on init', async () => {
const defaultUser = db.getUser('user-default');
expect(defaultUser).not.toBeNull();
expect(defaultUser!.email).toBe('default@webcad.local');
expect(defaultUser!.role).toBe('admin');
});
});
// ─── Users CRUD ─────────────────────────────────────
describe('Users CRUD', () => {
it('should create and get a user', () => {
const uid = uniqueId('user');
const user = db.createUser({
id: uid,
email: `${uid}@example.com`,
password_hash: 'hash123',
name: 'CRUD User',
role: 'planer',
});
expect(user.id).toBe(uid);
expect(user.email).toBe(`${uid}@example.com`);
const fetched = db.getUser(user.id);
expect(fetched).not.toBeNull();
expect(fetched!.email).toBe(`${uid}@example.com`);
});
it('should get user by email', () => {
const uid = uniqueId('user');
db.createUser({ id: uid, email: `${uid}@example.com`, password_hash: 'hash', name: 'Email User', role: 'planer' });
const user = db.getUserByEmail(`${uid}@example.com`);
expect(user).not.toBeNull();
expect(user!.name).toBe('Email User');
});
it('should return null for non-existent user', () => {
expect(db.getUser('non-existent-id')).toBeNull();
expect(db.getUserByEmail('nobody@nowhere.com')).toBeNull();
});
it('should update a user', () => {
const uid = uniqueId('user');
db.createUser({ id: uid, email: `${uid}@example.com`, password_hash: 'hash', name: 'Original Name', role: 'planer' });
const updated = db.updateUser(uid, { name: 'Updated Name', role: 'admin' });
expect(updated).not.toBeNull();
expect(updated!.name).toBe('Updated Name');
expect(updated!.role).toBe('admin');
});
it('should list users', () => {
const users = db.listUsers();
expect(users.length).toBeGreaterThanOrEqual(2);
});
it('should delete a user', () => {
const uid = uniqueId('user');
db.createUser({ id: uid, email: `${uid}@example.com`, password_hash: 'hash', name: 'Delete Me', role: 'planer' });
const ok = db.deleteUser(uid);
expect(ok).toBe(true);
expect(db.getUser(uid)).toBeNull();
});
it('should return false when deleting non-existent user', () => {
expect(db.deleteUser('non-existent-id')).toBe(false);
});
});
// ─── Projects CRUD ──────────────────────────────────
describe('Projects CRUD', () => {
it('should create and get a project', () => {
const pid = uniqueId('proj');
const project = db.createProject({ id: pid, name: 'Test Project', description: 'Test desc' });
expect(project.id).toBe(pid);
expect(project.name).toBe('Test Project');
const fetched = db.getProject(pid);
expect(fetched).not.toBeNull();
expect(fetched!.name).toBe('Test Project');
});
it('should return null for non-existent project', () => {
expect(db.getProject('non-existent-id')).toBeNull();
});
it('should update a project', () => {
const pid = uniqueId('proj');
db.createProject({ id: pid, name: 'Update Project' });
const updated = db.updateProject(pid, { name: 'Updated Project', description: 'New desc' });
expect(updated).not.toBeNull();
expect(updated!.name).toBe('Updated Project');
expect(updated!.description).toBe('New desc');
});
it('should list projects', () => {
const projects = db.listProjects();
expect(projects.length).toBeGreaterThanOrEqual(1);
});
it('should delete a project', () => {
const pid = uniqueId('proj');
db.createProject({ id: pid, name: 'Delete Project' });
const ok = db.deleteProject(pid);
expect(ok).toBe(true);
expect(db.getProject(pid)).toBeNull();
});
it('should cascade delete drawings when project is deleted', () => {
const pid = uniqueId('proj');
const did = uniqueId('draw');
db.createProject({ id: pid, name: 'Cascade Project' });
db.createDrawing({ id: did, project_id: pid, name: 'Cascade Drawing' });
db.deleteProject(pid);
expect(db.getDrawing(did)).toBeNull();
});
});
// ─── Drawings CRUD ──────────────────────────────────
describe('Drawings CRUD', () => {
let projectId: string;
it('should create and get a drawing', () => {
projectId = uniqueId('proj');
const did = uniqueId('draw');
db.createProject({ id: projectId, name: 'Drawing Project' });
const drawing = db.createDrawing({ id: did, project_id: projectId, name: 'Floor 1' });
expect(drawing.id).toBe(did);
expect(drawing.name).toBe('Floor 1');
expect(drawing.project_id).toBe(projectId);
const fetched = db.getDrawing(did);
expect(fetched).not.toBeNull();
expect(fetched!.name).toBe('Floor 1');
});
it('should list drawings by project', () => {
const did1 = uniqueId('draw');
const did2 = uniqueId('draw');
db.createDrawing({ id: did1, project_id: projectId, name: 'Drawing A' });
db.createDrawing({ id: did2, project_id: projectId, name: 'Drawing B' });
const drawings = db.listDrawings(projectId);
expect(drawings.length).toBeGreaterThanOrEqual(3);
});
it('should update a drawing', () => {
const did = uniqueId('draw');
db.createDrawing({ id: did, project_id: projectId, name: 'Update Me' });
const updated = db.updateDrawing(did, { name: 'Updated Drawing', data_json: '{"x":1}' });
expect(updated).not.toBeNull();
expect(updated!.name).toBe('Updated Drawing');
expect(updated!.data_json).toBe('{"x":1}');
});
it('should delete a drawing', () => {
const did = uniqueId('draw');
db.createDrawing({ id: did, project_id: projectId, name: 'Delete Me' });
const ok = db.deleteDrawing(did);
expect(ok).toBe(true);
expect(db.getDrawing(did)).toBeNull();
});
it('should cascade delete layers when drawing is deleted', () => {
const did = uniqueId('draw');
const lid = uniqueId('layer');
db.createDrawing({ id: did, project_id: projectId, name: 'Cascade Drawing' });
db.createLayer({ id: lid, drawing_id: did, name: 'Cascade Layer' });
db.deleteDrawing(did);
const layers = db.listLayers(did);
expect(layers.find((l) => l.id === lid)).toBeUndefined();
});
});
// ─── Layers CRUD ────────────────────────────────────
describe('Layers CRUD', () => {
let drawingId: string;
it('should create and get a layer', () => {
const pid = uniqueId('proj');
drawingId = uniqueId('draw');
const lid = uniqueId('layer');
db.createProject({ id: pid, name: 'Layer Project' });
db.createDrawing({ id: drawingId, project_id: pid, name: 'Layer Drawing' });
const layer = db.createLayer({ id: lid, drawing_id: drawingId, name: 'Layer 1', color: '#ff0000' });
expect(layer.id).toBe(lid);
expect(layer.name).toBe('Layer 1');
expect(layer.color).toBe('#ff0000');
expect(layer.visible).toBe(1);
expect(layer.locked).toBe(0);
});
it('should list layers by drawing', () => {
const lid2 = uniqueId('layer');
db.createLayer({ id: lid2, drawing_id: drawingId, name: 'Layer 2' });
const layers = db.listLayers(drawingId);
expect(layers.length).toBeGreaterThanOrEqual(2);
});
it('should update a layer', () => {
const lid = uniqueId('layer');
db.createLayer({ id: lid, drawing_id: drawingId, name: 'Update Layer' });
const updated = db.updateLayer(lid, { name: 'Updated Layer', visible: 0, locked: 1 });
expect(updated).not.toBeNull();
expect(updated!.name).toBe('Updated Layer');
expect(updated!.visible).toBe(0);
expect(updated!.locked).toBe(1);
});
it('should delete a layer', () => {
const lid = uniqueId('layer');
db.createLayer({ id: lid, drawing_id: drawingId, name: 'Delete Layer' });
const ok = db.deleteLayer(lid);
expect(ok).toBe(true);
const layers = db.listLayers(drawingId);
expect(layers.find((l) => l.id === lid)).toBeUndefined();
});
});
// ─── Elements CRUD ──────────────────────────────────
describe('Elements CRUD', () => {
let drawingId: string;
let layerId: string;
it('should create and get an element', () => {
const pid = uniqueId('proj');
drawingId = uniqueId('draw');
layerId = uniqueId('layer');
const eid = uniqueId('elem');
db.createProject({ id: pid, name: 'Element Project' });
db.createDrawing({ id: drawingId, project_id: pid, name: 'Element Drawing' });
db.createLayer({ id: layerId, drawing_id: drawingId, name: 'Element Layer' });
const element = db.createElement({
id: eid,
drawing_id: drawingId,
layer_id: layerId,
type: 'rect',
x: 10,
y: 20,
width: 100,
height: 50,
});
expect(element.id).toBe(eid);
expect(element.type).toBe('rect');
expect(element.x).toBe(10);
expect(element.y).toBe(20);
});
it('should list elements by drawing', () => {
const eid2 = uniqueId('elem');
db.createElement({ id: eid2, drawing_id: drawingId, layer_id: layerId, type: 'circle' });
const elements = db.listElements(drawingId);
expect(elements.length).toBeGreaterThanOrEqual(2);
});
it('should update an element', () => {
const eid = uniqueId('elem');
db.createElement({ id: eid, drawing_id: drawingId, layer_id: layerId, type: 'line' });
const updated = db.updateElement(eid, { x: 500, y: 600, width: 200 });
expect(updated).not.toBeNull();
expect(updated!.x).toBe(500);
expect(updated!.y).toBe(600);
expect(updated!.width).toBe(200);
});
it('should delete an element', () => {
const eid = uniqueId('elem');
db.createElement({ id: eid, drawing_id: drawingId, layer_id: layerId, type: 'text' });
const ok = db.deleteElement(eid);
expect(ok).toBe(true);
const elements = db.listElements(drawingId);
expect(elements.find((e) => e.id === eid)).toBeUndefined();
});
});
// ─── Blocks CRUD ────────────────────────────────────
describe('Blocks CRUD', () => {
let drawingId: string;
it('should create and get a block', () => {
const pid = uniqueId('proj');
drawingId = uniqueId('draw');
const bid = uniqueId('block');
db.createProject({ id: pid, name: 'Block Project' });
db.createDrawing({ id: drawingId, project_id: pid, name: 'Block Drawing' });
const block = db.createBlock({ id: bid, drawing_id: drawingId, name: 'Table Block', category: 'Mobiliar' });
expect(block.id).toBe(bid);
expect(block.name).toBe('Table Block');
expect(block.category).toBe('Mobiliar');
expect(block.elements_json).toBe('[]');
});
it('should list blocks by drawing', () => {
const bid2 = uniqueId('block');
db.createBlock({ id: bid2, drawing_id: drawingId, name: 'Chair Block' });
const blocks = db.listBlocks(drawingId);
expect(blocks.length).toBeGreaterThanOrEqual(2);
});
it('should update a block', () => {
const bid = uniqueId('block');
db.createBlock({ id: bid, drawing_id: drawingId, name: 'Update Block' });
const updated = db.updateBlock(bid, { name: 'Updated Block', category: 'Bühne' });
expect(updated).not.toBeNull();
expect(updated!.name).toBe('Updated Block');
expect(updated!.category).toBe('Bühne');
});
it('should delete a block', () => {
const bid = uniqueId('block');
db.createBlock({ id: bid, drawing_id: drawingId, name: 'Delete Block' });
const ok = db.deleteBlock(bid);
expect(ok).toBe(true);
const blocks = db.listBlocks(drawingId);
expect(blocks.find((b) => b.id === bid)).toBeUndefined();
});
});
// ─── Settings CRUD ──────────────────────────────────
describe('Settings CRUD', () => {
it('should set and get a setting', () => {
db.setSetting('test-key', 'test-value');
const setting = db.getSetting('test-key');
expect(setting).not.toBeNull();
expect(setting!.key).toBe('test-key');
expect(setting!.value).toBe('test-value');
expect(setting!.updated_at).toBeDefined();
});
it('should return null for non-existent setting', () => {
expect(db.getSetting('non-existent-key')).toBeNull();
});
it('should upsert (update existing setting)', () => {
db.setSetting('upsert-key', 'initial');
db.setSetting('upsert-key', 'updated');
const setting = db.getSetting('upsert-key');
expect(setting).not.toBeNull();
expect(setting!.value).toBe('updated');
});
});
});