docs: roadmap log CAD-14 phase 3 + proof test selection workflow

This commit is contained in:
Agent Zero
2026-09-16 22:06:23 +02:00
parent 1d129042d4
commit cd5d4326db
2 changed files with 84 additions and 11 deletions
@@ -8,24 +8,55 @@
import { test, expect } from '@playwright/test';
const BASE_URL = process.env.FRONTEND_URL || 'https://web-cad-neu.server.media-on.de';
const API_URL = process.env.API_URL || 'https://web-cad-neu.server.media-on.de';
async function api(method: string, endpoint: string, body?: unknown, token?: string) {
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
if (token) headers.Authorization = `Bearer ${token}`;
const res = await fetch(`${API_URL}${endpoint}`, { method, headers, body: body ? JSON.stringify(body) : undefined });
const text = await res.text();
return { status: res.status, body: text ? JSON.parse(text) : null };
}
interface VerifyWindow {
__v2Debug?: { info: () => { cachedElements: number; ready: boolean } | null };
}
test('zeichnen erzeugt GENAU EIN Element an der Klick-Position', async ({ page }) => {
test.setTimeout(60000);
await page.goto(BASE_URL);
await page.fill('input[type=email]', 'admin@media-on.de');
await page.fill('input[type=password]', 'WebCAD2026!');
await page.click('button[type=submit]');
await page.waitForTimeout(3000);
// Neues leeres Projekt anlegen (damit der Count deterministisch ist)
const newBtn = page.locator('button:has-text("Neu"), [title*="Neues Projekt"]').first();
const cards = await page.$$('.dashboard-project-card, [class*=project-card]');
if (cards.length === 0) { await newBtn.click(); } // Dashboard-Variante
// Falls Dashboard: einfach das erste Projekt oeffnen und Delta messen
if (cards.length > 0) { await cards[0].click(); }
// CAD-14: Frisches Projekt + Zeichnung -> Basis 0, Zuordnung eindeutig
const token = await page.evaluate(() => localStorage.getItem('auth_token'));
expect(token).toBeTruthy();
const uniq = Date.now();
const projRes = await fetch(`${BASE_URL}/api/projects`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
body: JSON.stringify({ name: `CAD14-${uniq}`, description: 'proof' }),
});
const proj = await projRes.json();
expect(proj?.id).toBeTruthy();
const drawingRes = await fetch(`${BASE_URL}/api/projects/${proj.id}/drawings`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
body: JSON.stringify({ name: `CAD14-Proof-${uniq}` }),
});
const drawing = await drawingRes.json();
expect(drawing?.id).toBeTruthy();
const drawingId: string = drawing.id;
const beforeDbCount = 0;
// Karte des frischen Projekts oeffnen (eindeutig per Name) — Dashboard
// laedt die Liste beim Mount, daher Reload nach API-Anlage.
await page.reload();
await page.waitForTimeout(2500);
const card = page.locator(`.dashboard-project-card, [class*=project-card]`).filter({ hasText: `CAD14-${uniq}` }).first();
await card.click();
await page.waitForTimeout(2500);
const verify = () => page.evaluate(() => {
@@ -37,6 +68,8 @@ test('zeichnen erzeugt GENAU EIN Element an der Klick-Position', async ({ page }
const beforeCount = before?.cachedElements ?? -1;
expect(beforeCount, 'Pixi muss ready sein').toBeGreaterThanOrEqual(0);
// DB-Basis ist 0 (frische Zeichnung)
// Linie-Werkzeug aus der SIDEBAR (der richtige Ort)
await page.locator('[data-tool="line"]').first().click();
await page.waitForTimeout(300);
@@ -47,14 +80,53 @@ test('zeichnen erzeugt GENAU EIN Element an der Klick-Position', async ({ page }
if (!box) throw new Error('Kein Canvas gefunden');
const cx = box.x + box.width / 2;
const cy = box.y + box.height / 2;
await page.mouse.click(cx, cy);
await page.waitForTimeout(200);
await page.mouse.click(cx + 120, cy + 60);
await page.waitForTimeout(600);
// CAD-14: line ist ein DRAG-Werkzeug (down -> move -> up committet).
const startX = cx - 60;
const startY = cy - 30;
await page.mouse.move(startX, startY);
await page.mouse.down();
await page.mouse.move(startX + 120, startY + 60, { steps: 8 });
await page.mouse.up();
await page.waitForTimeout(800);
const after = await verify();
const afterCount = after?.cachedElements ?? -1;
// ABNAHME: genau +1 Element (jetzt faehlt der Test, weil 2 entstehen)
// ABNAHME 1: genau +1 Element im Renderer
expect(afterCount - beforeCount, `Erwartet genau 1 neues Element, got ${afterCount - beforeCount}`).toBe(1);
// ABNAHME 2: das Element MUSS in der DB persistiert sein (Autosave/Save-Kette)
// drawingId aus Scope (frisch angelegt)
// Autosave braucht bis zu 30s — poll bis zu 40s
// CAD-14: ALLE Drawings des Proof-Projekts pruefen (die App koennte in
// eine auto-angelegte Zeichnung schreiben statt in meine).
let dbCount = -1;
for (let i = 0; i < 8; i++) {
await page.waitForTimeout(5000);
const drs = await (await fetch(`${BASE_URL}/api/projects/${proj.id}/drawings`, { headers: { Authorization: `Bearer ${token}` } })).json();
let total = 0;
for (const d of drs) {
const els = await (await fetch(`${BASE_URL}/api/drawings/${d.id}/elements`, { headers: { Authorization: `Bearer ${token}` } })).json();
total += els.length;
if (els.length > 0) console.log(`DRAWING ${d.id}: ${els.length} Elemente`);
}
dbCount = total;
if (total >= 1) { console.log('GEFUNDEN in drawings:', drs.map((d: any) => d.id)); break; }
}
expect(dbCount, `Genau 1 Element muss in der DB landen (vor ${beforeDbCount}, nach ${dbCount})`).toBe(1);
// ABNAHME 3: V2-Select-Tool klickt auf die Linienmitte — Auswahl muss
// auf dem V2-Dokument landen (Karte: __v2GetSelection).
await page.locator('[data-tool="select"]').first().click();
await page.waitForTimeout(300);
const midX = startX + 60;
const midY = startY + 30;
await page.mouse.click(midX, midY);
await page.waitForTimeout(500);
const sel = await page.evaluate(() => {
const w = window as unknown as { __v2GetSelection?: () => { ids: string[] } };
return w.__v2GetSelection?.() ?? null;
});
expect(sel, 'Selection-Bridge muss erreichbar sein').toBeTruthy();
expect(sel!.ids.length, `Genau 1 Element muss ausgewaehlt sein, got ${sel!.ids.length}`).toBe(1);
});