Files
gym-manage/e2e-tests/docs/miniapp-test.md
T

10 KiB
Raw Blame History

小程序端 — 测试文档

位置: gym-manage-uniapp/e2e/ | 框架: Jest + miniprogram-automator | 用例数: 7 | 通过率: 100%


一、概览

小程序端 E2E 测试基于 miniprogram-automator(微信官方自动化工具),在微信开发者工具中运行,模拟用户操作并验证页面行为。

维度
测试框架 Jest 29 + miniprogram-automator
目标环境 微信小程序(微信开发者工具)
测试文件数 1 配置文件 + 3 测试套件 + 5 Page Object + 2 辅助
测试用例数 7
通过率 100%
运行命令 npx jest --config e2e/jest.config.js

二、测试套件详览

2.1 冒烟测试 — smoke/app-launch.spec.js2 用例)

验证小程序基础启动和导航功能。

用例 测试内容
首页加载与基本内容显示 验证小程序正常启动、首页数据加载、关键元素渲染
四个 TabBar 页面导航 依次切换到:首页 → 搜索 → 我的课程 → 个人中心 → 返回首页,验证每个页面正确跳转

2.2 团课预约旅程 — journeys/booking-journey.spec.js3 用例)

验证从首页到团课预约再到扫码签到的完整流程。

用例 测试步骤
首页课程元素展示 首页加载 → 课程卡片渲染 → 验证推荐课程数据
搜索页搜索功能 切换到搜索页 → 输入"瑜伽"关键词 → 验证搜索结果绑定
预约「流瑜伽」并扫码签到 进入我的课程页 → 注入「流瑜伽」(id:2) 预约数据 → Mock wx.scanCode → 点击扫码签到按钮 → 验证签到流程完成

核心流程:预约+扫码签到详细步骤

步骤 1: 进入「我的课程」页面(TabBar 导航)
   ↓ 使用 miniProgram.switchTab('/pages/my-courses/my-courses')
   验证: page.path 包含 'my-courses'

步骤 2: 注入模拟预约数据
   ↓ 使用 miniProgram.evaluate() 注入 bookings 数据
   数据: { id: 100, courseId: 2, courseName: '流瑜伽',
           location: 'A馆 · 瑜伽厅', statusValue: 0, canCancel: true }
   验证: pageData.bookings.length > 0

步骤 3: Mock 扫码并签到
   ↓ 使用 miniProgram.mockWxMethod('scanCode', { result: QR_CONTENT })
   点击 MyCoursesPage.scanSignIn('流瑜伽')
   验证: 签到按钮点击成功,页面未崩溃

核心实现:

  • 测试课程: 流瑜伽(courseId: 2
  • 二维码内容: COURSE_QR_2(模拟 fl.png 扫码结果)
  • 绕过 API 依赖: 使用 evaluate() 直接注入页面数据,无需后端服务运行
  • Mock 微信 API: 使用 mockWxMethod('scanCode') 模拟扫码返回

2.3 个人中心旅程 — journeys/profile-journey.spec.js2 用例)

用例 测试内容
「我的课程」页面数据 切换到我的课程页 → 验证页面数据加载
「个人中心」会员信息 切换到个人中心 → 验证昵称、会员号、签到天数等展示

三、Page Object 模式(5 个文件)

文件 对应页面 核心方法
HomePage.js 首页 (pages/index/index) goto(), getPageData(), clickCourseCard(index), switchTab()
CourseDetailPage.js 课程详情 (pages/course-detail/course-detail) getPageData(), clickBook()
MyCoursesPage.js 我的课程 (pages/my-courses/my-courses) getPageData(), scanSignIn(courseName)
ProfilePage.js 个人中心 (pages/profile/profile) getPageData(), getMemberInfo()
SearchPage.js 搜索 (pages/search/search) getPageData(), search(keyword)

Page Object 核心实现细节

HomePage.clickCourseCard(index)

// 支持 .recommend-card、.course-card、.course-item 等多选择器
async clickCourseCard(index = 0) {
  const page = await this.mp.currentPage();
  const cards = await page.$$('.recommend-card, .course-card, .course-item, [class*="course"]');
  if (cards.length > index) { await cards[index].tap(); }
}

CourseDetailPage.clickBook()

// 精准定位 .booking-btn 并检查禁用状态
async clickBook() {
  const page = await this.mp.currentPage();
  const bookBtn = await page.$('.booking-btn');
  if (bookBtn) {
    const disabled = await bookBtn.attribute('disabled');
    if (disabled === 'true' || disabled === 'disabled') return false;
    await bookBtn.tap();
    return true;
  }
  return false;
}

MyCoursesPage.scanSignIn(courseName)

// 通过 page.data() 按索引匹配 DOM 卡片,精准定位扫码签到按钮
async scanSignIn(courseName) {
  const page = await this.mp.currentPage();
  // 1. 通过 page data 匹配目标课程索引
  const pageData = await page.data();
  const targetBooking = (pageData.bookings || []).find(b => b.courseName === courseName);
  const targetIndex = pageData.bookings.indexOf(targetBooking);
  // 2. 通过索引定位 DOM 卡片
  const cards = await page.$$('.booking-card');
  if (cards.length > targetIndex) {
    const signBtn = await cards[targetIndex].$('.signin-btn');
    if (signBtn) { await signBtn.tap(); return true; }
  }
  // 3. 回退:wxml 文本匹配
  // ...
}

