Fix preview cropping: canvas fits within viewport, preserves aspect ratio
.preview was width:100% inside max-height:50vh container — tall photos were clipped. Now: max-width:100%, max-height:50vh, width/height auto, object-fit:contain, flex-centered in the wrap. Added e2e regression test: loads a photo, verifies the canvas bounding box fits the viewport, preserves aspect ratio, and is not clipped by the container.
This commit is contained in:
@@ -468,11 +468,17 @@
|
||||
border-radius: 8px;
|
||||
border: 1px solid #ddd;
|
||||
background: #f5f5f5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.preview {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
max-height: 50vh;
|
||||
width: auto;
|
||||
height: auto;
|
||||
display: block;
|
||||
object-fit: contain;
|
||||
}
|
||||
.busy {
|
||||
position: absolute;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
const SLAB_FIXTURE = 'tests/fixtures/slab-green.jpg';
|
||||
|
||||
// E2E smoke: the app serves and the health route responds.
|
||||
// Later cards extend this to walk the full 5-state capture flow.
|
||||
test('M1-1 harness smoke: app serves + health ok', async ({ page, request }) => {
|
||||
await page.goto('/');
|
||||
await expect(page).toHaveTitle(/SlabUploader/);
|
||||
@@ -10,3 +11,35 @@ test('M1-1 harness smoke: app serves + health ok', async ({ page, request }) =>
|
||||
const body = await res.json();
|
||||
expect(body.ok).toBe(true);
|
||||
});
|
||||
|
||||
// Regression: the preview canvas must fit the full photo within the
|
||||
// viewport without cropping. Spec: "Preview fits the device width.
|
||||
// Height is capped so Mask and Measure controls stay on screen."
|
||||
test('preview canvas fits full photo without cropping', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.locator('input[type="file"]').setInputFiles(SLAB_FIXTURE);
|
||||
await page.waitForTimeout(2500); // mask recompute
|
||||
|
||||
const canvas = page.locator('canvas.preview');
|
||||
await expect(canvas).toBeVisible();
|
||||
|
||||
// Get the canvas's rendered (CSS) size and its intrinsic (pixel) size.
|
||||
const box = await canvas.boundingBox();
|
||||
const intrinsic = await canvas.evaluate((c) => ({ w: c.width, h: c.height }));
|
||||
|
||||
// The rendered size must fit within the viewport.
|
||||
const vp = page.viewportSize();
|
||||
expect(box.width).toBeLessThanOrEqual(vp.width);
|
||||
expect(box.height).toBeLessThanOrEqual(vp.height * 0.55); // 50vh cap + tolerance
|
||||
|
||||
// Aspect ratio must be preserved (no distortion).
|
||||
const renderedRatio = box.width / box.height;
|
||||
const intrinsicRatio = intrinsic.w / intrinsic.h;
|
||||
expect(renderedRatio).toBeCloseTo(intrinsicRatio, 1);
|
||||
|
||||
// The canvas must not be clipped by its container.
|
||||
const wrap = page.locator('.preview-wrap');
|
||||
const wrapBox = await wrap.boundingBox();
|
||||
expect(box.width).toBeLessThanOrEqual(wrapBox.width + 1);
|
||||
expect(box.height).toBeLessThanOrEqual(wrapBox.height + 1);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user