patrol

Patrol E2E Test Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "patrol" with this command: npx skills add soliplex/flutter/soliplex-flutter-patrol

Patrol E2E Test Skill

Run and manage Patrol integration tests for this Flutter project (macOS, iOS, Android, and Chrome).

Running Tests

CLI location: patrol

Always use --device to avoid the interactive device selection prompt.

macOS (default)

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

First-time setup: See macOS Setup Guide for entitlements and window constraints.

iOS (simulator)

Use a booted simulator's device ID or name. The --ios flag specifies the OS version (defaults to latest — must match the simulator's OS).

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

Use xcrun simctl list devices booted to find the device ID and OS version.

First-time setup: See iOS Setup Guide for RunnerUITests target and simulator OS matching.

Android (emulator or device)

Requires a booted emulator or connected device. Use the name/serial from 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

Note: Android emulators use 10.0.2.2 to reach the host's localhost .

First-time setup: See Android Setup Guide for AVD creation, JDK, and Google APIs image requirement.

Chrome (web)

Requires Node.js >= 18 (Playwright auto-installs on first run).

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

First-time setup: See Web Setup Guide for Node.js, CORS, and viewport details.

If $ARGUMENTS is empty or "all", run against integration_test/ (all tests). If $ARGUMENTS is a filename like smoke_test.dart , run that specific file.

Pre-flight Checks

Before running tests, verify:

  • Backend is running in --no-auth-mode at the URL above

  • patrol CLI is installed: patrol --version

  • Code compiles: Run dart analyze integration_test/ first

  • test_bundle.dart is current: Patrol auto-generates this — if tests are missing from the bundle, delete it and let patrol test regenerate

Test Patterns

Never use pumpAndSettle

SSE streams prevent settling. Use these instead:

  • waitForCondition — polling-based, for UI states

  • harness.waitForLog — stream-based, for async events (preferred)

  • tester.pump(duration) — fixed delays, only for brief rendering pauses

Standard test structure

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 finders reference

Target Finder

Room list items find.byType(RoomListTile)

Chat input find.byType(TextField)

Send button find.byTooltip('Send message')

Chat messages find.byType(ChatMessageWidget)

Settings icon find.byIcon(Icons.settings)

Avoid find.bySemanticsLabel for text entry — it can resolve to the Semantics wrapper instead of the TextField, causing enterText to fail.

Log patterns for assertions

Logger Pattern Meaning

Router

redirect called

App booted, router active

HTTP

/api/v1/rooms

Rooms API called

Room

Rooms loaded:

Rooms parsed successfully

ActiveRun

RUN_STARTED

AG-UI SSE stream opened

ActiveRun

TEXT_START:

First text chunk received

ActiveRun

RUN_FINISHED

SSE stream completed

Debugging: Two-Phase Workflow

Phase 1: Discover (dart MCP — flutter run )

Use mcp__dart-tools__launch_app to start the app, then inspect the live widget tree and logs to find the right finders and log patterns for your test.

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

Stdout logs appear as [DEBUG] Router: redirect called for / — use these to identify the logger name and message pattern for harness.expectLog() .

The widget tree shows actual widgetRuntimeType values — use these for find.byType() finders.

Phase 2: Assert (TestLogHarness — patrol run)

Patrol launches the app through xcodebuild, which does not expose a DTD URI. The dart MCP tools cannot connect during a patrol test run.

Instead, all test assertions use TestLogHarness which captures logs in-process via MemorySink :

  • harness.expectLog('Router', 'redirect called') — synchronous check

  • harness.waitForLog('ActiveRun', 'RUN_FINISHED') — stream-based wait

  • harness.dumpLogs(last: 50) — dump to console on failure

The harness sees the same [DEBUG] logs that appear in get_app_logs , but accessed in-process rather than via stdout.

Git Worktree Caveat

This repo is a git worktree. Pre-commit hooks that invoke flutter /dart must unset GIT_DIR first, otherwise Flutter reports version 0.0.0-unknown . Wrapper scripts in scripts/ handle this.

Troubleshooting

Symptom Cause Fix

"Multiple devices found" prompt Missing --device flag Add --device macos

command not found: patrol

~/.pub-cache/bin not on PATH Add to PATH or use full path

Test hangs on "Waiting for app" Entitlements missing/wrong See macOS setup

0.0.0-unknown version GIT_DIR set in worktree Use scripts/flutter-analyze.sh wrapper

"did not appear within 10s" Widget in drawer, not body See macOS setup

Bad state: No element on enterText Finder matched Semantics, not TextField Use find.byType(TextField) instead

Accessibility permission denied Entitlements changed Re-approve in System Settings > Privacy > Accessibility

iOS: xcodebuild exit code 70 OS=latest doesn't match simulator See iOS setup

iOS: "Device ... is not attached" Wrong device ID format Use UUID from xcrun simctl list devices booted

Android: "No connected devices" Emulator not running or adb not on PATH See Android setup

Android: connection refused to localhost Emulator can't reach host localhost Use 10.0.2.2 instead of localhost

Android: Gmail login prompt on boot AVD uses Google Play image See Android setup

Chrome: "Cannot find module playwright" Node.js not installed See Web setup

Chrome: CORS error in test Backend missing CORS headers See Web setup

Chrome: "Failed to fetch" on verifyBackendOrFail

Backend offline or CORS block Start backend; check browser console

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

Flutter AppStore Doc UI Kit

Generate a complete App Store deliverable pack for a Flutter 3.35.1 app with offline-first design, camera/photo permissions, Apple-style UI mockups, and a sq...

Registry SourceRecently Updated
1660Profile unavailable
General

flutter-architecture

Flutter 四层组件化 + MVVM 项目架构规范。适用于 Flutter 项目开发、新模块创建、目录结构设计、代码评审、架构对齐。支持在项目中直接创建/搭建整套 MVVM+组件化目录结构。

Registry SourceRecently Updated
1520Profile unavailable
General

flutter-layout

No summary provided by upstream source.

Repository SourceNeeds Review
1.2K-flutter
General

flutter-performance

No summary provided by upstream source.

Repository SourceNeeds Review
1.2K-flutter