flutter-integration-tests
SKILL.md
Flutter Integration Tests
Setup
Add integration_test as a dev dependency:
flutter pub add 'dev:integration_test:{"sdk":"flutter"}'
Required pubspec.yaml entries:
dev_dependencies:
flutter_test:
sdk: flutter
integration_test:
sdk: flutter
Project Structure
my_app/
lib/
main.dart
integration_test/
app_test.dart
feature_a_test.dart
feature_b_test.dart
test_driver/ # Only for web testing and performance profiling
integration_test.dart
perf_driver.dart
- Place all integration tests in
integration_test/. - Only create
test_driver/when targeting web browsers or capturing performance timelines.
Writing Tests
Binding Initialization
Always initialize the binding before any tests:
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('description', (tester) async {
await tester.pumpWidget(const MyApp());
await tester.pumpAndSettle();
// assertions
});
}
Widget Identification
Add Key or ValueKey to widgets that tests need to find:
// In production code
FloatingActionButton(
key: const ValueKey('increment'),
onPressed: _incrementCounter,
child: const Icon(Icons.add),
)
// In test code
final fab = find.byKey(const ValueKey('increment'));
await tester.tap(fab);
Prefer find.byKey() over find.text() for stability across localization changes.
Core Test Pattern
testWidgets('tap increment, verify counter updates', (tester) async {
await tester.pumpWidget(const MyApp());
// 1. Verify initial state
expect(find.text('0'), findsOneWidget);
// 2. Perform action
await tester.tap(find.byKey(const ValueKey('increment')));
// 3. Wait for UI to settle
await tester.pumpAndSettle();
// 4. Verify result
expect(find.text('1'), findsOneWidget);
});
Grouping Tests
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('counter', () {
testWidgets('starts at zero', (tester) async { /* ... */ });
testWidgets('increments on tap', (tester) async { /* ... */ });
});
group('navigation', () {
testWidgets('opens settings page', (tester) async { /* ... */ });
});
}
Platform-Specific Patterns
Platform-Conditional Imports
When tests differ between web and native platforms:
// example_test.dart
import '_example_test_io.dart'
if (dart.library.js_interop) '_example_test_web.dart' as tests;
void main() => tests.main();
Create _example_test_io.dart and _example_test_web.dart with platform-specific implementations.
Screenshots
void main() {
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('capture screenshot', (tester) async {
await tester.pumpWidget(const MyApp());
// Required on Android before taking screenshots
await binding.convertFlutterSurfaceToImage();
await tester.pumpAndSettle();
final bytes = await binding.takeScreenshot('home_screen');
expect(bytes.isNotEmpty, isTrue);
});
}
- Call
convertFlutterSurfaceToImage()before screenshots on Android/iOS. - Web screenshots return empty bytes; handle accordingly.
Golden File Testing
testWidgets('matches golden', (tester) async {
await tester.pumpWidget(const MyApp());
await tester.pumpAndSettle();
await expectLater(
find.byType(MaterialApp),
matchesGoldenFile('goldens/home_screen.png'),
);
});
Performance Profiling
For detailed guidance on performance profiling with traceAction(), timeline recording, and driver setup, see references/performance-profiling.md.
Running Tests
Mobile and Desktop
flutter test integration_test/app_test.dart
Web
- Create
test_driver/integration_test.dart:
import 'package:integration_test/integration_test_driver.dart';
Future<void> main() => integrationDriver();
- Launch ChromeDriver and run:
chromedriver --port=4444
flutter drive \
--driver=test_driver/integration_test.dart \
--target=integration_test/app_test.dart \
-d chrome
Use -d web-server for headless mode.
CI/CD (Linux)
Use xvfb-run for headless display:
xvfb-run flutter test integration_test -d linux
Best Practices
- Initialize binding once -- call
IntegrationTestWidgetsFlutterBinding.ensureInitialized()at the top ofmain(), before anytestWidgets. - Verify initial state -- always assert starting conditions before performing actions.
- Use
pumpAndSettle()after every action -- wait for animations and async operations to complete. - Prefer
find.byKey()overfind.text()-- keys are stable across locales and text changes. - Add
ValueKeyto testable widgets -- plan for testability in production code. - Group related tests -- use
group()for logical organization. - One concern per test -- each
testWidgetsshould verify a single user flow or behavior. - Use
--profilefor performance tests -- never measure performance in debug mode. - Use
--no-ddson mobile devices -- avoids Dart Development Service conflicts during profiling. - Separate platform implementations -- use conditional imports (
_io.dart/_web.dart) when behavior diverges. - Call
convertFlutterSurfaceToImage()on Android -- required before taking screenshots. - Clean up test apps on device -- leftover apps can cause subsequent test failures.
Weekly Installs
1
Repository
victor-teles/skillsFirst Seen
Mar 1, 2026
Security Audits
Installed on
amp1
cline1
opencode1
cursor1
continue1
kimi-cli1