| name | flutter-add-integration-test |
| description | Use when adding Flutter integration tests, wiring up `integration_test/`, `test_driver/integration_test.dart`, enabling `flutter_driver` extension, assigning `ValueKey`s for test targeting, or running `flutter drive` on Chrome, Android, iOS, or Firebase Test Lab. Also use when converting interactive MCP exploration (launch_app, get_widget_tree, tap, enter_text) into permanent `WidgetTester`-based tests, or capturing performance timelines via `traceAction`. |
| metadata | {"model":"deepseek/deepseek-chat","source":"https://github.com/flutter/skills/blob/main/skills/flutter-add-integration-test/SKILL.md","last_modified":"Tue, 21 Apr 2026 18:29:20 GMT"} |
Implementing Flutter Integration Tests
Contents
Project Setup and Dependencies
Configure the project to support integration testing and Flutter Driver extensions.
- Add required development dependencies to
pubspec.yaml:
flutter pub add 'dev:integration_test:{"sdk":"flutter"}'
flutter pub add 'dev:flutter_test:{"sdk":"flutter"}'
- Enable the Flutter Driver extension in your application entry point (typically
lib/main.dart or a dedicated lib/main_test.dart):
- Import
package:flutter_driver/driver_extension.dart.
- Call
enableFlutterDriverExtension(); before runApp().
- Add
Key parameters (e.g., ValueKey('login_button')) to critical widgets in the application code to ensure reliable targeting during tests.
Interactive Exploration via MCP
Use the Dart/Flutter MCP server tools to interactively explore and manipulate the application state before writing static tests.
- Launch: Execute
launch_app with target: "lib/main_test.dart" to start the application and acquire the DTD URI.
- Inspect: Execute
get_widget_tree to discover available Keys, Text nodes, and widget Types.
- Interact: Execute
tap, enter_text, and scroll to simulate user flows.
- Wait: Always execute
waitFor or verify state with get_health when navigating or triggering animations.
- Troubleshoot Unmounted Widgets: If a widget is not found in the tree, it may be lazily loaded in a
SliverList or ListView. Execute scroll or scrollIntoView to force the widget to mount before interacting with it.
Test Authoring Guidelines
Structure integration tests using the flutter_test API paradigm.
- Create a dedicated
integration_test/ directory at the project root.
- Name all test files using the
<name>_test.dart convention.
- Initialize the binding by calling
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); at the start of main().
- Load the application UI using
await tester.pumpWidget(MyApp());.
- Trigger frames and wait for animations to complete using
await tester.pumpAndSettle(); after interactions like tester.tap().
- Assert widget visibility using
expect(find.byKey(ValueKey('foo')), findsOneWidget); or findsNothing.
- Scroll to specific off-screen widgets using
await tester.scrollUntilVisible(itemFinder, 500.0, scrollable: listFinder);.
Conditional Logic for Legacy flutter_driver:
- If maintaining or migrating legacy
flutter_driver tests, use driver.waitFor(), driver.waitForAbsent(), driver.tap(), and driver.scroll() instead of the WidgetTester APIs.
Execution and Profiling
Execute tests using the flutter drive command. Require a host driver script located in test_driver/integration_test.dart that calls integrationDriver().
Conditional Execution Targets:
- If testing on Chrome: Launch
chromedriver --port=4444 in a separate terminal, then run:
flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart -d chrome
- If testing headless web: Run with
-d web-server.
- If testing on Android (Local): Run
flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart.
- If testing on Firebase Test Lab (Android):
- Build debug APK:
flutter build apk --debug
- Build test APK:
./gradlew app:assembleAndroidTest
- Upload both APKs to the Firebase Test Lab console.
Workflow: End-to-End Integration Testing
Copy and follow this checklist to implement and verify integration tests.
Examples
Standard Integration Test (integration_test/app_test.dart)
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('End-to-end test', () {
testWidgets('tap on the floating action button, verify counter', (tester) async {
await tester.pumpWidget(const MyApp());
expect(find.text('0'), findsOneWidget);
final fab = find.byKey(const ValueKey('increment'));
await tester.tap(fab);
await tester.pumpAndSettle();
expect(find.text('1'), findsOneWidget);
});
});
}
Host Driver Script (test_driver/integration_test.dart)
import 'package:integration_test/integration_test_driver.dart';
Future<void> main() => integrationDriver();
Performance Profiling Driver Script (test_driver/perf_driver.dart)
Use this driver script if you wrap your test actions in binding.traceAction() to capture performance metrics.
import 'package:flutter_driver/flutter_driver.dart' as driver;
import 'package:integration_test/integration_test_driver.dart';
Future<void> main() {
return integrationDriver(
responseDataCallback: (data) async {
if (data != null) {
final timeline = driver.Timeline.fromJson(
data['scrolling_timeline'] as Map<String, dynamic>,
);
final summary = driver.TimelineSummary.summarize(timeline);
await summary.writeTimelineToFile(
'scrolling_timeline',
pretty: true,
includeSummary: true,
);
}
},
);
}