Files
novalon-website/docs/plans/2026-03-05-mobile-testing-enhancement-design.md
T

39 KiB
Raw Blame History

移动端测试完善方案设计文档

创建日期: 2026-03-05
项目: Novalon Website E2E Testing Enhancement
目标: 建立全面完善的移动端测试体系,覆盖性能、兼容性、手势交互、PWA 功能等方面


1. 项目背景

1.1 当前现状

项目已建立基于 Playwright 的 E2E 测试框架,具备基础的移动端测试能力:

  • 基本的移动端 UI 交互测试(菜单、导航、表单)
  • 多设备尺寸配置(iPhone、Android、Tablet
  • 基础的触摸交互测试
  • 响应式布局测试

1.2 存在的问题

当前移动端测试体系存在以下不足:

  • 缺乏系统的性能测试,无法验证移动端网络条件下的加载性能
  • 兼容性测试覆盖不全面,缺乏跨设备、跨浏览器的深度验证
  • 手势交互测试仅覆盖基本操作,缺乏复杂手势测试
  • 缺少 PWA 功能测试,无法验证离线缓存、安装等功能
  • 测试报告缺乏移动端特定的分析和可视化

1.3 项目目标

建立企业级移动端测试体系,实现:

  • 🎯 全面的性能测试覆盖,包括 Core Web Vitals 和网络性能
  • 🎯 完整的兼容性测试矩阵,支持多设备、多浏览器验证
  • 🎯 丰富的手势交互测试,覆盖所有常见移动端手势
  • 🎯 完整的 PWA 功能测试,验证移动端特性
  • 🎯 智能的测试报告系统,提供移动端专属的分析和可视化

2. 整体架构设计

采用分层架构设计,确保系统的可扩展性和可维护性:

┌─────────────────────────────────────────────────────────────┐
│                     测试执行层                               │
│  - 测试配置扩展  - 并行测试策略  - 测试报告系统              │
└─────────────────────────────────────────────────────────────┘
                            ↑
┌─────────────────────────────────────────────────────────────┐
│                     测试用例层                               │
│  - 性能测试套件  - 兼容性测试套件  - 手势交互测试套件        │
│  - PWA 功能测试套件                                          │
└─────────────────────────────────────────────────────────────┘
                            ↑
┌─────────────────────────────────────────────────────────────┐
│                     测试工具层                               │
│  - 手势模拟器  - 网络环境模拟器  - 性能监控器                │
│  - 设备兼容性验证工具                                        │
└─────────────────────────────────────────────────────────────┘
                            ↑
┌─────────────────────────────────────────────────────────────┐
│                     测试数据层                               │
│  - 移动端测试数据生成器  - 设备配置数据  - 网络配置数据      │
│  - 性能基准数据  - 测试数据仓库                              │
└─────────────────────────────────────────────────────────────┘

2.1 测试数据层

职责: 提供移动端测试所需的所有数据支持

核心组件:

  1. 移动端测试数据生成器

    • 扩展现有的 TestDataGenerator
    • 增加设备特定的测试数据(User Agent、触摸事件数据)
    • 支持不同网络条件下的测试数据
  2. 设备配置数据

    • 扩展 devices.ts,增加更多真实设备配置
    • 支持 iPhone 13/14/15 系列
    • 支持 Samsung Galaxy、Google Pixel 系列
    • 支持 iPad Air/Pro 系列
  3. 网络配置数据

    • 预设网络配置(2G、3G、4G、WiFi)
    • 自定义网络配置(延迟、丢包率、带宽)
    • 网络切换场景配置
  4. 性能基准数据

    • Core Web Vitals 基准值
    • 不同设备类型的性能阈值
    • 性能回归检测基准
  5. 测试数据仓库

    • 集中管理所有测试数据
    • 支持数据版本控制
    • 提供数据查询和复用机制

2.2 测试工具层

职责: 提供移动端测试所需的专用工具和功能

核心组件:

  1. 手势模拟器 (GestureSimulator)

    • 基于 Playwright Touch API 构建
    • 支持的手势类型:
      • 单指滑动(水平、垂直,支持速度和距离控制)
      • 双指捏合缩放(支持缩放比例控制)
      • 长按操作(支持自定义时长)
      • 双击操作(支持自定义间隔时间)
      • 拖拽操作(支持方向和距离控制)
    • 提供统一的 API 接口
    • 支持链式调用和参数化配置
  2. 网络环境模拟器 (NetworkSimulator)

    • 利用 Chrome DevTools Protocol 实现
    • 支持的网络场景:
      • 弱网环境(2G、3G、4G 不同信号强度)
      • 离线模式(完全断网)
      • 网络切换(在线→离线、弱网→强网)
      • 网络延迟和丢包模拟
    • 提供预设配置和自定义配置
    • 支持动态切换网络环境
  3. 性能监控器 (PerformanceMonitor)

    • 集成 Lighthouse API
    • 监控的 Core Web Vitals 指标:
      • First Contentful Paint (FCP)
      • Largest Contentful Paint (LCP)
      • Cumulative Layout Shift (CLS)
      • First Input Delay (FID)
      • Time to Interactive (TTI)
    • 建立移动端性能基准
    • 支持性能回归检测
    • 生成详细性能分析报告
  4. 设备兼容性验证工具 (CompatibilityValidator)

    • 跨设备布局验证
    • 功能兼容性检查
    • 渲染一致性对比
    • 系统版本降级测试

2.3 测试用例层

职责: 组织和管理所有移动端测试用例

核心组件:

  1. 性能测试套件 (PerformanceTestSuite)

    • 首屏加载性能测试
    • 页面交互响应测试
    • 资源加载优化测试
    • 内存泄漏检测测试
    • 每个测试用例设置明确的性能阈值
  2. 兼容性测试套件 (CompatibilityTestSuite)

    • 不同屏幕尺寸的布局适配测试
    • 不同操作系统的功能兼容性测试
    • 不同浏览器的渲染一致性测试
    • 不同系统版本的功能降级测试
    • 采用参数化测试方式
  3. 手势交互测试套件 (GestureTestSuite)

    • 单指滑动测试(页面滚动、轮播图切换)
    • 双指捏合缩放测试(图片查看、地图缩放)
    • 长按操作测试(上下文菜单、多选操作)
    • 双击操作测试(图片放大、点赞功能)
    • 拖拽操作测试(卡片排序、元素移动)
  4. PWA 功能测试套件 (PWATestSuite)

    • Service Worker 注册测试
    • 离线缓存功能测试
    • 应用安装测试
    • 推送通知测试
    • 应用更新测试

2.4 测试执行层

职责: 管理测试的执行、调度和报告

核心组件:

  1. 测试配置扩展

    • 扩展现有 Playwright 配置
    • 增加移动设备项目配置
    • 增加网络环境项目配置
    • 增加性能测试专用项目配置
    • 支持动态设备选择和网络条件切换
  2. 并行测试策略

    • 设备级并行(不同设备上的测试用例同时执行)
    • 网络条件级并行(同一设备在不同网络条件下并行测试)
    • 智能测试调度(根据依赖关系和资源使用优化执行顺序)
    • 显著缩短测试执行时间
  3. 测试报告系统

    • 移动端测试概览(通过率、失败率、执行时间)
    • 设备兼容性报告(每个设备上的测试结果对比)
    • 性能分析报告(Core Web Vitals 趋势、性能回归检测)
    • 网络环境影响报告(不同网络条件下的性能对比)
    • 支持多种输出格式(HTML、JSON、JUnit

3. 详细设计

3.1 测试数据层详细设计

3.1.1 移动端测试数据生成器

文件位置: e2e/src/utils/MobileTestDataGenerator.ts

核心功能:

export class MobileTestDataGenerator {
  // 生成设备特定的 User Agent
  static generateUserAgent(device: string): string;
  
  // 生成触摸事件数据
  static generateTouchEvent(type: 'tap' | 'swipe' | 'pinch' | 'longPress'): TouchEventData;
  
  // 生成网络配置数据
  static generateNetworkConfig(type: '2G' | '3G' | '4G' | 'WiFi' | 'offline'): NetworkConfig;
  
  // 生成性能基准数据
  static generatePerformanceBaseline(device: string): PerformanceBaseline;
  
  // 生成手势测试数据
  static generateGestureData(gesture: GestureType): GestureData;
}

3.1.2 扩展设备配置

文件位置: e2e/src/utils/devices.ts

新增设备配置:

export const devices: Record<string, DeviceConfig> = {
  // 现有设备配置...
  
  // 新增 iPhone 系列
  'iphone-13-pro': {
    name: 'iPhone 13 Pro',
    viewport: { width: 390, height: 844 },
    userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X)...',
    isMobile: true,
    deviceScaleFactor: 3,
  },
  'iphone-14-pro': {
    name: 'iPhone 14 Pro',
    viewport: { width: 393, height: 852 },
    userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X)...',
    isMobile: true,
    deviceScaleFactor: 3,
  },
  'iphone-15-pro': {
    name: 'iPhone 15 Pro',
    viewport: { width: 393, height: 852 },
    userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)...',
    isMobile: true,
    deviceScaleFactor: 3,
  },
  
  // 新增 Android 系列
  'pixel-7': {
    name: 'Google Pixel 7',
    viewport: { width: 412, height: 915 },
    userAgent: 'Mozilla/5.0 (Linux; Android 13; Pixel 7)...',
    isMobile: true,
    deviceScaleFactor: 2.625,
  },
  'samsung-galaxy-s23': {
    name: 'Samsung Galaxy S23',
    viewport: { width: 360, height: 780 },
    userAgent: 'Mozilla/5.0 (Linux; Android 13; SM-S911B)...',
    isMobile: true,
    deviceScaleFactor: 3,
  },
  
  // 新增 iPad 系列
  'ipad-air': {
    name: 'iPad Air',
    viewport: { width: 820, height: 1180 },
    userAgent: 'Mozilla/5.0 (iPad; CPU OS 16_0 like Mac OS X)...',
    isMobile: true,
    deviceScaleFactor: 2,
  },
  'ipad-pro-12-9': {
    name: 'iPad Pro 12.9"',
    viewport: { width: 1024, height: 1366 },
    userAgent: 'Mozilla/5.0 (iPad; CPU OS 16_0 like Mac OS X)...',
    isMobile: true,
    deviceScaleFactor: 2,
  },
};

