关于 patrol-e2e-testing
面向 Flutter 项目使用 Patrol 4.x 设计、编写和运行端到端测试的技能,指导测试结构、原生交互与稳定执行。
主要功能
- 01Patrol 测试结构与约定
- 02控件选择与交互
- 03原生对话框自动化
- 04显式等待与稳定化
- 05按目标、设备或标签运行测试
适用场景
- 01覆盖新页面或用户流程
- 02测试权限与系统对话框
- 03验证跨平台行为
- 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 环境。
输出要求
应用此技能后,应产出:
- 覆盖指定功能的 Patrol 测试。
- 在生产代码中添加任何必需的 Widget
Key。 - 可在本地执行的准确
patrol test命令。 - 说明稳定性或时序决策的备注。
检查点: 提交前,在本地运行 patrol test --target <file>,确认测试通过。
质量标准
有效的 Patrol 测试必须:
- 确定性强——不使用任意延迟;采用明确的等待条件。
- 易于阅读——测试名称清楚描述用户流程。
- 精简但完整——每个流程包含一条断言链。
- 保护机密——凭据通过
String.fromEnvironment加载,绝不硬编码。 - 可用于 CI——能够使用
--web-headless true在无头模式下通过,或在模拟器上通过。
评论
支持 Markdown