Integration test framework for Flutter web applications built on top of Chrome WebDriver.
Screencast running sample test
flutter-web-integration-test/
├── lib/ # Core library code
│ ├── chrome_driver_manager.dart # ChromeDriver management
│ └── test_dsl_parser.dart # JSON/YAML test DSL parser
├── bin/ # Executables
│ └── run_flutter_tests.dart # Flutter integration test runner
├── test_dsl/ # Test DSL files (JSON/YAML)
│ ├── sample_test.json # Sample test case (JSON)
│ ├── sample_test.yaml # Sample test case (YAML)
│ └── anchor_test.yaml # YAML anchor example
├── integration_test/ # Flutter integration test runner
│ └── dsl_runner.dart # Converts JSON/YAML DSL into Flutter tests
├── test_driver/ # Flutter driver
│ └── integration_test.dart # Integration test driver
├── test_target/ # Standalone Flutter web app under test
│ ├── lib/main.dart # Flutter app entry point
│ ├── pubspec.yaml # Flutter project configuration
│ └── web/ # Web build assets
├── drivers/ # ChromeDriver binaries
├── screenshots/ # Screenshot output when tests fail
├── config/ # Configuration files
│ └── chromedriver_config.json # ChromeDriver settings
└── test/ # Unit tests
dart pub getIf ChromeDriver is not installed, the test runner will ask whether it should install it automatically when you launch the tests.
You can also install it manually in advance:
# Automatic installation (downloads the matching version for Chrome)
dart run bin/install_chromedriver.dart
# Or download ChromeDriver yourself and place it under drivers/chromedriver# Run a single test file (YAML preferred, JSON also supported)
./test.sh test_dsl/sample_test.yaml
# Run multiple test files (supports glob patterns)
./test.sh "test_dsl/*.yaml"
./test.sh "test_dsl/**/*.yaml"
# Test a different Flutter app (auto-generates app_config.dart)
./test.sh test_dsl/* --target-app ../myapp
./test.sh test_dsl/* --target-app /path/to/app
# Pass additional Flutter arguments (e.g., --dart-define)
./test.sh test_dsl/* --dart-define flavor=local
./test.sh test_dsl/* --target-app ../myapp --dart-define ENV=prod
# Alternatively, point directly to an app directory (requires manual app_config.dart)
./test.sh test_dsl/sample_test.yaml /path/to/flutter/apptest.sh is a thin wrapper around dart run bin/run_flutter_tests.dart, so you can continue to invoke the Dart script directly if preferred.
Note: When tests run, symbolic links to integration_test/ and test_driver/ are created and automatically removed when execution finishes.
-
Add the
integration_testdependencydev_dependencies: flutter_test: sdk: flutter integration_test: sdk: flutter
-
Add Keys to widgets: Add identifiable keys to the widgets you want to test
TextFormField( key: const Key('username-input'), decoration: const InputDecoration(labelText: 'Username'), )
-
Write the test DSL: Use selectors like text,
key:, andtype:- action: type selector: "key:username-input" value: testuser
-
Run the tests
./test.sh my-test.yaml --target-app /path/to/your/flutter/app
Write your tests in YAML (JSON is also supported).
name: Test suite name
testCases:
- description: Test description
steps:
- action: click|type|wait|assert_text|assert_visible
selector: "Selector (if needed)"
value: Input value (for type actions)
expected: Expected value (for assert actions)
waitTime: Wait time in millisecondsUse YAML anchors and aliases to reuse repeated steps:
name: YAML Anchor Example
# Reusable step definitions
x-common-steps:
wait-short: &wait-short
action: wait
waitTime: 500
wait-long: &wait-long
action: wait
waitTime: 3000
testCases:
- description: Example test with anchors
steps:
- *wait-long # reference an anchor
- action: click
selector: "text:Button"
- *wait-shortclick: Tap or click a widgettype: Enter textwait: Pause for the given durationassert_text: Verify widget textassert_visible: Verify widget visibility
Selectors can be written as:
Button Text- Match exact text (no prefix required)Button Text[0]- Select the first match with that textcontains:partial text- Match partial textcontains:partial[1]- Select the second match for a partial textkey:my-widget-key- Match by widget keykey:my-key[0]- Select the first match by keylabel:Submit Button- Match by semantics labellabel:Submit[0]- Select the first match for a semantics labeltype:ElevatedButton- Match by widget typetype:TextField[2]- Select the third match for a widget type
Using indexes: When multiple widgets match, append [number] to target a specific instance (0-based).
Supported widget types:
ElevatedButton,TextButton,OutlinedButton,IconButtonTextField,TextFormFieldCheckbox,Radio,Switch
Screenshots are currently not available on the web.
takeScreenshot()in Flutter integration tests hangs on the web because of WebDriver session issues- The screenshot code is implemented but disabled
- It should work on mobile and desktop platforms
- Once the WebDriver session issue is resolved, screenshots can be re-enabled
To add a new action, modify the _executeStep function in integration_test/dsl_runner.dart.