3.1.3 网络配置数据

文件位置: e2e/src/config/network-configs.ts

网络配置示例:

export const networkConfigs: Record<string, NetworkConfig> = {
  '2g-slow': {
    name: '2G Slow',
    offline: false,
    downloadThroughput: 250 * 1024, // 250 Kbps
    uploadThroughput: 50 * 1024,   // 50 Kbps
    latency: 2000,                 // 2000ms
  },
  '3g-fast': {
    name: '3G Fast',
    offline: false,
    downloadThroughput: 1.6 * 1024 * 1024, // 1.6 Mbps
    uploadThroughput: 750 * 1024,          // 750 Kbps
    latency: 100,                          // 100ms
  },
  '4g-lte': {
    name: '4G LTE',
    offline: false,
    downloadThroughput: 4 * 1024 * 1024, // 4 Mbps
    uploadThroughput: 3 * 1024 * 1024,  // 3 Mbps
    latency: 20,                        // 20ms
  },
  'wifi-fast': {
    name: 'WiFi Fast',
    offline: false,
    downloadThroughput: 30 * 1024 * 1024, // 30 Mbps
    uploadThroughput: 15 * 1024 * 1024,  // 15 Mbps
    latency: 2,                          // 2ms
  },
  'offline': {
    name: 'Offline',
    offline: true,
  },
};

