slopus--happy
98e40dac97
CLI Smoke Test / smoke-test-linux (20) (push) Has been cancelled
CLI Smoke Test / smoke-test-linux (24) (push) Has been cancelled
CLI Smoke Test / smoke-test-windows (20) (push) Has been cancelled
CLI Smoke Test / smoke-test-windows (24) (push) Has been cancelled
Expo App TypeScript typecheck / typecheck (push) Has been cancelled
318 行
11 KiB
TypeScript
318 行
11 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { calculateDeviceDimensions, determineDeviceType, calculateHeaderHeight } from './deviceCalculations';
|
|
|
|
describe('responsive utilities', () => {
|
|
describe('calculateDeviceDimensions', () => {
|
|
it('should calculate dimensions correctly for standard phone (iPhone 13)', () => {
|
|
// iPhone 13: 390x844 points (logical pixels)
|
|
const result = calculateDeviceDimensions({
|
|
widthPoints: 390,
|
|
heightPoints: 844,
|
|
pointsPerInch: 163 // iOS standard
|
|
});
|
|
|
|
expect(result.widthInches).toBeCloseTo(2.393, 3); // 390/163
|
|
expect(result.heightInches).toBeCloseTo(5.178, 3); // 844/163
|
|
expect(result.diagonalInches).toBeCloseTo(5.704, 2); // ~5.7 inches
|
|
});
|
|
|
|
it('should calculate dimensions correctly for tablet (iPad Pro 11")', () => {
|
|
// iPad Pro 11": 834x1194 points
|
|
const result = calculateDeviceDimensions({
|
|
widthPoints: 834,
|
|
heightPoints: 1194,
|
|
pointsPerInch: 163 // iOS standard
|
|
});
|
|
|
|
expect(result.widthInches).toBeCloseTo(5.117, 3); // 834/163
|
|
expect(result.heightInches).toBeCloseTo(7.325, 3); // 1194/163
|
|
expect(result.diagonalInches).toBeCloseTo(8.935, 2); // ~8.9 inches (marketed as 11" diagonal screen)
|
|
});
|
|
|
|
it('should calculate dimensions correctly for Android phone', () => {
|
|
// Typical Android phone: 360x800 dp (density-independent pixels)
|
|
const result = calculateDeviceDimensions({
|
|
widthPoints: 360,
|
|
heightPoints: 800,
|
|
pointsPerInch: 160 // Android standard
|
|
});
|
|
|
|
expect(result.widthInches).toBeCloseTo(2.25, 3); // 360/160
|
|
expect(result.heightInches).toBeCloseTo(5.0, 3); // 800/160
|
|
expect(result.diagonalInches).toBeCloseTo(5.483, 3); // ~5.5 inches
|
|
});
|
|
|
|
it('should calculate dimensions correctly for Android tablet', () => {
|
|
// Typical Android tablet: 800x1280 dp
|
|
const result = calculateDeviceDimensions({
|
|
widthPoints: 800,
|
|
heightPoints: 1280,
|
|
pointsPerInch: 160 // Android standard
|
|
});
|
|
|
|
expect(result.widthInches).toBeCloseTo(5.0, 4);
|
|
expect(result.heightInches).toBeCloseTo(8.0, 4);
|
|
expect(result.diagonalInches).toBeCloseTo(9.434, 4); // ~9.4 inches
|
|
});
|
|
|
|
it('should handle custom points per inch values', () => {
|
|
const result = calculateDeviceDimensions({
|
|
widthPoints: 1000,
|
|
heightPoints: 2000,
|
|
pointsPerInch: 96 // Custom value
|
|
});
|
|
|
|
expect(result.widthInches).toBeCloseTo(10.417, 3);
|
|
expect(result.heightInches).toBeCloseTo(20.833, 3);
|
|
expect(result.diagonalInches).toBeCloseTo(23.292, 2);
|
|
});
|
|
|
|
it('should handle very small screens', () => {
|
|
const result = calculateDeviceDimensions({
|
|
widthPoints: 320,
|
|
heightPoints: 480,
|
|
pointsPerInch: 160
|
|
});
|
|
|
|
expect(result.widthInches).toBeCloseTo(2.0, 4);
|
|
expect(result.heightInches).toBeCloseTo(3.0, 4);
|
|
expect(result.diagonalInches).toBeCloseTo(3.6056, 3);
|
|
});
|
|
});
|
|
|
|
describe('determineDeviceType', () => {
|
|
it('should identify small iPads (iPad Mini) as phones', () => {
|
|
const result = determineDeviceType({
|
|
diagonalInches: 8.3, // iPad Mini diagonal
|
|
platform: 'ios',
|
|
isPad: true
|
|
});
|
|
|
|
expect(result).toBe('phone');
|
|
});
|
|
|
|
it('should identify large iPads as tablets', () => {
|
|
const result = determineDeviceType({
|
|
diagonalInches: 10.9, // iPad Air diagonal
|
|
platform: 'ios',
|
|
isPad: true
|
|
});
|
|
|
|
expect(result).toBe('tablet');
|
|
});
|
|
|
|
it('should identify large diagonal as tablet on Android', () => {
|
|
const result = determineDeviceType({
|
|
diagonalInches: 10.1, // Large Android tablet
|
|
platform: 'android'
|
|
});
|
|
|
|
expect(result).toBe('tablet');
|
|
});
|
|
|
|
it('should identify small diagonal as phone on Android', () => {
|
|
const result = determineDeviceType({
|
|
diagonalInches: 5.5,
|
|
platform: 'android'
|
|
});
|
|
|
|
expect(result).toBe('phone');
|
|
});
|
|
|
|
it('should respect custom tablet threshold', () => {
|
|
const result1 = determineDeviceType({
|
|
diagonalInches: 8.0,
|
|
platform: 'android',
|
|
tabletThresholdInches: 7.5
|
|
});
|
|
expect(result1).toBe('tablet');
|
|
|
|
const result2 = determineDeviceType({
|
|
diagonalInches: 8.0,
|
|
platform: 'android',
|
|
tabletThresholdInches: 8.5
|
|
});
|
|
expect(result2).toBe('phone');
|
|
});
|
|
|
|
it('should handle edge case at exact threshold', () => {
|
|
const result = determineDeviceType({
|
|
diagonalInches: 9.0,
|
|
platform: 'android'
|
|
});
|
|
|
|
expect(result).toBe('tablet');
|
|
});
|
|
|
|
it('should handle iOS non-iPad devices', () => {
|
|
const result = determineDeviceType({
|
|
diagonalInches: 5.8, // iPhone size
|
|
platform: 'ios',
|
|
isPad: false
|
|
});
|
|
|
|
expect(result).toBe('phone');
|
|
});
|
|
|
|
it('should handle web platform', () => {
|
|
const result = determineDeviceType({
|
|
diagonalInches: 15, // Large monitor
|
|
platform: 'web'
|
|
});
|
|
|
|
expect(result).toBe('tablet'); // Large screens are considered tablets
|
|
});
|
|
});
|
|
|
|
describe('integration scenarios', () => {
|
|
it('should correctly identify iPhone 13 Pro Max as phone', () => {
|
|
// iPhone 13 Pro Max: 428x926 points
|
|
const dimensions = calculateDeviceDimensions({
|
|
widthPoints: 428,
|
|
heightPoints: 926,
|
|
pointsPerInch: 163
|
|
});
|
|
|
|
const deviceType = determineDeviceType({
|
|
diagonalInches: dimensions.diagonalInches,
|
|
platform: 'ios',
|
|
isPad: false
|
|
});
|
|
|
|
expect(deviceType).toBe('phone');
|
|
expect(dimensions.diagonalInches).toBeCloseTo(6.258, 2); // ~6.3 inches
|
|
expect(dimensions.diagonalInches).toBeLessThan(7);
|
|
});
|
|
|
|
it('should correctly identify iPad Mini as phone', () => {
|
|
// iPad Mini: 744x1133 points
|
|
const dimensions = calculateDeviceDimensions({
|
|
widthPoints: 744,
|
|
heightPoints: 1133,
|
|
pointsPerInch: 163
|
|
});
|
|
|
|
const deviceType = determineDeviceType({
|
|
diagonalInches: dimensions.diagonalInches,
|
|
platform: 'ios',
|
|
isPad: true
|
|
});
|
|
|
|
expect(deviceType).toBe('phone'); // iPad Mini treated as phone
|
|
expect(dimensions.diagonalInches).toBeCloseTo(8.316, 2); // ~8.3 inches
|
|
});
|
|
|
|
it('should handle foldable devices appropriately', () => {
|
|
// Samsung Galaxy Fold (unfolded): typically around 673x884 dp
|
|
const dimensions = calculateDeviceDimensions({
|
|
widthPoints: 673,
|
|
heightPoints: 884,
|
|
pointsPerInch: 160
|
|
});
|
|
|
|
const deviceType = determineDeviceType({
|
|
diagonalInches: dimensions.diagonalInches,
|
|
platform: 'android'
|
|
});
|
|
|
|
// Unfolded state diagonal is around 6.9 inches
|
|
expect(dimensions.diagonalInches).toBeCloseTo(6.944, 2);
|
|
// With 9" threshold, it's classified as phone
|
|
expect(deviceType).toBe('phone');
|
|
});
|
|
|
|
it('should identify Galaxy Z Fold as phone when unfolded', () => {
|
|
// Galaxy Z Fold5 unfolded: 7.6" diagonal screen
|
|
const deviceType = determineDeviceType({
|
|
diagonalInches: 7.6,
|
|
platform: 'android'
|
|
});
|
|
|
|
expect(deviceType).toBe('phone'); // Foldables are phones
|
|
});
|
|
});
|
|
|
|
describe('calculateHeaderHeight', () => {
|
|
it('should return correct height for Android phone in portrait', () => {
|
|
const height = calculateHeaderHeight({
|
|
platform: 'android',
|
|
deviceType: 'phone',
|
|
isLandscape: false
|
|
});
|
|
expect(height).toBe(56);
|
|
});
|
|
|
|
it('should return correct height for Android phone in landscape', () => {
|
|
const height = calculateHeaderHeight({
|
|
platform: 'android',
|
|
deviceType: 'phone',
|
|
isLandscape: true
|
|
});
|
|
expect(height).toBe(48);
|
|
});
|
|
|
|
it('should return correct height for Android tablet', () => {
|
|
const height = calculateHeaderHeight({
|
|
platform: 'android',
|
|
deviceType: 'tablet',
|
|
isLandscape: false
|
|
});
|
|
expect(height).toBe(64);
|
|
});
|
|
|
|
it('should return correct height for iOS iPhone', () => {
|
|
const height = calculateHeaderHeight({
|
|
platform: 'ios',
|
|
isPad: false,
|
|
isLandscape: false
|
|
});
|
|
expect(height).toBe(44);
|
|
});
|
|
|
|
it('should return correct height for iOS iPad', () => {
|
|
const height = calculateHeaderHeight({
|
|
platform: 'ios',
|
|
isPad: true,
|
|
isLandscape: false
|
|
});
|
|
expect(height).toBe(50);
|
|
});
|
|
|
|
it('should ignore landscape for iOS devices', () => {
|
|
const iPhonePortrait = calculateHeaderHeight({
|
|
platform: 'ios',
|
|
isPad: false,
|
|
isLandscape: false
|
|
});
|
|
const iPhoneLandscape = calculateHeaderHeight({
|
|
platform: 'ios',
|
|
isPad: false,
|
|
isLandscape: true
|
|
});
|
|
expect(iPhonePortrait).toBe(iPhoneLandscape);
|
|
|
|
const iPadPortrait = calculateHeaderHeight({
|
|
platform: 'ios',
|
|
isPad: true,
|
|
isLandscape: false
|
|
});
|
|
const iPadLandscape = calculateHeaderHeight({
|
|
platform: 'ios',
|
|
isPad: true,
|
|
isLandscape: true
|
|
});
|
|
expect(iPadPortrait).toBe(iPadLandscape);
|
|
});
|
|
|
|
it('should use isPad for iOS and ignore deviceType', () => {
|
|
// Even if deviceType says phone, if isPad is true, should return iPad height
|
|
const height = calculateHeaderHeight({
|
|
platform: 'ios',
|
|
isPad: true,
|
|
deviceType: 'phone', // This should be ignored
|
|
isLandscape: false
|
|
});
|
|
expect(height).toBe(50);
|
|
});
|
|
});
|
|
}); |