feat(quick-260922-ge2): XFrame-Widget - Ausschnitt der Seite waehlen und einpassen, Zoom fuer die ganze Seite, Nur anzeigen
- Resolver: crop (x/y/w/h, geklemmt auf 1280er-Seite, x verschoben statt abgewiesen), zoom (50..150, groesste Stufe <= n), readOnly (nur echtes true) - xframe-crop.ts: reine Geometrie - computeCropLayout (contain + zentriert, scale 0 bis gemessen), applyCropDrag (Verschieben, vier Ecken, Gegenecke bleibt) - Kachel: Clip + verschobener, skalierter <iframe> bei fester Layoutbreite 1280, ResizeObserver am Koerper; Zoom-Zweig mit Prozentmassen; 100 % wie bisher; readOnly-Flaeche nur im Ansichtsmodus - Formular: Checkbox Ausschnitt (ein Aufruf mit crop + readOnly), Vorschau 1280 px breit mit derselben Sandbox und pointer-events none, Rahmen mit vier Griffen (Pointer-Events, Capture-Waechter fuer jsdom), Zahlenfelder, Zoom-Auswahl nur ohne Ausschnitt, Nur anzeigen, dauerhafter Hinweis - Rahmen als <fieldset> statt div role=group (Biome useSemanticElements, kein biome-ignore) - Test-Helfer stubResizeObserver, 13 neue Schluessel de/en, Ausschnitt auf der Umlaut-Allowlist; Web-Tests 604 -> 640 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
XFRAME_CROP_DEFAULT,
|
||||
XFRAME_PAGE_WIDTH,
|
||||
XFRAME_RELOAD_MAX,
|
||||
XFRAME_RELOAD_MIN,
|
||||
XFRAME_RELOAD_OPTIONS,
|
||||
XFRAME_SANDBOX,
|
||||
XFRAME_TITLE_MAX,
|
||||
XFRAME_ZOOM_OPTIONS,
|
||||
clampXframeCrop,
|
||||
isHttpsUrl,
|
||||
resolveXframeConfig,
|
||||
} from './xframe-config';
|
||||
@@ -19,7 +23,14 @@ import {
|
||||
*/
|
||||
describe('resolveXframeConfig (quick-260921-qd3)', () => {
|
||||
it('Test 1: leere Konfiguration -> keine Adresse, leerer Titel, nie neu laden', () => {
|
||||
expect(resolveXframeConfig({})).toEqual({ url: null, title: '', reloadSeconds: 0 });
|
||||
expect(resolveXframeConfig({})).toEqual({
|
||||
url: null,
|
||||
title: '',
|
||||
reloadSeconds: 0,
|
||||
crop: null,
|
||||
zoom: 100,
|
||||
readOnly: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('Test 2: https-Adresse bleibt (getrimmt)', () => {
|
||||
@@ -64,7 +75,101 @@ describe('resolveXframeConfig (quick-260921-qd3)', () => {
|
||||
it('Test 8: alle drei Felder zusammen', () => {
|
||||
expect(
|
||||
resolveXframeConfig({ url: 'https://a.de/', title: ' Board ', reloadSeconds: 1800 }),
|
||||
).toEqual({ url: 'https://a.de/', title: 'Board', reloadSeconds: 1800 });
|
||||
).toEqual({
|
||||
url: 'https://a.de/',
|
||||
title: 'Board',
|
||||
reloadSeconds: 1800,
|
||||
crop: null,
|
||||
zoom: 100,
|
||||
readOnly: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* quick-260922-ge2: Ausschnitt, Zoom, readOnly. Die Werte landen in
|
||||
* Inline-Styles (T-GE2-05) — der Resolver klemmt und weist nie ab: ein
|
||||
* manipulierter Wert ergibt hoechstens einen anderen Ausschnitt, nie
|
||||
* `scale(NaN)` oder einen 10⁹-px-Rahmen.
|
||||
*/
|
||||
describe('resolveXframeConfig — Ausschnitt, Zoom, readOnly (quick-260922-ge2)', () => {
|
||||
it('Test 13: crop fehlt / null / String / unvollstaendig / Nicht-Zahl -> null', () => {
|
||||
expect(resolveXframeConfig({}).crop).toBeNull();
|
||||
expect(resolveXframeConfig({ crop: null }).crop).toBeNull();
|
||||
expect(resolveXframeConfig({ crop: 'x' }).crop).toBeNull();
|
||||
expect(resolveXframeConfig({ crop: { x: 1 } }).crop).toBeNull();
|
||||
expect(resolveXframeConfig({ crop: { x: 'a', y: 0, w: 500, h: 300 } }).crop).toBeNull();
|
||||
expect(resolveXframeConfig({ crop: { x: Number.NaN, y: 0, w: 500, h: 300 } }).crop).toBeNull();
|
||||
});
|
||||
|
||||
it('Test 14: gueltiger Ausschnitt bleibt unveraendert; x wird verschoben, wenn x + w > 1280 (nie abgewiesen)', () => {
|
||||
expect(resolveXframeConfig({ crop: { x: 0, y: 0, w: 1280, h: 720 } }).crop).toEqual({ x: 0, y: 0, w: 1280, h: 720 });
|
||||
expect(resolveXframeConfig({ crop: { x: 500, y: 0, w: 1000, h: 300 } }).crop).toEqual({ x: 280, y: 0, w: 1000, h: 300 });
|
||||
});
|
||||
|
||||
it('Test 15: Breite und Hoehe geklemmt — w 50 -> 100, w 5000 -> 1280 (x -> 0), h 10 -> 60, h 9999 -> 4000', () => {
|
||||
expect(resolveXframeConfig({ crop: { x: 0, y: 0, w: 50, h: 300 } }).crop).toEqual({ x: 0, y: 0, w: 100, h: 300 });
|
||||
expect(resolveXframeConfig({ crop: { x: 300, y: 0, w: 5000, h: 300 } }).crop).toEqual({ x: 0, y: 0, w: 1280, h: 300 });
|
||||
expect(resolveXframeConfig({ crop: { x: 0, y: 0, w: 500, h: 10 } }).crop).toEqual({ x: 0, y: 0, w: 500, h: 60 });
|
||||
expect(resolveXframeConfig({ crop: { x: 0, y: 0, w: 500, h: 9999 } }).crop).toEqual({ x: 0, y: 0, w: 500, h: 4000 });
|
||||
});
|
||||
|
||||
it('Test 16: negative Position -> 0; Nachkommastellen gerundet', () => {
|
||||
expect(resolveXframeConfig({ crop: { x: -5, y: -1, w: 500, h: 300 } }).crop).toEqual({ x: 0, y: 0, w: 500, h: 300 });
|
||||
expect(resolveXframeConfig({ crop: { x: 10.6, y: 2.4, w: 500.4, h: 300.5 } }).crop).toEqual({
|
||||
x: 11,
|
||||
y: 2,
|
||||
w: 500,
|
||||
h: 301,
|
||||
});
|
||||
});
|
||||
|
||||
it('Test 17: zoom fehlt / "abc" / NaN -> 100; 70 -> 60, 200 -> 150, 0 -> 50, 10 -> 50, 125 -> 125', () => {
|
||||
expect(resolveXframeConfig({}).zoom).toBe(100);
|
||||
expect(resolveXframeConfig({ zoom: 'abc' }).zoom).toBe(100);
|
||||
expect(resolveXframeConfig({ zoom: Number.NaN }).zoom).toBe(100);
|
||||
expect(resolveXframeConfig({ zoom: 70 }).zoom).toBe(60);
|
||||
expect(resolveXframeConfig({ zoom: 200 }).zoom).toBe(150);
|
||||
expect(resolveXframeConfig({ zoom: 0 }).zoom).toBe(50);
|
||||
expect(resolveXframeConfig({ zoom: 10 }).zoom).toBe(50);
|
||||
expect(resolveXframeConfig({ zoom: 125 }).zoom).toBe(125);
|
||||
});
|
||||
|
||||
it('Test 18: readOnly nur bei echtem true; "true", 1, fehlt -> false', () => {
|
||||
expect(resolveXframeConfig({ readOnly: true }).readOnly).toBe(true);
|
||||
expect(resolveXframeConfig({ readOnly: 'true' }).readOnly).toBe(false);
|
||||
expect(resolveXframeConfig({ readOnly: 1 }).readOnly).toBe(false);
|
||||
expect(resolveXframeConfig({}).readOnly).toBe(false);
|
||||
});
|
||||
|
||||
it('Test 19: Konstanten — Zoom-Stufen, Seitenbreite 1280, Vorgabe-Ausschnitt 0/0/1280/720', () => {
|
||||
expect(XFRAME_ZOOM_OPTIONS).toEqual([50, 60, 75, 90, 100, 125, 150]);
|
||||
expect(XFRAME_PAGE_WIDTH).toBe(1280);
|
||||
expect(XFRAME_CROP_DEFAULT).toEqual({ x: 0, y: 0, w: 1280, h: 720 });
|
||||
});
|
||||
|
||||
it('Test 20: alle sechs Felder zusammen', () => {
|
||||
expect(
|
||||
resolveXframeConfig({
|
||||
url: 'https://a.de/',
|
||||
title: 'Board',
|
||||
reloadSeconds: 60,
|
||||
crop: { x: 100, y: 200, w: 800, h: 400 },
|
||||
zoom: 75,
|
||||
readOnly: true,
|
||||
}),
|
||||
).toEqual({
|
||||
url: 'https://a.de/',
|
||||
title: 'Board',
|
||||
reloadSeconds: 60,
|
||||
crop: { x: 100, y: 200, w: 800, h: 400 },
|
||||
zoom: 75,
|
||||
readOnly: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('Test 21: clampXframeCrop ist exportiert — { 1200, 0, 200, 100 } -> x 1080', () => {
|
||||
expect(clampXframeCrop({ x: 1200, y: 0, w: 200, h: 100 })).toEqual({ x: 1080, y: 0, w: 200, h: 100 });
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user