3.2 测试工具层详细设计

3.2.1 手势模拟器

文件位置: e2e/src/utils/GestureSimulator.ts

核心功能:

export class GestureSimulator {
  constructor(private page: Page) {}
  
  // 单指滑动
  async swipe(options: SwipeOptions): Promise<void>;
  
  // 双指捏合缩放
  async pinch(options: PinchOptions): Promise<void>;
  
  // 长按
  async longPress(element: Locator, duration: number): Promise<void>;
  
  // 双击
  async doubleTap(element: Locator): Promise<void>;
  
  // 拖拽
  async drag(options: DragOptions): Promise<void>;
  
  // 快速滑动(用于刷新)
  async quickSwipeDown(): Promise<void>;
  
  // 慢速滑动(用于浏览)
  async slowSwipeUp(): Promise<void>;
}

使用示例:

const gestureSimulator = new GestureSimulator(page);

// 向上滑动页面
await gestureSimulator.swipe({
  startX: 200,
  startY: 600,
  endX: 200,
  endY: 200,
  duration: 500,
});

// 双指缩放图片
await gestureSimulator.pinch({
  centerX: 200,
  centerY: 300,
  startDistance: 100,
  endDistance: 50,
  duration: 300,
});

// 长按元素
await gestureSimulator.longPress(page.locator('.card'), 1000);

3.2.2 网络环境模拟器

文件位置: e2e/src/utils/NetworkSimulator.ts

核心功能:

export class NetworkSimulator {
  constructor(private context: BrowserContext) {}
  
  // 设置网络条件
  async setNetworkCondition(config: NetworkConfig): Promise<void>;
  
  // 切换到离线模式
  async goOffline(): Promise<void>;
  
  // 切换到在线模式
  async goOnline(): Promise<void>;
  
  // 模拟网络切换
  async simulateNetworkSwitch(fromConfig: NetworkConfig, toConfig: NetworkConfig): Promise<void>;
  
  // 重置网络条件
  async resetNetworkCondition(): Promise<void>;
  
  // 监控网络请求
  async monitorNetworkRequests(): Promise<NetworkRequest[]>;
}

使用示例:

const networkSimulator = new NetworkSimulator(context);

// 设置 3G 网络条件
await networkSimulator.setNetworkCondition(networkConfigs['3g-fast']);

// 测试弱网环境下的页面加载
await page.goto('/');

// 切换到离线模式
await networkSimulator.goOffline();

// 验证离线缓存功能
await expect(page.locator('.offline-content')).toBeVisible();

// 恢复在线
await networkSimulator.goOnline();

3.2.3 性能监控器

文件位置: e2e/src/utils/MobilePerformanceMonitor.ts

核心功能:

export class MobilePerformanceMonitor {
  constructor(private page: Page) {}
  
  // 运行 Lighthouse 性能测试
  async runLighthouseAudit(options: LighthouseOptions): Promise<LighthouseResult>;
  
  // 获取 Core Web Vitals 指标
  async getCoreWebVitals(): Promise<CoreWebVitals>;
  
  // 检测性能回归
  async detectPerformanceRegression(baseline: PerformanceBaseline): Promise<RegressionReport>;
  
