mirror of
https://github.com/immich-app/immich.git
synced 2026-05-21 15:16:31 -04:00
95 lines
3.6 KiB
TypeScript
95 lines
3.6 KiB
TypeScript
import { getContentMetrics, getNaturalSize, scaleToFit } from '$lib/utils/container-utils';
|
|
|
|
const mockImage = (props: {
|
|
naturalWidth: number;
|
|
naturalHeight: number;
|
|
width: number;
|
|
height: number;
|
|
}): HTMLImageElement => props as unknown as HTMLImageElement;
|
|
|
|
const mockVideo = (props: {
|
|
videoWidth: number;
|
|
videoHeight: number;
|
|
clientWidth: number;
|
|
clientHeight: number;
|
|
}): HTMLVideoElement => {
|
|
const element = Object.create(HTMLVideoElement.prototype);
|
|
for (const [key, value] of Object.entries(props)) {
|
|
Object.defineProperty(element, key, { value, writable: true, configurable: true });
|
|
}
|
|
return element;
|
|
};
|
|
|
|
describe('scaleToFit', () => {
|
|
it('should return full width when image is wider than container', () => {
|
|
expect(scaleToFit({ width: 2000, height: 1000 }, { width: 800, height: 600 })).toEqual({ width: 800, height: 400 });
|
|
});
|
|
|
|
it('should return full height when image is taller than container', () => {
|
|
expect(scaleToFit({ width: 1000, height: 2000 }, { width: 800, height: 600 })).toEqual({ width: 300, height: 600 });
|
|
});
|
|
|
|
it('should return exact fit when aspect ratios match', () => {
|
|
expect(scaleToFit({ width: 1600, height: 900 }, { width: 800, height: 450 })).toEqual({ width: 800, height: 450 });
|
|
});
|
|
|
|
it('should handle square images in landscape container', () => {
|
|
expect(scaleToFit({ width: 500, height: 500 }, { width: 800, height: 600 })).toEqual({ width: 600, height: 600 });
|
|
});
|
|
|
|
it('should handle square images in portrait container', () => {
|
|
expect(scaleToFit({ width: 500, height: 500 }, { width: 400, height: 600 })).toEqual({ width: 400, height: 400 });
|
|
});
|
|
});
|
|
|
|
describe('getContentMetrics', () => {
|
|
it('should compute zero offsets when aspect ratios match', () => {
|
|
const img = mockImage({ naturalWidth: 1600, naturalHeight: 900, width: 800, height: 450 });
|
|
expect(getContentMetrics(img)).toEqual({
|
|
contentWidth: 800,
|
|
contentHeight: 450,
|
|
offsetX: 0,
|
|
offsetY: 0,
|
|
});
|
|
});
|
|
|
|
it('should compute horizontal letterbox offsets for tall image', () => {
|
|
const img = mockImage({ naturalWidth: 1000, naturalHeight: 2000, width: 800, height: 600 });
|
|
const metrics = getContentMetrics(img);
|
|
expect(metrics.contentWidth).toBe(300);
|
|
expect(metrics.contentHeight).toBe(600);
|
|
expect(metrics.offsetX).toBe(250);
|
|
expect(metrics.offsetY).toBe(0);
|
|
});
|
|
|
|
it('should compute vertical letterbox offsets for wide image', () => {
|
|
const img = mockImage({ naturalWidth: 2000, naturalHeight: 1000, width: 800, height: 600 });
|
|
const metrics = getContentMetrics(img);
|
|
expect(metrics.contentWidth).toBe(800);
|
|
expect(metrics.contentHeight).toBe(400);
|
|
expect(metrics.offsetX).toBe(0);
|
|
expect(metrics.offsetY).toBe(100);
|
|
});
|
|
|
|
it('should use clientWidth/clientHeight for video elements', () => {
|
|
const video = mockVideo({ videoWidth: 1920, videoHeight: 1080, clientWidth: 800, clientHeight: 600 });
|
|
const metrics = getContentMetrics(video);
|
|
expect(metrics.contentWidth).toBe(800);
|
|
expect(metrics.contentHeight).toBe(450);
|
|
expect(metrics.offsetX).toBe(0);
|
|
expect(metrics.offsetY).toBe(75);
|
|
});
|
|
});
|
|
|
|
describe('getNaturalSize', () => {
|
|
it('should return naturalWidth/naturalHeight for images', () => {
|
|
const img = mockImage({ naturalWidth: 4000, naturalHeight: 3000, width: 800, height: 600 });
|
|
expect(getNaturalSize(img)).toEqual({ width: 4000, height: 3000 });
|
|
});
|
|
|
|
it('should return videoWidth/videoHeight for videos', () => {
|
|
const video = mockVideo({ videoWidth: 1920, videoHeight: 1080, clientWidth: 800, clientHeight: 600 });
|
|
expect(getNaturalSize(video)).toEqual({ width: 1920, height: 1080 });
|
|
});
|
|
});
|