mattermost-mobile/app/utils/images/index.test.ts
2025-11-10 19:18:27 +08:00

293 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import RNUtils from '@mattermost/rnutils';
import {IMAGE_MAX_HEIGHT, IMAGE_MIN_DIMENSION} from '@constants/image';
import {
calculateDimensions,
getViewPortWidth,
isGifTooLarge,
} from './index';
jest.mock('@mattermost/rnutils', () => ({
getWindowDimensions: jest.fn(() => ({width: 800, height: 600})),
}));
jest.mock('@constants/image', () => ({
IMAGE_MAX_HEIGHT: 800,
IMAGE_MIN_DIMENSION: 50,
MAX_GIF_SIZE: 1000000,
VIEWPORT_IMAGE_OFFSET: 20,
VIEWPORT_IMAGE_REPLY_OFFSET: 40,
}));
jest.mock('@constants', () => ({
View: {
TABLET_SIDEBAR_WIDTH: 100,
},
}));
describe('calculateDimensions', () => {
it('should return 0 dimensions when height and width are not provided', () => {
const result = calculateDimensions();
expect(result).toEqual({height: 0, width: 0});
});
it('should return correct dimensions when width exceeds viewport width', () => {
const result = calculateDimensions(200, 400, 300);
expect(result).toEqual({height: 150, width: 300});
});
it('should assign imageHeight as IMAGE_MAX_HEIGHT when imageHeight exceeds IMAGE_MAX_HEIGHT and viewPortHeight is undefined', () => {
const result = calculateDimensions(900, 400, 600);
expect(result).toEqual({
height: IMAGE_MAX_HEIGHT,
width: IMAGE_MAX_HEIGHT * (400 / 900),
});
});
it('should return minimum dimensions when width is less than IMAGE_MIN_DIMENSION', () => {
const result = calculateDimensions(20, 30, 100);
expect(result).toEqual({height: 50, width: 75});
});
it('should return correct dimensions when height exceeds IMAGE_MAX_HEIGHT', () => {
const result = calculateDimensions(900, 500, 600, 700);
expect(result).toEqual({height: 700, width: 388.8888888888889});
});
it('should return minimum dimensions when height is less than IMAGE_MIN_DIMENSION', () => {
const result = calculateDimensions(30, 40, 100);
expect(result).toEqual({height: 50, width: 66.66666666666666});
});
it('should assign imageHeight as viewPortHeight when imageHeight exceeds viewPortHeight and viewPortHeight is less than IMAGE_MAX_HEIGHT', () => {
const result = calculateDimensions(900, 400, 600, 700);
expect(result).toEqual({
height: 700,
width: 700 * (400 / 900),
});
});
it('should assign imageHeight and imageWidth based on IMAGE_MIN_DIMENSION when imageHeight is less than IMAGE_MIN_DIMENSION and fits within viewPortWidth', () => {
const result = calculateDimensions(20, 40, 100);
expect(result).toEqual({
height: 50,
width: 50 * (40 / 20),
});
});
it('should assign imageHeight and imageWidth based on viewPortHeight when imageHeight exceeds viewPortHeight', () => {
const result = calculateDimensions(600, 400, 500, 300);
expect(result).toEqual({
height: 300,
width: 300 * (400 / 600),
});
});
it('should assign imageHeight and imageWidth based on viewPortHeight when imageHeight exceeds viewPortHeight and previous conditions are not met', () => {
const result = calculateDimensions(1700, 900, 1000, 900);
expect(result).toEqual({
height: 900,
width: 900 * (900 / 1700),
});
});
it('should handle negative image dimensions gracefully', () => {
const result = calculateDimensions(-100, -200, 300);
expect(result.height).toBeGreaterThanOrEqual(0);
expect(result.width).toBeGreaterThanOrEqual(0);
});
it('should handle zero viewport width', () => {
const result = calculateDimensions(100, 200, 0);
expect(result).toEqual({height: 0, width: 0});
});
it('should handle square images', () => {
const result = calculateDimensions(100, 100, 50);
expect(result).toEqual({height: 50, width: 50});
});
it('should handle extremely large images', () => {
const result = calculateDimensions(10000, 5000, 1000, 800);
expect(result.height).toBeLessThanOrEqual(800);
expect(result.width).toBeLessThanOrEqual(1000);
});
it('should handle extremely small images', () => {
const result = calculateDimensions(1, 1, 100);
expect(result.height).toBeGreaterThanOrEqual(IMAGE_MIN_DIMENSION);
expect(result.width).toBeGreaterThanOrEqual(IMAGE_MIN_DIMENSION);
});
it('should handle when only width is provided', () => {
const result = calculateDimensions(undefined, 200, 300);
expect(result).toEqual({height: 0, width: 0});
});
it('should handle when only height is provided', () => {
const result = calculateDimensions(200, undefined, 300);
expect(result).toEqual({height: 0, width: 0});
});
it('should handle when all parameters are undefined', () => {
const result = calculateDimensions(undefined, undefined, undefined, undefined);
expect(result).toEqual({height: 0, width: 0});
});
it('should fit portrait image to viewport height when matchViewPort is true', () => {
const result = calculateDimensions(800, 400, 600, 900, true);
expect(result.height).toBe(900);
expect(result.width).toBe(450);
});
it('should fit landscape image to viewport width when matchViewPort is true', () => {
const result = calculateDimensions(400, 800, 600, 900, true);
expect(result.width).toBe(600);
expect(result.height).toBe(300);
});
it('should fit square image to viewport width when matchViewPort is true', () => {
const result = calculateDimensions(500, 500, 300, 700, true);
expect(result.width).toBe(300);
expect(result.height).toBe(300);
});
it('should not fit to viewport if matchViewPort is false', () => {
const result = calculateDimensions(800, 400, 600, 900, false);
expect(result.height).not.toBe(900);
expect(result.width).not.toBe(450);
});
it('should handle when viewPortHeight is 0', () => {
const result = calculateDimensions(800, 400, 600, 0, true);
expect(result.height).not.toBe(0);
expect(result.width).not.toBe(0);
});
it('should handle when matchViewPort is true and image is smaller than viewport', () => {
const result = calculateDimensions(100, 80, 300, 300, true);
expect(result.width).toBe(240);
expect(result.height).toBe(300);
});
it('should handle when matchViewPort is true and image is square', () => {
const result = calculateDimensions(100, 100, 200, 300, true);
expect(result.width).toBe(200);
expect(result.height).toBe(200);
});
it('should handle when matchViewPort is true and image is wider than tall', () => {
const result = calculateDimensions(100, 200, 150, 300, true);
expect(result.width).toBe(150);
expect(result.height).toBe(75);
});
it('should handle when matchViewPort is true and image is taller than wide', () => {
const result = calculateDimensions(200, 100, 150, 300, true);
expect(result.height).toBe(300);
expect(result.width).toBe(150);
});
it('should handle when matchViewPort is true and image is exactly viewport size', () => {
const result = calculateDimensions(300, 300, 300, 300, true);
expect(result.width).toBe(300);
expect(result.height).toBe(300);
});
it('should constrain portrait image width when scaling to viewport height would cause overflow', () => {
// Portrait image 380×800, viewport 400×900
// Without fix: height=900, width=900×(380/800)=427.5 (OVERFLOW!)
// With fix: should scale based on width instead
const result = calculateDimensions(800, 380, 400, 900, true);
expect(result.width).toBeLessThanOrEqual(400);
expect(result.height).toBeLessThanOrEqual(900);
// Should constrain to width: 400w, height=400×(800/380)≈842
expect(result.width).toBe(400);
expect(result.height).toBeCloseTo(842.1, 0);
});
it('should constrain landscape image height when scaling to viewport width would cause overflow', () => {
// Landscape image 800×380, viewport 900×400
// Without fix: width=900, height=900×(380/800)=427.5 (OVERFLOW!)
// With fix: should scale based on height instead
const result = calculateDimensions(380, 800, 900, 400, true);
expect(result.width).toBeLessThanOrEqual(900);
expect(result.height).toBeLessThanOrEqual(400);
// Should constrain to height: 400h, width=400×(800/380)≈842
expect(result.height).toBe(400);
expect(result.width).toBeCloseTo(842.1, 0);
});
it('should handle extreme portrait aspect ratio with matchViewPort', () => {
// Very tall portrait image 200×1000 (1:5 ratio), viewport 300×600
// Would try to fit to height: 600h, width=600×(200/1000)=120 (OK)
// But if viewport is narrower: 100×600
// Would try: 600h, width=600×(200/1000)=120 (OVERFLOW!)
const result = calculateDimensions(1000, 200, 100, 600, true);
expect(result.width).toBeLessThanOrEqual(100);
expect(result.height).toBeLessThanOrEqual(600);
// Should constrain to width: 100w, height=100×(1000/200)=500
expect(result.width).toBe(100);
expect(result.height).toBe(500);
});
});
describe('getViewPortWidth', () => {
beforeEach(() => {
(RNUtils.getWindowDimensions as jest.Mock).mockReturnValue({width: 800, height: 600});
});
it('should calculate viewport width for normal post', () => {
const result = getViewPortWidth(false);
expect(result).toBe(580);
});
it('should calculate viewport width for reply post', () => {
const result = getViewPortWidth(true);
expect(result).toBe(540);
});
it('should calculate viewport width for tablet offset', () => {
const result = getViewPortWidth(false, true);
expect(result).toBe(480);
});
it('should calculate viewport width for reply post with tablet offset', () => {
const result = getViewPortWidth(true, true);
expect(result).toBe(440);
});
});
describe('isGifTooLarge', () => {
it('should return false if image is not a gif', () => {
const result = isGifTooLarge({format: 'jpg', frame_count: 1, height: 500, width: 500});
expect(result).toBe(false);
});
it('should return false if image metadata is undefined', () => {
const result = isGifTooLarge(undefined);
expect(result).toBe(false);
});
it('should return true if gif is too large', () => {
const result = isGifTooLarge({format: 'gif', frame_count: 100, height: 1000, width: 1000});
expect(result).toBe(true);
});
it('should return false if gif is not too large', () => {
const result = isGifTooLarge({format: 'gif', frame_count: 10, height: 100, width: 100});
expect(result).toBe(false);
});
it('should return false if gif does not specify frame count', () => {
const result = isGifTooLarge({format: 'gif', height: 100, width: 100});
expect(result).toBe(false);
});
});