  // 生成性能报告
  async generatePerformanceReport(): Promise<PerformanceReport>;
  
  // 监控资源加载
  async monitorResourceLoading(): Promise<ResourceLoadingMetrics>;
  
  // 监控内存使用
  async monitorMemoryUsage(): Promise<MemoryMetrics>;
}

使用示例:

const performanceMonitor = new MobilePerformanceMonitor(page);

// 运行 Lighthouse 审计
const lighthouseResult = await performanceMonitor.runLighthouseAudit({
  onlyAudits: ['first-contentful-paint', 'largest-contentful-paint', 'cumulative-layout-shift'],
});

// 获取 Core Web Vitals
const vitals = await performanceMonitor.getCoreWebVitals();
expect(vitals.LCP).toBeLessThan(2500);
expect(vitals.CLS).toBeLessThan(0.1);

// 检测性能回归
const regressionReport = await performanceMonitor.detectPerformanceRegression(baseline);
expect(regressionReport.hasRegression).toBe(false);

3.3 测试用例层详细设计

3.3.1 性能测试套件

文件位置: e2e/src/tests/mobile/performance/mobile-performance.spec.ts

测试用例结构:

test.describe('移动端性能测试 @mobile @performance', () => {
  const devices = getMobileDevices();
  const networkConfigs = ['wifi-fast', '4g-lte', '3g-fast', '2g-slow'];
  
  for (const device of devices) {
    for (const network of networkConfigs) {
      test(`${device.name} - ${network} - 首屏加载性能`, async ({ page, context }) => {
        // 设置设备和网络条件
        await page.setViewportSize(device.viewport);
        await new NetworkSimulator(context).setNetworkCondition(networkConfigs[network]);
        
        // 运行性能测试
        const monitor = new MobilePerformanceMonitor(page);
        await page.goto('/');
        
        const vitals = await monitor.getCoreWebVitals();
        
        // 验证性能指标
        expect(vitals.LCP).toBeLessThan(getPerformanceThreshold(device.name, network, 'LCP'));
        expect(vitals.FCP).toBeLessThan(getPerformanceThreshold(device.name, network, 'FCP'));
        expect(vitals.CLS).toBeLessThan(getPerformanceThreshold(device.name, network, 'CLS'));
      });
    }
  }
  
  test('移动端 - 交互响应性能', async ({ page }) => {
    await page.setViewportSize({ width: 375, height: 667 });
    await page.goto('/');
    
    const monitor = new MobilePerformanceMonitor(page);
    
    // 测量点击响应时间
    const button = page.locator('button').first();
    const startTime = Date.now();
    await button.click();
    const responseTime = Date.now() - startTime;
    
    expect(responseTime).toBeLessThan(100);
  });
  
  test('移动端 - 内存泄漏检测', async ({ page }) => {
    await page.setViewportSize({ width: 375, height: 667 });
    await page.goto('/');
    
    const monitor = new MobilePerformanceMonitor(page);
    
    // 执行多次页面导航
    const initialMemory = await monitor.monitorMemoryUsage();
    for (let i = 0; i < 10; i++) {
      await page.goto('/about');
      await page.goto('/');
    }
    const finalMemory = await monitor.monitorMemoryUsage();
    
    // 验证内存增长在合理范围内
    const memoryGrowth = finalMemory.usedJSHeapSize - initialMemory.usedJSHeapSize;
    expect(memoryGrowth).toBeLessThan(10 * 1024 * 1024); // 10MB
  });
});

3.3.2 兼容性测试套件

文件位置: e2e/src/tests/mobile/compatibility/device-compatibility.spec.ts

测试用例结构:

test.describe('移动端兼容性测试 @mobile @compatibility', () => {
  const devices = getMobileDevices();
  
  for (const device of devices) {
    test.describe(`${device.name} 兼容性`, () => {
      test('布局适配正确', async ({ page }) => {
        await page.setViewportSize(device.viewport);
        await page.goto('/');
        
        // 验证关键元素可见
        await expect(page.locator('header')).toBeVisible();
        await expect(page.locator('main')).toBeVisible();
        await expect(page.locator('footer')).toBeVisible();
        
        // 验证布局没有溢出
        const bodyWidth = await page.evaluate(() => document.body.scrollWidth);
        const viewportWidth = device.viewport.width;
        expect(bodyWidth).toBeLessThanOrEqual(viewportWidth);
      });
      
      test('导航功能正常', async ({ page }) => {
        await page.setViewportSize(device.viewport);
        await page.goto('/');
        
        // 测试移动菜单
        const menuButton = page.locator('button[aria-label="打开菜单"]');
        if (await menuButton.isVisible()) {
          await menuButton.click();
          await expect(page.locator('#mobile-menu')).toBeVisible();
        }
        
        // 测试页面导航
        await page.goto('/about');
        await expect(page).toHaveURL(/.*about.*/);
      });
      
      test('表单功能正常', async ({ page }) => {
        await page.setViewportSize(device.viewport);
        await page.goto('/contact');
        
        // 测试表单输入
        const nameInput = page.locator('input[name="name"]');
        await nameInput.fill('测试用户');
        
        const nameValue = await nameInput.inputValue();
        expect(nameValue).toBe('测试用户');
      });
    });
  }
  
  test('跨设备布局一致性', async ({ page }) => {
    const screenshots: Buffer[] = [];
    
    for (const device of devices) {
      await page.setViewportSize(device.viewport);
      await page.goto('/');
      await page.waitForLoadState('networkidle');
      
      const screenshot = await page.screenshot();
      screenshots.push(screenshot);
    }
    
    // 对比截图,验证布局一致性
    for (let i = 1; i < screenshots.length; i++) {
      const similarity = await compareImages(screenshots[0], screenshots[i]);
      expect(similarity).toBeGreaterThan(0.85); // 85% 相似度
    }
  });
});

