patrol-e2e-testing
Use when writing E2E/integration tests, testing native interactions like permissions or system dialogs, capturing UI regressions, or validating cross-platform behavior (Patrol 4.x).
Works with
---
name: patrol-e2e-testing
description: Use when writing E2E/integration tests, testing native interactions like permissions or system dialogs, capturing UI regressions, or validating cross-platform behavior (Patrol 4.x).
license: MIT
---
# Patrol E2E Testing Skill
Design, implement, and run end-to-end (E2E) tests using Patrol 4.x in Flutter projects.
## When to Use
Use this skill when:
* A new screen or user flow needs E2E test coverage.
* A feature interacts with native components (permissions, notifications, system dialogs, deep links).
* A UI bug should be captured as a regression test.
* Cross-platform behavior (Android / iOS / Web) must be validated.
* Setting up Patrol in a new or existing Flutter project.
## Setup
Follow the official Patrol documentation for installation and project initialization:
[https://patrol.leancode.co/documentation#setup](https://patrol.leancode.co/documentation#setup)
Key Patrol conventions:
* Add `patrol` as a dev dependency.
* Place tests in `patrol_test/`.
* Name test files with a `_test.dart` suffix.
* Execute tests with `patrol test`.
## Workflow
Follow these steps when implementing or updating Patrol tests.
### 1. Identify the user journey
Break the feature into:
* **Actions**: taps, scrolls, input, navigation, deep links.
* **Observable outcomes**: visible text, screen changes, enabled buttons, dialogs.
Rules:
* One test per primary (happy-path) journey.
* Separate tests for critical edge cases.
* Avoid combining unrelated flows in a single test.
### 2. Structure the Patrol test
Basic Patrol structure:
```dart
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'));
},
);
}
```
Key concepts:
* Use `patrolTest()` instead of `testWidgets()`.
* `$` is the Patrol tester.
* Use `$(#keyName)` to find widgets by `Key`.
* Use explicit wait conditions (e.g., `waitUntilVisible`).
### 3. Handle native dialogs
For OS-level permission dialogs:
```dart
patrolTest('grants camera permission', ($) async {
await $.pumpWidgetAndSettle(const MyApp());
await $(#openCameraButton).tap();
if (await $.native.isPermissionDialogVisible()) {
await $.native.grantPermission();
}
await $.waitUntilVisible($(#cameraPreview));
});
```
Use native automation only when required by the feature.
### 4. Selector & interaction quick reference
**Finding widgets:**
```dart
$('some text') // by text
$(TextField) // by type
$(Icons.arrow_back) // by icon
```
**Tapping:**
```dart
// 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();
```
**Entering text:**
```dart
// Enter text into the second TextField on screen
await $(TextField).at(1).enterText('your input');
```
**Scrolling:**
```dart
await $(widget_you_want_to_scroll_to).scrollTo();
```
**Native interactions:**
```dart
// 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. Running Patrol tests
Run all tests:
```bash
patrol test
```
Run a specific file with live reload (development mode):
```bash
patrol develop -t integration_test/my_test.dart
```
Run a specific file:
```bash
patrol test --target patrol_test/login_test.dart
```
Run on web:
```bash
patrol test --device chrome
```
Headless web (CI):
```bash
patrol test --device chrome --web-headless true
```
Filter by tags:
```bash
patrol test --tags android
```
### 6. Stabilization patterns
Flaky tests undermine confidence. Apply these patterns:
```dart
// AVOID — arbitrary delay
await Future.delayed(Duration(seconds: 3));
// PREFER — explicit wait condition
await $.waitUntilVisible($(#targetWidget));
// For animations, pump until settled
await $.pumpAndSettle();
```
* Never use `Future.delayed` as a synchronization mechanism.
* Use `waitUntilVisible` or `waitUntilExists` to wait for UI state.
* Set `settleTimeout` in `PatrolTesterConfig` for slow CI environments.
### Output requirements
When applied, this skill produces:
1. Patrol test(s) covering the specified feature.
2. Any required widget `Key` additions to production code.
3. Exact `patrol test` command(s) to execute locally.
4. Notes explaining stabilization or timing decisions.
**Checkpoint:** Run `patrol test --target <file>` locally to confirm the test passes before committing.
### Quality bar
A valid Patrol test must be:
* **Deterministic** — no arbitrary delays; uses explicit wait conditions.
* **Readable** — clear test name describing the user journey.
* **Minimal but complete** — one assertion chain per journey.
* **Secret-safe** — credentials loaded from `String.fromEnvironment`, never hardcoded.
* **CI-ready** — passes headless with `--web-headless true` or on emulator.More Testing skills
tdd
mattpocock/skills
Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.
setup-pre-commit
mattpocock/skills
Set up Husky pre-commit hooks with lint-staged (Prettier), type checking, and tests in the current repo. Use when user wants to add pre-commit hooks, set up Husky, configure lint-staged, or add commit-time formatting/typechecking/testing.
agent-browser
vercel-labs/agent-browser
Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools.

