Patrol has always been about bringing real-world reliability to Flutter apps, but one thing was still missing: a smooth, first-class workflow inside the IDE most Flutter teams rely on. With Patrol growing rapidly and being adopted across complex projects, we knew it was time to bring its power directly into VS Code, and it happened with the Patrol. 4.0.
We are excited to announce the release of the official Patrol extension for Visual Studio Code! It brings the power of Patrol directly into your IDE, transforming how you write, run, and debug Patrol tests. Keep reading to find out more about how it works.
Before the Patrol VS Code extension, QA working with Patrol only had the option to run tests from the terminal. Patrol tests appeared in the VS Code Test Explorer alongside unit and widget tests, which wasn’t convenient for either QAs or developers.
Debugging Patrol tests previously required running the patrol develop command in the terminal and manually typing out the specific path to the test file.
patrol develop -t integration_test/login_test.dart
This process was time-consuming, especially for repositories with a large number of tests. With the extension, all you need to do is click a button on a test in test explorer.
Currently, a typical Patrol developer's workspace is fragmented across a test file, a simulator/emulator, a terminal window, and the Patrol DevTools extension. The new VS Code extension unifies this workflow, removing the need to constantly switch context between code and terminal. It also streamlines the debugging process by allowing you to automate the opening of DevTools for every session.
The Patrol VS Code extension integrates with the IDE test explorer, allowing you to use all of its features. This includes:
Visual representation of test structure in a dedicated panel
This integration makes Patrol tests feel like a native part of your development workflow, mimicking the experience you expect from standard unit testing tools but optimized for Patrol.
The extension automatically scans the Flutter project for Patrol test files. By default, it looks for tests located in the patrol_test directory and ending with the test.dart suffix. Both the test directory and the file suffix are fully configurable. You can change them using the test_directory and test_file_suffix parameters in the patrol section of your pubspec.yaml file.
patrol:
test_directory: integration_test # default: patrol_test
test_file_suffix: patrol.dart# default: test.dartAll Patrol tests are displayed in a dedicated "Patrol" section in Test Explorer, providing clear separation from other test types in the project (e.g., Dart unit tests). This separation is crucial for larger projects. It prevents Patrol tests from cluttering the view when developers are running unit tests, and vice versa. It allows QAs to focus entirely on the Patrol suite without having to filter through dozens of widget tests.
The extension fully supports the hierarchical structure of Patrol tests, including:
- Test groups ( group() ) - displayed as folders in the test tree
- Nested groups - multi-level group hierarchy
- Individual tests - displayed as leaves in the tree
Each level of the hierarchy can be run or debugged independently.
Thanks to the extension, the tests will now show the “Run Test” (with a debug option also available) button right next to each test call in the code. This works for patrolTest calls as well as for your custom wrapper, if you’ve decided to use one.
Keep in mind, however, that regardless of which test you click, Patrol will always execute the entire file. This is a limitation of Patrol’s architecture, so we recommend keeping one test per file for the best experience.
For debugging tests, the extension uses the patrol develop command. You can start debugging sessions from the “Testing” tab in your IDE, as well as from additional options on the green play button next to test code.
During debug sessions, a dedicated Patrol button section appears in the VS Code debug toolbar (last three buttons):
- Hot Restart - restarts the currently running test,
- Stop Test - stops Patrol develop session,
- Open DevTools - opens Flutter DevTools Widget Inspector.
As with other testing tools, you can add breakpoints in tests so that the test flow will stop when using patrol develop. All other debugger tools (pause, continue, step over, step into, step out) are also supported.
To make life easier, the Patrol extension allows you to inspect your app in two ways. First, whenever you run Patrol develop and the debugger connects to the app, you will be prompted to open Patrol DevTools. You can even select an option to always open it automatically.
Additionally, the debug toolbar includes a dedicated button for the Flutter DevTools Widget Inspector. This allows you to, for example, use select mode, click the desired widget in the app, and the IDE will open a file with that widget. This makes navigating the app code much easier, especially for QAs.
Patrol extension allows you to create a set of arguments that will be passed to Patrol commands. From now on, you won’t have to pass flags and other arguments to every Patrol test run.
The extension offers flexible configuration of Patrol CLI arguments at three levels:
1. Global arguments (patrol.additionalArgs) - added to all Patrol commands
2. Arguments for patrol test (patrol.test.additionalArgs) - specific to patrol test calls
3. Arguments for patrol develop (patrol.develop.additionalArgs) - specific to patrol develop calls
Example configuration in settings.json:
"patrol.additionalArgs": ["--verbose"],
"patrol.develop.additionalArgs": ["--no-uninstall"],
"patrol.test.additionalArgs": ["--clear-permissions"],The extension allows defining custom test run profiles that appear as additional options in Test Explorer. Each profile can have its own CLI arguments:
"patrol.customProfiles": {
"iOS Simulator": {
"additionalArgs": ["--device", "iPhone 15 Pro"]
},
"Android Emulator": {
"additionalArgs": ["--device", "emulator-5554"]
},
"With Coverage": {
"additionalArgs": ["--coverage"]
}
},
Each profile is available in both Run and Debug modes, enabling easy switching between different test configurations.
For example, this allows you to create distinct profiles for dev, staging, and prod flavors, or create specific configurations that mimic your CI/CD pipeline locally. This ensures that when a test fails locally, you can be confident it's a code issue, not an environment mismatch.
The extension allows defining environment variables that are passed to Patrol CLI processes. This can be handy, for example, if you want to override the default value of PATROL_FLUTTER_COMMAND, which is an everyday use case for fvm users.
"patrol.env": {
"PATROL_FLUTTER_COMMAND": "fvm flutter"
}Developing Visual Studio Code extensions is a process built upon the TypeScript and Node.js ecosystem. In the standard model, plugins communicate with the editor via the exposed VS Code API, running in a separate process known as the Extension Host.
Facing the challenge of integrating Patrol tests with the standard VS Code API, we decided to leverage existing solutions and opted for tight integration with Dart-Code - the official and battle-tested extension for Dart and Flutter.
As Patrol builds on Dart-Code’s public API for analyzer data, project discovery/outlines, SDK resolution, and debugging hooks, running and debugging tests feels similar to standard Flutter workflows.
const dartExtension = vs.extensions.getExtension<PublicDartExtensionApi>("dart-code.dart-code")
if (!dartExtension) {
throw new Error("Dart extension not found")
}
const dartExtensionApi = dartExtension.exports
const testModel = new TestModel({ showSkippedTests: true }, isPathInsideFlutterProject)
const testDiscoverer = new TestDiscoverer(logger, dartExtensionApi.workspace, testModel)
context.subscriptions.push(testDiscoverer)
constvsTestController = newVsCodeTestController(logger, testModel, testDiscoverer, dartExtensionApi.sdks)A tree of test suites, groups, and tests is maintained in TestModel. It keeps this tree in sync during discovery and execution, updating node status, duration, and aggregated pass/total counts, deriving labels/descriptions, and pruning stale or deleted nodes. TestModel emits change events for the UI and forwards lifecycle callbacks to listeners like the VS Code TestController.
VsCodeTestController mirrors the TestModel tree as TestItems and updates the UI when the model changes. It delegates discovery to TestDiscoverer and runs/debugs tests by launching TerminalTestRunner, parsing Patrol output, and mapping lifecycle events to VS Code TestRun updates. It also manages debug session context and DevTools actions, and controls presentation.
TestDiscoverer, responsible for keeping the test tree up to date, requests the current Outline (a live, lightweight structural summary of a Dart file) via Dart-Code’s public API on files change events, then reconstructs tests/groups in TestModel by recognizing common package:test patterns, so the UI reflects current tests as you type or open files. Updates are debounced per file, nodes get accurate ranges and anything not rediscovered is marked and pruned.
Patrol runs on the device selected by the Patrol CLI, or on the device you explicitly specify with --device in the extension’s config. Attach and DevTools target the VM that Patrol prints in its output.
For debugging, we detect the DevTools URL in Patrol’s output, extract vmServiceUri (URL of the Dart VM Service), and start a “dart” attach session. By switching the VS Code context key on debugging session start, we enable Patrol’s toolbar (Hot Restart, Stop, Open DevTools). DevTools is opened by Dart-Code, so it targets the right VM and follows the user’s DevTools preferences.
const vmServiceUri = new URL(patrolDevToolsUrl).searchParams.get("uri")
if (vmServiceUri) {
vs.debug.startDebugging(undefined, {
name: "Patrol Tests",
request: "attach",
dartCodeDebugSessionID,
isPatrolDebugSession: true,
type: "dart",
cwd: projectRoot !== undefined ? path.join(projectRoot, getTestDirectory(projectRoot)) :
undefined,
vmServiceUri,
})
}The Patrol Visual Studio Code Extension arrives as part of the broader Patrol 4.0 release – a major update that also introduces Patrol Web support and expands what teams can test across platforms. This new extension brings first-class IDE support to Patrol by solving long-standing workflow gaps: no Test Explorer integration, manual terminal-based debugging, and constant tool switching.
Now, Patrol tests are automatically discovered, grouped, and runnable with a single click, with patrol develop debugging, hot-restart controls, DevTools integration, and full configurability built directly into VS Code. Whether you’re testing mobile or the Web, this extension makes working with Patrol smoother, faster, and far more intuitive.
If you need help setting up Patrol in your project or unlocking the full potential of our framework, the LeanCode team, creators of Patrol, offers dedicated support services such as Patrol Setup & Patrol Training and Automating QA processes in your Flutter application.
10 min. • Dec 8, 2025
Patrol 4.0 is here! By far the biggest update since improvements were made to the test building, it brings support for a web platform, a VS Code extension, a better debugging experience, and many smaller improvements. Let’s dive into the details and the brief backstory behind this release.
10 min. • Dec 8, 2025
Patrol has reached version 4.0, marking a major milestone. Among the many new features, one stands out in particular: Patrol now supports Web! In this article, you’ll find a rundown of what Patrol Web can do, but also a look behind the scenes: how we designed it, why certain decisions were made, and what it took to bring Patrol’s architecture from mobile into the browser.
6 min • Aug 6, 2025
This article explores effective strategies for testing email-dependent flows in automated end-to-end tests. It covers practical methods from workarounds to tools along with their implementation, pros and cons, and best practices for seamless integration into development pipelines.