3.3.3 手势交互测试套件

文件位置: e2e/src/tests/mobile/gesture/gesture-interaction.spec.ts

测试用例结构:

test.describe('移动端手势交互测试 @mobile @gesture', () => {
  let gestureSimulator: GestureSimulator;
  
  test.beforeEach(async ({ page }) => {
    await page.setViewportSize({ width: 375, height: 667 });
    gestureSimulator = new GestureSimulator(page);
  });
  
  test('单指滑动 - 页面滚动', async ({ page }) => {
    await page.goto('/');
    
    const initialScrollY = await page.evaluate(() => window.scrollY);
    expect(initialScrollY).toBe(0);
    
    // 向上滑动
    await gestureSimulator.swipe({
      startX: 200,
      startY: 600,
      endX: 200,
      endY: 200,
      duration: 500,
    });
    
    const afterScrollY = await page.evaluate(() => window.scrollY);
    expect(afterScrollY).toBeGreaterThan(0);
  });
  
  test('双指捏合 - 图片缩放', async ({ page }) => {
    await page.goto('/products');
    
    const image = page.locator('.product-image').first();
    await image.click();
    
    // 双指放大
    await gestureSimulator.pinch({
      centerX: 200,
      centerY: 300,
      startDistance: 100,
      endDistance: 50,
      duration: 300,
    });
    
    // 验证图片已放大
    const transform = await image.evaluate((el) => {
      const style = window.getComputedStyle(el);
      return style.transform;
    });
    expect(transform).toContain('scale');
  });
  
  test('长按 - 上下文菜单', async ({ page }) => {
    await page.goto('/');
    
    const card = page.locator('.card').first();
    
    // 长按卡片
    await gestureSimulator.longPress(card, 1000);
    
    // 验证上下文菜单出现
    await expect(page.locator('.context-menu')).toBeVisible();
  });
  
  test('双击 - 图片放大', async ({ page }) => {
    await page.goto('/products');
    
    const image = page.locator('.product-image').first();
    
    // 双击图片
    await gestureSimulator.doubleTap(image);
    
    // 验证图片已放大
    const transform = await image.evaluate((el) => {
      const style = window.getComputedStyle(el);
      return style.transform;
    });
    expect(transform).toContain('scale');
  });
  
  test('拖拽 - 卡片排序', async ({ page }) => {
    await page.goto('/products');
    
    const firstCard = page.locator('.card').first();
    const secondCard = page.locator('.card').nth(1);
    
    const firstCardInitialPosition = await firstCard.boundingBox();
    
    // 拖拽第一个卡片到第二个卡片位置
    await gestureSimulator.drag({
      source: firstCard,
      target: secondCard,
      duration: 500,
    });
    
    // 验证卡片位置已改变
    const firstCardFinalPosition = await firstCard.boundingBox();
    expect(firstCardFinalPosition.y).toBeGreaterThan(firstCardInitialPosition.y);
  });
  
  test('快速滑动 - 下拉刷新', async ({ page }) => {
    await page.goto('/news');
    
    // 快速向下滑动
    await gestureSimulator.quickSwipeDown();
    
    // 验证刷新指示器出现
    await expect(page.locator('.refresh-indicator')).toBeVisible();
    
    // 等待刷新完成
    await page.waitForSelector('.refresh-indicator', { state: 'hidden', timeout: 5000 });
  });
});

3.3.4 PWA 功能测试套件

文件位置: e2e/src/tests/mobile/pwa/pwa-functionality.spec.ts

测试用例结构:

