In this lesson we'll cover:
flutter_driver
packageYou can check out the step/step09
branch here which will contain the code for this lesson.
flutter_driver
package will run or "drive" our app for us.flutter_driver
package to start our app.flutter_driver
pubspec.yaml
file:# pubspec.yaml
# ...
dev_dependencies:
# ...
flutter_driver:
sdk: flutter
# ...
test/test_driver/app.dart
test/test_driver
flutter_driver
is initiated within a new main()
function within a new file called test/test_driver/app.dart
flutter_driver
then will invoke the main()
function of our app located in package:tourismandco/main.dart
:// test/test_driver/app.dart
import 'package:flutter_driver/driver_extension.dart';
import 'package:tourismandco/main.dart' as app;
void main() {
// This line enables the extension
enableFlutterDriverExtension();
// Call the `main()` function of your app or call `runApp` with any widget you
// are interested in testing.
app.main();
}
NOTE: Original source here.
flutter_driver
will provide a handy command to run this test/test_driver/app.dart
file: flutter drive --target=test_driver/app.dart
_test.dart
), create test/test_driver/app_test.dart
.lib/screens/locations/locations.dart
// lib/screens/locations/locations.dart
// ...
// NOTE _itemBuilder() is can existing method you'll have implemented in this file,
// so you're just adding the 'key' property here...
Widget _itemBuilder(BuildContext context, Location location) {
return GestureDetector(
// ...
key: Key('location_list_item_${location.id}'),
// ...
_itemBuilder()
is now uniquely identifyable in the Flutter widget tree.LocationTile
widget:// lib/widgets/location_tile.dart
// ...
@override
Widget build(BuildContext context) {
// ...
return Container(
// ...
children: [
Text(
// ..
key: Key('location_tile_name_${location.id}'),
// ...
Text
widget
in our LocationTile
.Locations
screen is loaded.// test/test_driver/app_test.dart
// Imports the Flutter Driver API
import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart';
import 'package:tourismandco/models/location.dart';
void main() {
group('happy path integration tests', () {
final locations = Location.fetchAll();
// First, define the Finders. We can use these to locate Widgets from the
// test suite. Note: the Strings provided to the `byValueKey` method must
// be the same as the Strings we used for the Keys in step 1.
final locationListItemTextFinder =
find.byValueKey('location_list_item_${locations.first.id}');
FlutterDriver driver;
// Connect to the Flutter driver before running any tests
setUpAll(() async {
driver = await FlutterDriver.connect();
});
// Close the connection to the driver after the tests have completed
tearDownAll(() async {
if (driver != null) {
driver.close();
}
});
test('a location name appears in location list', () async {
// Use the `driver.getText` method to verify the counter starts at 0.
expect(await driver.getText(locationTileOverlayTextFinder), isNotEmpty);
});
// NOTE one more test to come in the next step!
});
}
flutter drive <...>
, we can't just right click this test file and expect it to run.flutter
set in your PATH
environment variable. If you do not, check out my previous video on how to set up Flutter on macOS or Windows.cd <PATH TO YOUR tourismandco app>
then flutter drive --target=test_drive/app.dart
// test/test_driver/app_test.dart
// ...
void main() {
group('happy path integration tests', () {
// ...
final locationTileOverlayTextFinder =
find.byValueKey('location_tile_name_${locations.first.id}');
// ...
test('a location in the list is tappable', () async {
// First, tap on the button
await driver.tap(locationTileOverlayTextFinder);
// Use the `driver.getText` method to verify the counter starts at 0.
expect(await driver.getText(locationTileOverlayTextFinder), isNotEmpty);
});
// ...
group()
test case we've implemented in the previous step.