mcpField
P
patrol

patrol

github.com/soliplex测试与质量38 次安装
代码仓库

关于 patrol

patrol 是用于 Flutter 项目的端到端集成测试技能,面向在 macOS、iOS、Android 和 Chrome 上运行测试的开发者。它提供设备选择、测试前检查、断言模式和故障排查指导。

主要功能

  1. 01运行指定文件或全部集成测试
  2. 02支持 macOS、iOS、Android 和 Chrome
  3. 03提供测试前检查清单
  4. 04使用日志与条件等待进行断言
  5. 05提供常见故障排查指导

适用场景

  1. 01在指定设备上运行 Flutter 集成测试
  2. 02检查测试挂起或设备连接问题
  3. 03通过应用日志验证异步事件

安装

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

$npx skills add https://github.com/soliplex/flutter --skill patrol

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

setup/
android-setup.md
ios-setup.md
macos-setup.md
web-setup.md

详细介绍

Patrol 端到端测试技能

运行和管理此 Flutter 项目的 Patrol 集成测试(macOS、iOS、Android 和 Chrome)。

运行测试

CLI 位置: patrol

始终使用 --device,避免出现交互式设备选择提示。

macOS(默认)
# Run a specific test file
patrol test \
  --device macos \
  --target integration_test/$ARGUMENTS \
  --dart-define SOLIPLEX_BACKEND_URL=http://localhost:8000

# Run all integration tests
patrol test \
  --device macos \
  --target integration_test/ \
  --dart-define SOLIPLEX_BACKEND_URL=http://localhost:8000

首次设置: 有关权限和窗口限制,请参阅 macOS 设置指南。

iOS(模拟器)

使用已启动模拟器的设备 ID 或名称。--ios 标志用于指定操作系统 版本(默认为 latest,必须与模拟器的操作系统版本一致)。

# Run on a specific iOS simulator
patrol test \
  --device <DEVICE_ID> \
  --target integration_test/$ARGUMENTS \
  --dart-define SOLIPLEX_BACKEND_URL=http://localhost:8000

# If simulator OS != latest SDK, specify explicitly
patrol test \
  --device <DEVICE_ID> \
  --ios=18.6 \
  --target integration_test/$ARGUMENTS \
  --dart-define SOLIPLEX_BACKEND_URL=http://localhost:8000

使用 xcrun simctl list devices booted 查找设备 ID 和操作系统版本。

首次设置: 有关 RunnerUITests 目标和模拟器操作系统版本匹配要求,请参阅 iOS 设置指南。

Android(模拟器或设备)

需要已启动的模拟器或已连接的设备。使用 adb devices 中的名称或序列号。

# Boot emulator (if not running)
export ANDROID_HOME=~/Library/Android/sdk
export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator:$PATH"
emulator -avd Patrol_Test_API_36 &

# Run on Android emulator
patrol test \
  --device emulator-5554 \
  --target integration_test/$ARGUMENTS \
  --dart-define SOLIPLEX_BACKEND_URL=http://10.0.2.2:8000

注意: Android 模拟器使用 10.0.2.2 访问主机的 localhost。

首次设置: 有关 AVD 创建、JDK 和 Google APIs 镜像要求,请参阅 Android 设置指南。

Chrome(Web)

需要 Node.js >= 18(Playwright 会在首次运行时自动安装)。

# Run a specific test in Chrome
patrol test \
  --device chrome \
  --target integration_test/$ARGUMENTS \
  --dart-define SOLIPLEX_BACKEND_URL=http://localhost:8000

# Run headless (for CI or no-GUI environments)
patrol test \
  --device chrome \
  --web-headless true \
  --target integration_test/$ARGUMENTS \
  --dart-define SOLIPLEX_BACKEND_URL=http://localhost:8000

# Custom viewport (default is browser-dependent)
patrol test \
  --device chrome \
  --web-viewport "1280x720" \
  --target integration_test/$ARGUMENTS \
  --dart-define SOLIPLEX_BACKEND_URL=http://localhost:8000

首次设置: 有关 Node.js、CORS 和视口详情,请参阅 Web 设置指南。

如果 $ARGUMENTS 为空或为 "all",则针对 integration_test/ 运行测试(所有测试)。 如果 $ARGUMENTS 是类似 smoke_test.dart 的文件名,则运行该特定文件。

预检检查

运行测试前,请确认:

  1. 后端正在以 --no-auth-mode 运行,且使用上文的 URL
  2. 已安装 patrol CLI:patrol --version
  3. 代码可编译:先运行 dart analyze integration_test/
  4. test_bundle.dart 是最新的:Patrol 会自动生成此文件——如果测试未包含在测试包中,请删除该文件并让 patrol test 重新生成

测试模式

切勿使用 pumpAndSettle

SSE 流会导致测试无法稳定。请改用以下方式:

  1. waitForCondition —— 基于轮询,用于检查 UI 状态
  2. harness.waitForLog —— 基于流,用于异步事件(首选)
  3. tester.pump(duration) —— 固定延迟,仅用于短暂的渲染等待