test.describe('移动端 PWA 功能测试 @mobile @pwa', () => {
  test('Service Worker 注册成功', async ({ page }) => {
    await page.goto('/');
    
    // 等待 Service Worker 注册
    const swRegistration = await page.evaluate(() => {
      return navigator.serviceWorker.getRegistration();
    });
    
    expect(swRegistration).toBeTruthy();
  });
  
  test('离线缓存功能正常', async ({ page, context }) => {
    // 首次访问,缓存资源
    await page.goto('/');
    await page.waitForLoadState('networkidle');
    
    // 切换到离线模式
    await context.setOffline(true);
    
    // 刷新页面,应该从缓存加载
    await page.reload();
    await expect(page.locator('header')).toBeVisible();
    await expect(page.locator('main')).toBeVisible();
    
    // 恢复在线
    await context.setOffline(false);
  });
  
  test('应用安装提示出现', async ({ page }) => {
    await page.goto('/');
    
    // 检查是否有安装提示
    const installPrompt = await page.evaluate(() => {
      return 'beforeinstallprompt' in window;
    });
    
    expect(installPrompt).toBe(true);
  });
  
  test('离线页面显示正确', async ({ page, context }) => {
    // 首次访问
    await page.goto('/');
    await page.waitForLoadState('networkidle');
    
    // 切换到离线模式
    await context.setOffline(true);
    
    // 访问未缓存的页面
    await page.goto('/non-existent-page');
    
    // 验证显示离线页面
    await expect(page.locator('.offline-page')).toBeVisible();
  });
  
  test('应用更新检测正常', async ({ page }) => {
    await page.goto('/');
    
    // 模拟应用更新
    await page.evaluate(() => {
      window.dispatchEvent(new Event('sw-update'));
    });
    
    // 验证更新提示出现
    await expect(page.locator('.update-notification')).toBeVisible();
  });
});

3.4 测试执行层详细设计

3.4.1 测试配置扩展

文件位置: e2e/playwright.config.ts

扩展配置:

import { defineConfig, devices } from '@playwright/test';
import { getEnvironment } from './src/config/environments';
import { getMobileDevices } from './src/utils/devices';

const env = getEnvironment();
const mobileDevices = getMobileDevices();

export default defineConfig({
  testDir: './src/tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: env.retries,
  workers: process.env.CI ? 4 : undefined,
  reporter: [
    ['html', { open: 'never' }],
    ['json', { outputFile: 'test-results/results.json' }],
    ['junit', { outputFile: 'test-results/junit.xml' }],
    ['line'],
    ['list'],
    ['allure-playwright', {
      outputFolder: 'allure-results',
      detail: true,
      suiteTitle: false,
    }],
  ],
  timeout: env.timeout,
  expect: {
    timeout: 30000
  },
  use: {
    baseURL: env.baseURL,
    trace: env.trace,
    screenshot: env.screenshot,
    video: env.video,
    headless: env.headless,
    viewport: { width: 1280, height: 720 },
    actionTimeout: 30000,
    navigationTimeout: 60000,
    launchOptions: {
      slowMo: env.slowMo,
    },
  },
  projects: [
    // 桌面浏览器项目
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] },
    },
    
    // 移动设备项目
    ...mobileDevices.map(device => ({
      name: `mobile-${device.name.replace(/\s+/g, '-').toLowerCase()}`,
      use: {
        ...devices['Mobile Chrome'],
        viewport: device.viewport,
        userAgent: device.userAgent,
        deviceScaleFactor: device.deviceScaleFactor,
        isMobile: true,
      },
    })),
    
    // 性能测试项目
    {
      name: 'performance-mobile',
      use: {
        ...devices['Mobile Chrome'],
        viewport: { width: 375, height: 667 },
        isMobile: true,
      },
      testMatch: /.*\.perf\.spec\.ts/,
    },
    
    // PWA 测试项目
    {
      name: 'pwa-mobile',
      use: {
        ...devices['Mobile Chrome'],
        viewport: { width: 375, height: 667 },
        isMobile: true,
        serviceWorkers: 'allow',
      },
      testMatch: /.*\.pwa\.spec\.ts/,
    },
  ],
  webServer: env.name === 'development' ? {
    command: 'cd .. && npm run dev',
    url: 'http://localhost:3000',
    timeout: 120000,
    reuseExistingServer: !process.env.CI,
  } : undefined,
});

3.4.2 并行测试策略

文件位置: e2e/src/utils/TestScheduler.ts

核心功能:

export class TestScheduler {
  private testQueue: TestTask[] = [];
  private runningTasks: Map<string, TestTask> = new Map();
  
  // 添加测试任务
  addTest(task: TestTask): void;
  
  // 智能调度测试
  async scheduleTests(): Promise<void>;
  
  // 监控测试执行
  monitorExecution(): ExecutionStatus;
  
  // 优化执行顺序
  optimizeExecutionOrder(): TestTask[];
  
  // 获取执行统计
  getExecutionStats(): ExecutionStats;
}

调度策略:

  1. 设备级并行: 不同设备上的测试用例可以同时执行
  2. 网络条件级并行: 同一设备在不同网络条件下的测试可以并行
  3. 依赖关系优化: 根据测试依赖关系优化执行顺序
  4. 资源使用优化: 根据 CPU、内存使用情况动态调整并行度

3.4.3 测试报告系统

文件位置: e2e/src/utils/MobileTestReporter.ts

核心功能:

export class MobileTestReporter {
  // 生成移动端测试概览
  generateOverview(): TestOverview;
  
