flutter_test_pilot 1.0.8
flutter_test_pilot: ^1.0.8 copied to clipboard
A comprehensive Flutter automation testing framework for intuitive UI testing.
Flutter Test Pilot #
A comprehensive, fluent testing framework for Flutter applications that makes UI testing intuitive and maintainable.
โจ Key Highlights #
๐ Works Independently - No Prior Knowledge Required #
Flutter Test Pilot operates completely independently without requiring any knowledge of your application's internal flow or structure. Simply integrate it into your Flutter app and start writing tests immediately. The framework:
- โ Automatically discovers and interacts with UI elements using intelligent widget finding strategies
- โ Works seamlessly with any Flutter application architecture (BLoC, Provider, Riverpod, GetX, etc.)
- โ No manual setup of routes, navigation keys, or application state required
- โ Plug-and-play integration - add the dependency and you're ready to test
๐งช Verified with Live Data Integration Testing #
Battle-tested with real-world integration tests using live data and actual application flows. Our comprehensive test suite validates:
- โ Multi-page navigation scenarios (HomePage โ ClaimsPage โ ProfilePage)
- โ Real user interactions (taps, text input, gestures) on actual Flutter widgets
- โ API call interception and validation with live HTTP requests
- โ Production-like testing environments with real Flutter apps
- โ Complex UI flows including form submissions, navigation, and state management
See the example integration tests for real-world usage patterns.
Features #
- ๐ฏ Fluent API: Write tests that read like natural language
- ๐ฎ Comprehensive UI Interactions: Tap, type, drag, swipe, scroll, pinch, and pan gestures
- ๐ Smart Widget Finding: 17+ strategies for finding UI elements - works without prior app knowledge
- ๐ API Testing: Intercept and validate HTTP requests/responses with live data
- ๐ Rich Reporting: Console and JSON output with detailed test results
- ๐ฆ Test Suites: Organize tests with setup, main steps, and cleanup phases
- ๐ก๏ธ Error Handling: Robust error handling with retry mechanisms
- ๐ Zero Configuration: Works independently - no setup required
- โ Integration Tested: Verified with real Flutter apps and live data
Installation #
Add this to your package's pubspec.yaml file:
dev_dependencies:
flutter_test_pilot: ^1.0.0
flutter_test: ^1.0.0
Then run:
flutter pub get
Quick Start #
1. Initialize Test Pilot #
import 'package:flutter_test_pilot/flutter_test_pilot.dart';
void main() {
testWidgets('Login flow test', (WidgetTester tester) async {
// Initialize your app
await tester.pumpWidget(MyApp());
// Create and run test suite
final loginSuite = TestSuite(
name: 'User Login Flow',
steps: [
Type.hint('Email').text('user@example.com'),
Type.hint('Password').text('password123'),
Tap.text('Login'),
// Add API validation
Api.post(
id: 'login-api',
urlPattern: r'/api/auth/login',
expectedStatus: 200,
responseChecks: [
ResponseCheck('token', exists()),
ResponseCheck('user.id', isNotEmpty()),
],
),
],
);
await TestPilotRunner.runSuite(tester, loginSuite);
});
}
2. UI Interactions #
Tapping
// Tap by text
Tap.text('Submit')
// Tap by key
Tap.key('submit_button')
// Double tap
DoubleTap.text('Item')
// Long press
LongPress.widget('Menu Item')
// Disambiguate multiple elements
Tap.text('Submit').inContext('Login Form')
Tap.text('Delete').atPosition('first')
Text Input
// Type by hint text
Type.hint('Email').text('user@example.com')
// Type by label
Type.label('Full Name').text('John Doe')
// Type by key
Type.key('password_field').text('secret123')
// Clear and type
Type.hint('Search').clearAndType('flutter')
// Append to existing text
Type.hint('Notes').append(' - Additional info')
Gestures
// Drag and drop
DragDrop.fromTo(
fromText: 'Item 1',
toText: 'Drop Zone'
)
// Swipe to dismiss
Swipe.toDismiss(itemText: 'Notification')
// Scroll until visible
Scroll.untilVisible('Bottom Item')
// Pinch to zoom
Pinch.zoomIn(scale: 2.0, onType: InteractiveViewer)
// Pan in direction
Pan.inDirection(direction: PanDirection.left, distance: 100)
3. Test Suites and Organization #
final comprehensive_test = TestSuite(
name: 'User Registration',
description: 'Complete user registration flow with validation',
// Setup phase
setup: [
Tap.text('Get Started'),
// Navigate to registration
],
// Main test steps
steps: [
Type.hint('First Name').text('John'),
Type.hint('Last Name').text('Doe'),
Type.hint('Email').text('john.doe@example.com'),
Type.hint('Password').text('securePassword123'),
Tap.text('Register'),
],
// API validations
apis: [
Api.post(
id: 'register-user',
urlPattern: r'/api/users/register',
expectedStatus: 201,
requestChecks: [
RequestCheck('email', isEmail()),
RequestCheck('firstName', isNotEmpty()),
],
responseChecks: [
ResponseCheck('user.id', exists()),
ResponseCheck('message', contains('success')),
],
),
],
// Cleanup phase
cleanup: [
// Logout or reset state if needed
],
);
4. Test Groups #
final testGroup = TestGroup(
name: 'Authentication Tests',
description: 'Complete authentication flow testing',
suites: [
loginTestSuite,
registrationTestSuite,
forgotPasswordTestSuite,
],
stopOnFailure: true,
);
// Run the entire group
await TestPilotRunner.runGroup(tester, testGroup);
5. API Testing #
Setup API Interception
// In your main.dart or test setup
void main() {
final dio = Dio();
ApiObserverManager.initialize(dio); // Initialize API observation
runApp(MyApp(dio: dio));
}
API Validation Examples
// Basic API test
Api.get(
id: 'fetch-profile',
urlPattern: r'/api/user/profile',
responseChecks: [
ResponseCheck('name', isNotEmpty()),
ResponseCheck('email', isEmail()),
ResponseCheck('age', isGreaterThan(0)),
],
)
// Complex request validation
Api.post(
id: 'create-order',
urlPattern: r'/api/orders',
requestChecks: [
RequestCheck('items', isNotEmpty()),
RequestCheck('items[0].quantity', isGreaterThan(0)),
RequestCheck('total', isNumber()),
],
responseChecks: [
ResponseCheck('orderId', exists()),
ResponseCheck('status', equals('pending')),
],
)
6. Reporting #
Console Output
final consoleReporter = ConsoleReporter(
showDetails: true,
showTimings: true,
useColors: true,
);
// Report individual test
consoleReporter.reportTest(testResult);
// Report group results
consoleReporter.reportGroup('Auth Tests', results);
JSON Reports
final jsonReporter = JsonReporter(
prettyPrint: true,
outputFile: 'test_results.json',
);
// Generate comprehensive report
final report = jsonReporter.generateExecutionReport(
allResults,
environment: {
'platform': 'iOS',
'version': '16.0',
'device': 'iPhone 14'
},
);
await jsonReporter.outputReport(report);
Advanced Features #
Smart Widget Finding #
The framework uses multiple strategies to find widgets:
- By key (ValueKey, Key, GlobalKey)
- By text content
- By widget type
- By semantic labels
- By decoration properties (hint, label, helper text)
- By position and index
- By parent/child relationships
- By controller and focus node properties
Error Handling and Retries #
Pan.inDirection(
direction: PanDirection.left,
distance: 100,
maxRetries: 3,
onError: (e) => print('Pan failed: $e'),
waitForAnimation: true,
)
Context and Disambiguation #
// When multiple widgets match, use context
Tap.text('Submit')
.inContext('Payment Form')
.withRetry(maxAttempts: 2)
// Or specify position
Type.hint('Search')
.atPosition('first')
.clearAndType('flutter')
Custom Validations #
// Create custom validation functions
ValidationFunction isValidPrice() {
return (field, value) async {
if (value is num && value > 0) {
return ApiValidationResult.success(field, 'Valid price', value: value);
}
return ApiValidationResult.failure(field, 'Invalid price', actual: value);
};
}
// Use in API tests
ResponseCheck('price', isValidPrice())
Best Practices #
1. Organize Tests Logically #
// Group related functionality
final userManagementTests = TestGroup(
name: 'User Management',
suites: [
profileUpdateSuite,
passwordChangeSuite,
accountDeletionSuite,
],
);
2. Use Meaningful Test Names #
TestSuite(
name: 'Checkout - Payment Processing with Credit Card',
description: 'Validates complete payment flow including validation errors',
// ...
);
3. Validate Both UI and APIs #
steps: [
Type.hint('Amount').text('100.00'),
Tap.text('Pay Now'),
// Wait for UI feedback
WaitFor.text('Payment Successful', timeout: Duration(seconds: 5)),
],
apis: [
Api.post(
id: 'process-payment',
urlPattern: r'/api/payments',
expectedStatus: 200,
responseChecks: [
ResponseCheck('transactionId', exists()),
ResponseCheck('status', equals('completed')),
],
),
],
4. Handle Loading States #
steps: [
Tap.text('Load Data'),
WaitFor.text('Loading...', timeout: Duration(seconds: 2)),
WaitFor.textDisappears('Loading...', timeout: Duration(seconds: 10)),
Assert.textExists('Data loaded successfully'),
],
API Reference #
Core Classes #
FlutterTestPilot: Main entry point and singleton managerTestSuite: Container for organized test stepsTestGroup: Collection of test suitesTestResult: Results and metrics from test execution
UI Actions #
Tap,DoubleTap,TripleTap,LongPress: Touch interactionsType: Text input with smart field detectionDragDrop: Drag and drop operationsSwipe: Swipe gestures in all directionsScroll: Scrolling with position controlPan: Pan gestures with momentumPinch: Pinch-to-zoom operations
API Testing #
Api: Factory for creating API testsRequestCheck,ResponseCheck: Field validationApiObserverManager: HTTP interception and validation
Reporting #
ConsoleReporter: Rich console output with colorsJsonReporter: Structured JSON reports for CI/CD
Contributing #
Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.
License #
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog #
See CHANGELOG.md for a detailed list of changes and updates.