task(B4): cache background image (fixes BUG-4)

This commit is contained in:
Agent Zero
2026-08-26 20:51:43 +02:00
parent d8f29e42e3
commit d93ee5308c
2 changed files with 98 additions and 6 deletions
+72 -1
View File
@@ -3,10 +3,14 @@
* Diese Tests sind VOR dem jeweiligen Fix ROT (dokumentiertes Fehlverhalten)
* und müssen danach GRÜN sein.
*/
import { describe, it, expect } from 'vitest';
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { SeatingService } from '../src/services/seatingService';
import { trimElement, offsetElement } from '../src/tools/modification/geometry';
import type { CADElement } from '../src/types/cad.types';
import { RenderEngine } from '../src/canvas/RenderEngine';
import { ZoomPanController } from '../src/canvas/ZoomPanController';
import { SpatialIndex } from '../src/canvas/SpatialIndex';
import { LayerManager } from '../src/canvas/LayerManager';
// ── Helfer (Muster aus tests/geometry.test.ts) ─────────────
function makeLine(id: string, x1: number, y1: number, x2: number, y2: number): CADElement {
@@ -100,3 +104,70 @@ describe('BUG-3: offset respects click side', () => {
expect(offsetElement(circle, 10, 1).properties.radius).toBeCloseTo(60);
});
});
// ── BUG-4: Hintergrundbild wurde pro Frame neu geladen ──────
describe('BUG-4: background image cached', () => {
let imageCount: number;
let OriginalImage: typeof Image;
beforeEach(() => {
imageCount = 0;
OriginalImage = global.Image;
// Bild-Stub: zaehlt Konstruktur-Aufrufe; simuliert Browser-Cache-Bild
// (complete=true sofort verfuegbar, onload als Mikrotask wie async decode)
class FakeImage {
complete = true;
naturalWidth = 800;
width = 800;
height = 600;
onload: (() => void) | null = null;
private internalSrc = '';
get src(): string {
return this.internalSrc;
}
set src(value: string) {
this.internalSrc = value;
queueMicrotask(() => this.onload?.());
}
constructor() {
imageCount += 1;
}
}
(global as { Image: unknown }).Image = FakeImage as unknown as typeof Image;
});
afterEach(() => {
(global as { Image: unknown }).Image = OriginalImage;
});
function createEngine(): RenderEngine {
const canvas = document.createElement('canvas');
canvas.width = 800;
canvas.height = 600;
const zoomPan = new ZoomPanController(canvas);
const spatialIndex = new SpatialIndex();
const layerManager = new LayerManager();
return new RenderEngine(canvas, zoomPan, spatialIndex, layerManager);
}
it('lädt das Bild pro Quellwechsel nur EINMAL, weitere Frames nutzen den Cache', async () => {
const engine = createEngine();
const DATA_URL = 'data:image/png;base64,iVBORw0KGgo=';
engine.setOptions({ backgroundSrc: DATA_URL, backgroundOpacity: 0.5 });
// Frame 1: legt genau ein Image an und cachet es (complete=true)
engine.render();
expect(imageCount).toBe(1);
// Weitere Frames mit identischer src: dürfen KEIN neues Image erzeugen
engine.render();
engine.render();
engine.render();
expect(imageCount).toBe(1);
// Ausstehende Mikrotasks (simuliertes onload) abwarten, dann erneut prüfen:
await Promise.resolve();
engine.render();
expect(imageCount).toBe(1); // vorher (Bug): jedes render() erzeugte ein neues Image
});
});