  // 生成设备兼容性报告
  generateCompatibilityReport(): CompatibilityReport;
  
  // 生成性能分析报告
  generatePerformanceReport(): PerformanceReport;
  
  // 生成网络环境影响报告
  generateNetworkImpactReport(): NetworkImpactReport;
  
  // 生成 HTML 报告
  generateHtmlReport(): string;
  
  // 生成 JSON 报告
  generateJsonReport(): object;
  
  // 生成 JUnit 报告
  generateJUnitReport(): string;
}

报告内容:

  1. 移动端测试概览

    • 总体通过率
    • 各设备测试结果
    • 执行时间统计
    • 失败用例分析
  2. 设备兼容性报告

    • 每个设备上的测试结果对比
    • 兼容性问题汇总
    • 布局差异截图
    • 功能降级情况
  3. 性能分析报告

    • Core Web Vitals 指标趋势
    • 性能回归检测结果
    • 资源加载分析
    • 性能优化建议
  4. 网络环境影响报告

    • 不同网络条件下的性能对比
    • 离线功能验证结果
    • 网络切换测试结果
    • 弱网优化建议

4. 实施计划

4.1 第一阶段:基础设施扩展(优先级:高)

时间: 1-2 周

任务:

  1. 扩展设备配置

    • 添加 iPhone 13/14/15 系列配置
    • 添加 Samsung Galaxy 系列配置
    • 添加 Google Pixel 系列配置
    • 添加 iPad Air/Pro 系列配置
    • 更新设备选择工具函数
  2. 建立移动端测试数据生成器

    • 创建 MobileTestDataGenerator
    • 实现设备特定数据生成
    • 实现网络配置数据生成
    • 实现性能基准数据生成
  3. 扩展 Playwright 配置

    • 添加移动设备测试项目
    • 配置性能测试项目
    • 配置 PWA 测试项目
    • 优化并行执行策略

验收标准:

  • 所有新设备配置正确
  • 测试数据生成器功能完整
  • Playwright 配置支持多设备并行测试

4.2 第二阶段:核心测试工具开发(优先级:高)

时间: 2-3 周

任务:

  1. 开发手势模拟器

    • 实现 GestureSimulator
    • 实现单指滑动功能
    • 实现双指捏合功能
    • 实现长按功能
    • 实现双击功能
    • 实现拖拽功能
    • 编写使用文档和示例
  2. 开发网络环境模拟器

    • 实现 NetworkSimulator
    • 实现网络条件设置
    • 实现离线模式切换
    • 实现网络切换模拟
    • 实现网络请求监控
    • 编写使用文档和示例
  3. 集成 Lighthouse 性能测试

    • 实现 MobilePerformanceMonitor
    • 集成 Lighthouse API
    • 实现 Core Web Vitals 监控
    • 实现性能回归检测
    • 实现性能报告生成
    • 编写使用文档和示例
  4. 建立移动端测试报告系统

    • 实现 MobileTestReporter
    • 实现测试概览报告
    • 实现兼容性报告
    • 实现性能分析报告
    • 实现网络影响报告
    • 支持多种输出格式

验收标准:

  • 手势模拟器支持所有基本手势
  • 网络模拟器支持所有网络场景
  • 性能监控器能准确测量 Core Web Vitals
  • 测试报告系统生成完整的移动端报告

4.3 第三阶段:测试用例开发(优先级:中)

时间: 3-4 周

任务:

  1. 开发性能测试套件

    • 首屏加载性能测试
    • 页面交互响应测试
    • 资源加载优化测试
    • 内存泄漏检测测试
    • 建立性能基准和阈值
  2. 开发兼容性测试套件

    • 不同屏幕尺寸布局测试
    • 不同操作系统功能测试
    • 不同浏览器渲染测试
    • 不同系统版本降级测试
    • 建立设备测试矩阵
  3. 开发手势交互测试套件

    • 单指滑动测试
    • 双指捏合缩放测试
    • 长按操作测试
    • 双击操作测试
    • 拖拽操作测试
  4. 开发 PWA 功能测试套件

    • Service Worker 注册测试
    • 离线缓存功能测试
    • 应用安装测试
    • 推送通知测试
    • 应用更新测试

验收标准:

  • 所有测试用例通过
  • 测试覆盖率达到预期目标
  • 测试执行时间在可接受范围内

4.4 第四阶段:高级功能和优化(优先级:低)

时间: 2-3 周

任务:

  1. 开发复杂手势模拟器

    • 实现三指手势
    • 实现复杂手势组合
    • 优化手势识别算法
  2. 完善网络环境模拟

    • 实现网络丢包模拟
    • 实现网络抖动模拟
    • 实现自定义网络配置
  3. 建立 PWA 功能测试套件

    • 完善离线功能测试
    • 完善推送通知测试
    • 完善应用更新测试
  4. 优化测试执行效率

    • 实现智能测试调度
    • 优化并行执行策略
    • 实现测试缓存机制
  5. 完善测试报告系统

    • 优化报告可视化
    • 添加趋势分析
    • 添加性能对比功能

