mcpField
P
patrol-e2e-testing

patrol-e2e-testing

github.com/evanca测试与质量663206 次安装3 周前更新
代码仓库

关于 patrol-e2e-testing

面向 Flutter 项目使用 Patrol 4.x 设计、编写和运行端到端测试的技能,指导测试结构、原生交互与稳定执行。

主要功能

  1. 01Patrol 测试结构与约定
  2. 02控件选择与交互
  3. 03原生对话框自动化
  4. 04显式等待与稳定化
  5. 05按目标、设备或标签运行测试

适用场景

  1. 01覆盖新页面或用户流程
  2. 02测试权限与系统对话框
  3. 03验证跨平台行为
  4. 04将 UI 缺陷转为回归测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/evanca/flutter-ai-rules --skill patrol-e2e-testing

安装后在 Claude Code 中输入/patrol-e2e-testing确认已加载。

详细介绍

Patrol 端到端测试技能

在 Flutter 项目中使用 Patrol 4.x 设计、实现和运行端到端(E2E)测试。

适用场景

在以下情况下使用此技能:

  • 新屏幕或用户流程需要 E2E 测试覆盖。
  • 某项功能会与原生组件交互(权限、通知、系统对话框、深层链接)。
  • 需要将 UI 错误记录为回归测试。
  • 必须验证跨平台行为(Android / iOS / Web)。
  • 在新的或现有的 Flutter 项目中设置 Patrol。

设置

按照 Patrol 官方文档进行安装和项目初始化: https://patrol.leancode.co/documentation#setup

Patrol 的关键约定:

  • 将 patrol 添加为开发依赖项。
  • 将测试放在 patrol_test/ 中。
  • 测试文件名以 _test.dart 结尾。
  • 使用 patrol test 执行测试。

工作流

实现或更新 Patrol 测试时,请遵循以下步骤。

1. 确定用户流程

将功能拆分为:

  • 操作:点击、滚动、输入、导航、深层链接。
  • 可观察结果:可见文本、屏幕变化、已启用的按钮、对话框。

规则:

  • 每个主要(顺利完成)流程编写一个测试。
  • 为关键边缘情况单独编写测试。
  • 避免在单个测试中组合不相关的流程。
2. 构建 Patrol 测试

Patrol 的基本结构:

import 'package:flutter_test/flutter_test.dart';
import 'package:patrol/patrol.dart';

void main() {
  patrolTest(
    'user can log in successfully',
    ($) async {
      await $.pumpWidgetAndSettle(const MyApp());

      const email = String.fromEnvironment('E2E_EMAIL');
      const password = String.fromEnvironment('E2E_PASSWORD');

      await $(#emailField).enterText(email);
      await $(#passwordField).enterText(password);
      await $(#loginButton).tap();

      await $.waitUntilVisible($(#homeScreenTitle));

      expect($(#homeScreenTitle).text, equals('Welcome'));
    },
  );
}

关键概念:

  • 使用 patrolTest(),而不是 testWidgets()。
  • $ 是 Patrol 测试器。
  • 使用 $(#keyName) 按 Key 查找 Widget。
  • 使用明确的等待条件(例如,waitUntilVisible)。
3. 处理原生对话框

对于操作系统级权限对话框:

patrolTest('grants camera permission', ($) async {
  await $.pumpWidgetAndSettle(const MyApp());

  await $(#openCameraButton).tap();

  if (await $.native.isPermissionDialogVisible()) {
    await $.native.grantPermission();
  }

  await $.waitUntilVisible($(#cameraPreview));
});

仅在功能需要时使用原生自动化。

4. 选择器和交互速查

查找 Widget:

$('some text')        // by text
$(TextField)          // by type
$(Icons.arrow_back)   // by icon

点击:

// Tap a widget containing a specific text label
await $(Container).$('click').tap();

// Tap a container that contains an ElevatedButton
await $(Container).containing(ElevatedButton).tap();

// Tap only the enabled ElevatedButton
await $(ElevatedButton)
    .which<ElevatedButton>(
      (b) => b.enabled,
    )
    .tap();

输入文本:

// Enter text into the second TextField on screen
await $(TextField).at(1).enterText('your input');

滚动:

await $(widget_you_want_to_scroll_to).scrollTo();

原生交互:

// Grant permission while app is in use
await $.native.grantPermissionWhenInUse();

// Open notification shade and tap a notification by text
await $.native.openNotifications();
await $.native.tapOnNotificationBySelector(
  Selector(textContains: 'text'),
);
5. 运行 Patrol 测试

运行所有测试:

patrol test

在开发模式下运行指定文件并启用热重载:

patrol develop -t integration_test/my_test.dart

运行指定文件:

patrol test --target patrol_test/login_test.dart

在 Web 上运行:

patrol test --device chrome

无头 Web(CI):

patrol test --device chrome --web-headless true

按标签筛选:

patrol test --tags android
6. 稳定性模式

不稳定的测试会削弱信心。请采用以下模式:

// AVOID — arbitrary delay
await Future.delayed(Duration(seconds: 3));

// PREFER — explicit wait condition
await $.waitUntilVisible($(#targetWidget));

// For animations, pump until settled
await $.pumpAndSettle();
  • 切勿使用 Future.delayed 作为同步机制。
  • 使用 waitUntilVisible 或 waitUntilExists 等待 UI 状态。
  • 在 PatrolTesterConfig 中设置 settleTimeout,以适应速度较慢的 CI 环境。
输出要求

应用此技能后,应产出:

  1. 覆盖指定功能的 Patrol 测试。
  2. 在生产代码中添加任何必需的 Widget Key。
  3. 可在本地执行的准确 patrol test 命令。
  4. 说明稳定性或时序决策的备注。

检查点: 提交前,在本地运行 patrol test --target <file>,确认测试通过。

质量标准

有效的 Patrol 测试必须:

  • 确定性强——不使用任意延迟;采用明确的等待条件。
  • 易于阅读——测试名称清楚描述用户流程。
  • 精简但完整——每个流程包含一条断言链。
  • 保护机密——凭据通过 String.fromEnvironment 加载,绝不硬编码。
  • 可用于 CI——能够使用 --web-headless true 在无头模式下通过,或在模拟器上通过。

评论

支持 Markdown