Files
OrionTV/utils/__tests__/ResponsiveStyles.test.ts

237 lines
6.5 KiB
TypeScript

import { StyleSheet } from "react-native";
import {
createResponsiveStyles,
useResponsiveStyles,
getCommonResponsiveStyles,
getResponsiveTextSize,
getResponsiveSpacing,
ResponsiveStyleCreator,
} from "../ResponsiveStyles";
import { ResponsiveConfig } from "@/hooks/useResponsiveLayout";
import { DeviceUtils } from "../DeviceUtils";
jest.mock("react-native", () => ({
StyleSheet: {
create: jest.fn((styles) => styles),
},
}));
jest.mock("@/hooks/useResponsiveLayout", () => ({
useResponsiveLayout: jest.fn(),
}));
jest.mock("@/utils/DeviceUtils", () => ({
DeviceUtils: {
getMinTouchTargetSize: jest.fn(),
getOptimalFontSize: jest.fn(),
},
}));
const mockedStyleSheet = StyleSheet as jest.Mocked<typeof StyleSheet>;
const mockedDeviceUtils = DeviceUtils as jest.Mocked<typeof DeviceUtils>;
describe("ResponsiveStyles", () => {
const mockConfig: ResponsiveConfig = {
deviceType: "mobile",
spacing: 16,
safeAreaInsets: { top: 0, bottom: 0, left: 0, right: 0 },
windowWidth: 375,
windowHeight: 812,
isLandscape: false,
};
beforeEach(() => {
jest.clearAllMocks();
mockedDeviceUtils.getMinTouchTargetSize.mockReturnValue(44);
mockedDeviceUtils.getOptimalFontSize.mockImplementation((size) => size);
});
describe("createResponsiveStyles", () => {
it("应该创建响应式样式函数", () => {
const styleCreator: ResponsiveStyleCreator<any> = (config) => ({
container: {
padding: config.spacing,
},
});
const responsiveStylesFunc = createResponsiveStyles(styleCreator);
const styles = responsiveStylesFunc(mockConfig);
expect(mockedStyleSheet.create).toHaveBeenCalledWith({
container: {
padding: 16,
},
});
expect(styles).toEqual({
container: {
padding: 16,
},
});
});
});
describe("getCommonResponsiveStyles", () => {
beforeEach(() => {
mockedDeviceUtils.getOptimalFontSize.mockImplementation((size) => {
const deviceType = "mobile";
const scaleFactor = {
mobile: 1.0,
tablet: 1.1,
tv: 1.25,
}[deviceType];
return Math.round(size * scaleFactor);
});
});
it("应该为 mobile 设备返回正确的样式", () => {
const mobileConfig: ResponsiveConfig = {
...mockConfig,
deviceType: "mobile",
spacing: 16,
};
mockedDeviceUtils.getMinTouchTargetSize.mockReturnValue(44);
const styles = getCommonResponsiveStyles(mobileConfig);
expect(styles.container).toEqual({
flex: 1,
paddingHorizontal: 16,
});
expect(styles.safeContainer).toEqual({
flex: 1,
paddingHorizontal: 16,
paddingTop: 20,
});
expect(styles.primaryButton).toEqual({
minHeight: 44,
paddingHorizontal: 24,
paddingVertical: 16,
borderRadius: 8,
justifyContent: "center",
alignItems: "center",
});
});
it("应该为 tablet 设备返回正确的样式", () => {
const tabletConfig: ResponsiveConfig = {
...mockConfig,
deviceType: "tablet",
spacing: 20,
};
mockedDeviceUtils.getMinTouchTargetSize.mockReturnValue(48);
const styles = getCommonResponsiveStyles(tabletConfig);
expect(styles.safeContainer.paddingTop).toBe(30);
expect(styles.primaryButton.borderRadius).toBe(10);
expect(styles.primaryButton.minHeight).toBe(48);
});
it("应该为 tv 设备返回正确的样式", () => {
const tvConfig: ResponsiveConfig = {
...mockConfig,
deviceType: "tv",
spacing: 24,
};
mockedDeviceUtils.getMinTouchTargetSize.mockReturnValue(60);
const styles = getCommonResponsiveStyles(tvConfig);
expect(styles.safeContainer.paddingTop).toBe(40);
expect(styles.primaryButton.borderRadius).toBe(12);
expect(styles.primaryButton.minHeight).toBe(60);
});
it("应该为 tv 设备不包含阴影样式", () => {
const tvConfig: ResponsiveConfig = {
...mockConfig,
deviceType: "tv",
spacing: 24,
};
const styles = getCommonResponsiveStyles(tvConfig);
expect(styles.shadow).toEqual({});
});
it("应该为非 tv 设备包含阴影样式", () => {
const mobileConfig: ResponsiveConfig = {
...mockConfig,
deviceType: "mobile",
spacing: 16,
};
const styles = getCommonResponsiveStyles(mobileConfig);
expect(styles.shadow).toEqual({
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
});
});
});
describe("getResponsiveTextSize", () => {
it("应该为 mobile 设备返回基础大小", () => {
const result = getResponsiveTextSize(16, "mobile");
expect(result).toBe(16);
});
it("应该为 tablet 设备返回缩放后的大小", () => {
const result = getResponsiveTextSize(16, "tablet");
expect(result).toBe(18); // 16 * 1.1 = 17.6, rounded to 18
});
it("应该为 tv 设备返回缩放后的大小", () => {
const result = getResponsiveTextSize(16, "tv");
expect(result).toBe(20); // 16 * 1.25 = 20
});
it("应该为未知设备类型返回基础大小", () => {
const result = getResponsiveTextSize(16, "unknown");
expect(result).toBe(16);
});
it("应该正确处理小数点", () => {
const result = getResponsiveTextSize(15, "tablet");
expect(result).toBe(17); // 15 * 1.1 = 16.5, rounded to 17
});
});
describe("getResponsiveSpacing", () => {
it("应该为 mobile 设备返回缩放后的间距", () => {
const result = getResponsiveSpacing(20, "mobile");
expect(result).toBe(16); // 20 * 0.8 = 16
});
it("应该为 tablet 设备返回基础间距", () => {
const result = getResponsiveSpacing(20, "tablet");
expect(result).toBe(20);
});
it("应该为 tv 设备返回缩放后的间距", () => {
const result = getResponsiveSpacing(20, "tv");
expect(result).toBe(30); // 20 * 1.5 = 30
});
it("应该为未知设备类型返回基础间距", () => {
const result = getResponsiveSpacing(20, "unknown");
expect(result).toBe(20);
});
it("应该正确处理小数点", () => {
const result = getResponsiveSpacing(15, "mobile");
expect(result).toBe(12); // 15 * 0.8 = 12
});
});
});