验收标准:

  • 所有高级功能正常工作
  • 测试执行效率提升 30% 以上
  • 测试报告更加直观和有用

5. 技术栈

5.1 核心技术

  • 测试框架: Playwright
  • 性能测试: Lighthouse
  • 网络模拟: Chrome DevTools Protocol
  • 报告生成: Allure、HTML、JSON、JUnit
  • 类型系统: TypeScript

5.2 依赖包

{
  "dependencies": {
    "@playwright/test": "^1.40.0",
    "lighthouse": "^11.0.0",
    "chrome-remote-interface": "^0.33.0",
    "@types/lighthouse": "^11.0.0"
  }
}

5.3 开发工具

  • 代码编辑器: VS Code
  • 版本控制: Git
  • 包管理器: npm
  • 构建工具: TypeScript Compiler

6. 成功标准

6.1 功能完整性

  • 支持所有主流移动设备(iPhone、Android、iPad
  • 支持所有基本手势操作(滑动、点击、长按、双击、拖拽)
  • 支持所有网络条件(在线、离线、弱网、网络切换)
  • 支持所有 Core Web Vitals 指标监控
  • 支持完整的 PWA 功能测试

6.2 测试覆盖率

  • 移动端功能测试覆盖率 ≥ 80%
  • 移动端性能测试覆盖率 ≥ 70%
  • 移动端兼容性测试覆盖率 ≥ 90%
  • 移动端 PWA 功能测试覆盖率 ≥ 85%

6.3 性能指标

  • 测试执行时间 ≤ 30 分钟(完整测试套件)
  • 测试通过率 ≥ 95%
  • 性能回归检测准确率 ≥ 90%
  • 测试报告生成时间 ≤ 1 分钟

6.4 可维护性

  • 代码覆盖率 ≥ 80%
  • 文档完整性 ≥ 90%
  • 代码审查通过率 100%
  • 技术债务控制良好

7. 风险和挑战

7.1 技术风险

  1. Playwright 限制

    • 风险: 某些高级手势可能无法完美模拟
    • 缓解: 优先实现基本手势,高级手势作为可选功能
  2. 网络模拟准确性

    • 风险: 模拟的网络条件可能与真实网络有差异
    • 缓解: 使用真实设备进行验证和校准
  3. 性能测试稳定性

    • 风险: 性能测试结果可能受环境影响
    • 缓解: 建立稳定的测试环境,多次测试取平均值

7.2 项目风险

  1. 时间压力

    • 风险: 项目时间可能紧张
    • 缓解: 采用敏捷开发,优先实现高优先级功能
  2. 资源限制

    • 风险: 开发资源可能不足
    • 缓解: 合理分配资源,必要时调整优先级
  3. 需求变更

    • 风险: 需求可能在开发过程中变更
    • 缓解: 采用迭代开发,及时响应需求变更

8. 后续优化方向

8.1 短期优化(1-3 个月)

  1. 真实设备集成

    • 集成 BrowserStack 或 Sauce Labs
    • 支持真实设备测试
    • 建立设备云管理
  2. 测试数据管理

    • 建立测试数据仓库
    • 支持数据版本控制
    • 实现数据复用机制
  3. 测试结果分析

    • 建立测试结果趋势分析
    • 实现智能问题诊断
    • 提供优化建议

8.2 中期优化(3-6 个月)

  1. AI 辅助测试

    • 使用 AI 生成测试用例
    • 智能测试用例选择
    • 自动化问题定位
  2. 测试平台化

    • 构建测试管理平台
    • 支持测试计划管理
    • 实现测试资源调度
  3. 持续监控

    • 建立生产环境监控
    • 实现实时性能监控
    • 集成告警机制

8.3 长期优化(6-12 个月)

  1. 测试即代码

    • 将测试代码与生产代码同等对待
    • 建立测试代码审查机制
    • 实现测试代码质量监控
  2. 测试左移

    • 在需求分析阶段引入测试
    • 实现测试驱动开发
    • 建立质量门禁
  3. 测试右移

    • 在生产环境进行测试
    • 实现金丝雀发布
    • 建立快速回滚机制

9. 总结

本设计文档详细描述了移动端测试完善方案的整体架构、详细设计、实施计划和技术栈。通过四个阶段的实施,我们将建立一个全面完善的移动端测试体系,覆盖性能、兼容性、手势交互、PWA 功能等方面。

该方案具有以下优势:

  1. 渐进式实施: 在现有框架基础上逐步扩展,风险可控
  2. 全面覆盖: 覆盖移动端测试的所有重要方面
  3. 可扩展性: 架构设计支持后续功能扩展
  4. 可维护性: 代码结构清晰,易于维护和优化

通过实施本方案,我们将显著提升移动端测试的质量和效率,为用户提供更好的移动端体验。


文档版本: 1.0
最后更新: 2026-03-05
文档状态: 待审核