标准测试结构
patrolTest('description', ($) async {
  await verifyBackendOrFail(backendUrl);
  ignoreKeyboardAssertions();

  final harness = TestLogHarness();
  await harness.initialize();

  try {
    await pumpTestApp($, harness);
    // ... test body ...
  } catch (e) {
    harness.dumpLogs(last: 50);
    rethrow;
  } finally {
    harness.dispose();
  }
});
Widget 查找器参考
目标查找器
房间列表项find.byType(RoomListTile)
聊天输入框find.byType(TextField)
发送按钮find.byTooltip('Send message')
聊天消息find.byType(ChatMessageWidget)
设置图标find.byIcon(Icons.settings)

避免使用 find.bySemanticsLabel 输入文本——它可能会定位到 Semantics 包装器,而不是 TextField,导致 enterText 失败。

用于断言的日志模式
日志记录器模式含义
Routerredirect called应用已启动,路由器已激活
HTTP/api/v1/rooms已调用房间 API
RoomRooms loaded:房间已成功解析
ActiveRunRUN_STARTEDAG-UI SSE 流已打开
ActiveRunTEXT_START:已收到第一个文本块
ActiveRunRUN_FINISHEDSSE 流已完成

调试:两阶段工作流

第一阶段:探索(dart MCP — flutter run)

使用 mcp__dart-tools__launch_app 启动应用,然后检查实时 Widget 树和日志,找出测试所需的查找器和日志模式。

mcp__dart-tools__launch_app   → starts app, returns DTD URI
mcp__dart-tools__connect_dart_tooling_daemon → connect to running app
mcp__dart-tools__get_widget_tree(summaryOnly: true) → see real widget hierarchy
mcp__dart-tools__get_app_logs(pid, maxLines: 50)    → see stdout log output
mcp__dart-tools__get_runtime_errors                  → check for exceptions

标准输出日志会显示为 [DEBUG] Router: redirect called for / ——可据此 确定日志记录器名称和消息模式,用于 harness.expectLog()。

Widget 树会显示实际的 widgetRuntimeType 值——将其用于 find.byType() 查找器。

阶段 2:断言(TestLogHarness — 巡检运行)

Patrol 通过 xcodebuild 启动应用,但它不会公开 DTD URI。在巡检测试运行期间,dart MCP 工具无法连接。

因此,所有测试断言都使用 TestLogHarness,通过 MemorySink 在进程内捕获日志:

  • harness.expectLog('Router', 'redirect called') — 同步检查
  • harness.waitForLog('ActiveRun', 'RUN_FINISHED') — 基于流的等待
  • harness.dumpLogs(last: 50) — 失败时将日志转储到控制台

该测试框架可以看到与 get_app_logs 中相同的 [DEBUG] 日志,但日志是在进程内访问的,而不是通过 stdout 访问。

Git Worktree 注意事项

此仓库是一个 git worktree。调用 flutter/dart 的 pre-commit 钩子必须先 unset GIT_DIR,否则 Flutter 会报告版本 0.0.0-unknown。scripts/ 中的包装脚本会处理此问题。

故障排除

症状原因解决方法
出现“Multiple devices found”提示缺少 --device 标志添加 --device macos
command not found: patrol~/.pub-cache/bin 不在 PATH 中将其添加到 PATH,或使用完整路径
测试卡在“Waiting for app”Entitlements 缺失或错误参见 macOS 设置
版本为 0.0.0-unknownworktree 中设置了 GIT_DIR使用 scripts/flutter-analyze.sh 包装脚本
“did not appear within 10s”Widget 位于抽屉中,而非主体中参见 macOS 设置
enterText 时出现 Bad state: No elementFinder 匹配到的是 Semantics,而非 TextField改用 find.byType(TextField)
辅助功能权限被拒绝Entitlements 已更改在“系统设置”>“隐私与安全性”>“辅助功能”中重新批准
iOS:xcodebuild 退出代码 70OS=latest 与模拟器不匹配参见 iOS 设置
iOS:“Device ... is not attached”设备 ID 格式错误使用 xcrun simctl list devices booted 中的 UUID
Android:“No connected devices”模拟器未运行,或 adb 不在 PATH 中参见 Android 设置
Android:连接 localhost 被拒绝模拟器无法访问主机的 localhost使用 10.0.2.2,而非 localhost
Android:启动时出现 Gmail 登录提示AVD 使用了 Google Play 镜像参见 Android 设置
Chrome:“Cannot find module playwright”未安装 Node.js参见 Web 设置
Chrome:测试中出现 CORS 错误后端缺少 CORS 标头参见 Web 设置
Chrome:verifyBackendOrFail 出现“Failed to fetch”后端离线或被 CORS 阻止启动后端;检查浏览器控制台

评论

支持 Markdown