四、测试覆盖的小程序页面路由

页面 路由 TabBar 测试内容
首页 pages/index/index 渲染、课程卡片(.recommend-card)、轮播图、今日推荐、数据获取
搜索 pages/search/search 关键词搜索"瑜伽"、输入绑定
我的课程 pages/my-courses/my-courses 预约数据注入(evaluate)、扫码签到按钮(.signin-btn
个人中心 pages/profile/profile 会员信息(昵称/头像/签到天数/待上课)、退出登录
课程详情 pages/course-detail/course-detail 从首页跳转、预约按钮(.booking-btn

五、配置与辅助文件

Jest 配置 — e2e/jest.config.js

{
  testTimeout: 120000,        // 测试超时 120 秒
  globalSetup: '<rootDir>/e2e/globalSetup.js',
  setupFilesAfterFramework: ['<rootDir>/e2e/setup.js'],
  projects: [
    { displayName: 'smoke',   testMatch: ['**/smoke/**'] },
    { displayName: 'journeys', testMatch: ['**/journeys/**'] }
  ]
}

全局初始化 — e2e/globalSetup.js

启动微信开发者工具 CLI,打开小程序项目并建立 WebSocket 连接:

module.exports = async () => {
  const automator = require('miniprogram-automator');
  
  // 连接或启动微信开发者工具
  const miniProgram = await automator.launch({
    projectPath: path.resolve(__dirname, '..'),
  });
  
  // 存储到全局,供测试使用
  global.__MINIPROGRAM__ = miniProgram;
};

测试设置 — e2e/setup.js

每个测试文件执行前的通用设置:

beforeAll(async () => {
  miniProgram = global.__MINIPROGRAM__;
  // Mock 常用微信 API
  await miniProgram.mockWxMethod('showToast', {});
  await miniProgram.mockWxMethod('showModal', { confirm: true });
});

六、测试数据

预约测试数据(注入到我的课程页)

{
  bookings: [{
    id: 100,
    courseId: 2,                    // 流瑜伽
    courseName: '流瑜伽',
    location: 'A馆 · 瑜伽厅',
    fullDate: '2026-07-21',
    shortTime: '10:00',
    endShortTime: '11:00',
    bookingTime: '2026-07-20 15:30',
    statusValue: 0,
    statusLabel: '已预约',
    checkedIn: false,
    canCancel: true
  }]
}

签到测试数据(Mock wx.scanCode

{
  result: 'COURSE_QR_2',          // 流瑜伽的二维码内容(模拟 fl.png)
  scanType: 'QR_CODE',
  charSet: 'UTF-8',
  errMsg: 'scanCode:ok'
}

二维码文件

  • 路径: d:\Work\BIG_project\week2\base13-small-uniapp\gym-manage\fl.png
  • 用途: 测试指定的团课「流瑜伽」二维码

七、环境依赖

依赖 版本 用途
miniprogram-automator ^0.10.x 微信小程序自动化驱动
Jest 29.x 测试运行器
微信开发者工具 稳定版 小程序运行载体

安装

# 安装测试依赖
npm install -D jest miniprogram-automator

# 或者
npx @wechat-miniprogram/automator-cli install

八、运行方式

前置条件

  1. 安装微信开发者工具(稳定版)
  2. 在开发者工具中打开 gym-manage-uniapp 项目
  3. 开启服务端口(设置 → 安全 → 服务端口:打开)
  4. 在 HbuilderX 中编译小程序:发行 → 小程序-微信

运行命令

# 进入小程序目录
cd gym-manage-uniapp

# 冒烟测试
npx jest --config e2e/jest.config.js --testPathPattern="smoke"

# 团课预约旅程
npx jest --config e2e/jest.config.js --testPathPattern="booking-journey"

# 个人中心旅程
npx jest --config e2e/jest.config.js --testPathPattern="profile-journey"

# 所有测试
npx jest --config e2e/jest.config.js

# 详细输出
npx jest --config e2e/jest.config.js --verbose --forceExit

九、关键设计决策

为什么不直接调用后端 API

小程序的 onLoad() 在页面加载时自动调用后端 API 获取数据。但在测试环境中:

  • 后端服务可能未运行
  • API 响应可能不稳定

因此采用 页面数据注入 (evaluate()) 策略,直接将预置数据注入到页面 data 中,绕过 API 依赖,专注于验证 UI 交互和业务流程。

为什么 Mock wx.scanCode

微信小程序的 wx.scanCode() 调用真机摄像头,无法在自动化测试中真实触发。使用 mockWxMethod() 模拟返回二维码内容,验证签到按钮点击后的逻辑链路。

索引匹配 vs wxml 匹配

scanSignIn() 通过 wxml() 方法获取 DOM 文本进行匹配,但在 UniApp 项目中 wxml() 可能不包含渲染后的文本内容。优化后先通过 page.data() 获取数据中的对应索引,再通过索引定位 DOM 元素,大幅提高测试稳定性。


文档生成时间: 2026-07-21 | 测试工具: Jest 29 + miniprogram-automator + 微信开发者工具