About patrol-write-test
patrol-write-test is an agent skill for creating and refining Patrol tests. It guides test authors through reusing existing code, assigning widget keys, writing and running tests incrementally, and following Patrol-specific interaction and assertion rules.
Key features
- 01Inspect and reuse existing test code
- 02Write Patrol actions directly in test files
- 03Assign unique widget keys
- 04Run tests incrementally through Patrol MCP
- 05Handle native dialogs and permissions
Use cases
- 01Adding a test for a new app flow
- 02Debugging a failing Patrol test with screenshots
- 03Adding keys to widgets used in tests
MCP support
The skill directs agents to use Patrol MCP tools to run a single test, inspect status and UI trees, capture screenshots, and quit the session.
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ leancodepl/ patrol --skill patrol-write-testAfter installing, type/patrol-write-testin Claude Code to confirm it loaded.
Details
From the project READMEIf the project's Patrol tests use LeanCode's Modules/System/ApiClients architecture (e.g. a patrol_test/modules/ directory and a testApp wrapper), also follow patrol-test-architecture, which builds on this skill and wins where the two differ.
Order of actions when writing new tests
- Inspect existing test code for functions that can be reused
- Also think if one of existing functions can be adjusted to match its existing usage and new test
- Assign test keys to required elements if they are not assigned yet
- Start writing test: reuse existing functions + put new test steps in new test file
- Write patrol actions directly in the test file, do not create new methods
- Run the test frequently during development — don't wait until the full test is written. Run after completing each logical group of steps to catch failures early
- After full test passes, reorganize new code into reusable functions
- Rerun the test after reorganizing to confirm it still passes
Patrol MCP Usage
When working with Patrol tests:
- Use
patrol-run({ "testFile": "patrol_test/your_test.dart" })to run tests and wait for completion - If no session running: starts new session with specified test file
- If session already running: automatically restarts current tests
- Use
patrol-screenshot({ "platform": "android" })orpatrol-screenshot({ "platform": "ios" })to capture screenshots for debugging test failures - Use
patrol-quit({})to quit the session gracefully - Use
patrol-status({})to check current status and recent output - Use
patrol-native-tree({})to fetch the current native UI tree hierarchy for writing native interactions and interactions with apps other than the app under test.
Patrol Tests Rules
Patrol API
- Any file that directly uses Patrol APIs (
$(),.scrollTo(),.tap(),.enterText(),.waitUntilVisible(), etc.) shouldimport 'package:patrol/patrol.dart'; - ALWAYS inspect Patrol API before implementing test actions:
- Search codebase for existing Patrol API usage patterns
- Check $.platform APIs for the specific action
- If method not found in codebase, check: https://patrol.leancode.co/
- Only implement after confirming the correct API method
- ALWAYS inspect
$.platformmethods before implementing test actions - Don't use flutter_test package. Use only patrol api
- Only run tests with Patrol MCP server for single test and
patrol testfor all tests. Never useflutter testcommand - Do not write patrolSetUp and patrolTearDown methods on your own
Action Rules
- Don't use
$.pump,waitUntilVisibleorwaitUntilExistsand other wait methods after or before tap, scrollTo and enterText. Patrol handles it automatically. Do this only at the end of the test - To find widgets, use only keys
- Don't write try catch blocks unless absolutely necessary
- After writing test check if it works by running it with MCP server, fix it if it fails
- If test fails because element was not found, check if it need to be scrolled to in the app code and adjust the test if needed
Assertion Rules
- Don't write assertions after actions, but do write them at the end of the test
- Prefer using
waitUntilVisibleas assertion at the end of the test - Use
expect()for assertions only whenwaitUntilVisibleis not enough
Native Dialog Handling
- ALWAYS handle native dialogs that appear during the flow:
- Handle dialogs immediately after the action that triggers them
- For native permissions prefer
$.platform.mobile.grantPermissionWhenInUseover$.platform.mobile.tap
Test Keys
-
Assign a key ONLY to widgets involved in testing
-
ONLY add the
keyparameter to existing widgets -
NEVER change widget signatures
-
NEVER refactor existing code structure
-
NEVER hardcode keys in the app, you must use keys from the keys file that is shared between app and tests
-
NEVER create new widgets in the app
-
NEVER create a key that is not assigned to a widget
-
Always make sure that each key value is unique
-
ALWAYS sort keys alphabetically
-
Add keys as first parameter to the widget constructor
-
If widget is not unique (for example generated from a list) use a parameterized key
- ALWAYS prefer using enums or DTOs as the parameter if they already exist
- Use existing widget properties for parameterized keys
- NEVER assign a parameterized key in the app and then use fixed values for it in the keys file (and vice versa)
- NEVER create helper methods, use parameterized keys instead
- When widgets are generated from existing enums or DTOs, always use parameterized keys with the those enum/DTO values as the parameter
Use individual keys when:
- Widgets are hardcoded and known at compile time
- Widgets have distinct, meaningful names
Use parameterized keys when:
- Widgets are generated from dynamic data
- Widgets are generated from a DTO or enums
- Number of widgets is variable or large
- Widgets are generated in loops or from lists