Repository: gadfly361/flutter_test_cookbook Branch: master Commit: d40b6e325332 Files: 105 Total size: 162.3 KB Directory structure: gitextract_qjt8kukw/ ├── .gitignore ├── LICENSE ├── README.md └── recipes/ ├── flutter_driver/ │ ├── how_do_i_find_something/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── lib/ │ │ │ └── main.dart │ │ ├── pubspec.yaml │ │ └── test_driver/ │ │ ├── example.dart │ │ └── example_test.dart │ ├── how_do_i_pop_dialog/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── lib/ │ │ │ └── main.dart │ │ ├── pubspec.yaml │ │ └── test_driver/ │ │ ├── example.dart │ │ └── example_test.dart │ ├── how_do_i_run_a_flutter_driver_test/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── lib/ │ │ │ └── main.dart │ │ ├── pubspec.yaml │ │ └── test_driver/ │ │ ├── example.dart │ │ └── example_test.dart │ ├── how_do_i_run_a_script/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── echo.sh │ │ ├── lib/ │ │ │ └── main.dart │ │ ├── pubspec.yaml │ │ └── test_driver/ │ │ ├── example.dart │ │ └── example_test.dart │ ├── how_do_i_run_multiple_test_files_without_restarting_app/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── lib/ │ │ │ └── main.dart │ │ ├── pubspec.yaml │ │ ├── run_all_tests.sh │ │ └── test_driver/ │ │ ├── start_app.dart │ │ ├── suite1.dart │ │ ├── suite1_test.dart │ │ ├── suite2.dart │ │ └── suite2_test.dart │ └── how_do_i_take_a_screenshot/ │ ├── .gitignore │ ├── README.md │ ├── lib/ │ │ └── main.dart │ ├── pubspec.yaml │ └── test_driver/ │ ├── example.dart │ └── example_test.dart └── flutter_test/ ├── how_do_i_drag_something/ │ ├── .gitignore │ ├── README.md │ ├── lib/ │ │ └── main.dart │ ├── pubspec.yaml │ └── test/ │ └── widget_test.dart ├── how_do_i_find_something/ │ ├── .gitignore │ ├── README.md │ ├── lib/ │ │ └── main.dart │ ├── pubspec.yaml │ └── test/ │ └── widget_test.dart ├── how_do_i_mock_async_http_request/ │ ├── .gitignore │ ├── README.md │ ├── lib/ │ │ └── main.dart │ ├── pubspec.yaml │ └── test/ │ └── widget_test.dart ├── how_do_i_mock_shared_preferences/ │ ├── .gitignore │ ├── README.md │ ├── lib/ │ │ └── main.dart │ ├── pubspec.yaml │ └── test/ │ └── widget_test.dart ├── how_do_i_open_a_drawer/ │ ├── .gitignore │ ├── README.md │ ├── lib/ │ │ └── main.dart │ ├── pubspec.yaml │ └── test/ │ └── widget_test.dart ├── how_do_i_run_a_flutter_test/ │ ├── .gitignore │ ├── README.md │ ├── lib/ │ │ └── main.dart │ ├── pubspec.yaml │ └── test/ │ └── widget_test.dart ├── how_do_i_run_a_script/ │ ├── .gitignore │ ├── README.md │ ├── echo.sh │ ├── lib/ │ │ └── main.dart │ ├── pubspec.yaml │ └── test/ │ └── widget_test.dart ├── how_do_i_send_a_keyboard_action/ │ ├── .gitignore │ ├── README.md │ ├── lib/ │ │ └── main.dart │ ├── pubspec.yaml │ └── test/ │ └── widget_test.dart ├── how_do_i_test_an_animation/ │ ├── .gitignore │ ├── README.md │ ├── lib/ │ │ └── main.dart │ ├── pubspec.yaml │ └── test/ │ └── widget_test.dart ├── how_do_i_test_an_exception/ │ ├── .gitignore │ ├── README.md │ ├── lib/ │ │ └── main.dart │ ├── pubspec.yaml │ └── test/ │ └── widget_test.dart ├── how_do_i_test_routes/ │ ├── .gitignore │ ├── README.md │ ├── lib/ │ │ └── main.dart │ ├── pubspec.yaml │ └── test/ │ └── widget_test.dart └── what_if_i_need_build_context/ ├── .gitignore ├── README.md ├── lib/ │ └── main.dart ├── pubspec.yaml └── test/ └── widget_test.dart ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .idea/ *.*~ ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2020 Matthew Jaoudi Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # flutter_test_cookbook A community driven cookbook with _recipes_ (i.e., examples) on how to test your flutter application. ## Recipes There are [three pillars](https://flutter.dev/docs/cookbook/testing) of flutter tests: 1) unit 2) widget 3) integration This cookbook is mostly concerned with 2 and 3. Currently, [flutter_test](https://api.flutter.dev/flutter/flutter_test/flutter_test-library.html) is used for widget tests, and [flutter_driver](https://api.flutter.dev/flutter/flutter_driver/flutter_driver-library.html) is used for integration tests. However, it is possible that `flutter_driver` could eventually be deprecated, and `flutter_test` could be used for both widget and integration tests. We're moving away from flutter_driver in favour of extending flutter_test to work on devices. - Hixie https://github.com/flutter/flutter/issues/7474#issuecomment-558882182 Because of this, the recipes will be split out into two directories: `flutter_test` and `flutter_driver` ### flutter_test recipes - [How do I run a flutter test?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_test/how_do_i_run_a_flutter_test) - [How do I find something?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_test/how_do_i_find_something) - [How do I test routes?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_test/how_do_i_test_routes) - [How do I drag something?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_test/how_do_i_drag_something) - [How do I open a Drawer?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_test/how_do_i_open_a_drawer) - [How do I send a keyboard action like done or next?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_test/how_do_i_send_a_keyboard_action) - [How do I test an Exception?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_test/how_do_i_test_an_exception) - [What if I need a BuildContext?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_test/what_if_i_need_build_context) - [How do I run a script inside a test?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_test/how_do_i_run_a_script) - [How do I mock an async http request?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_test/how_do_i_mock_async_http_request) - [How do I mock shared_preferences?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_test/how_do_i_mock_shared_preferences) - [How do I test an animation?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_test/how_do_i_test_an_animation) ### flutter_driver recipes - [How do I run a flutter driver test?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_driver/how_do_i_run_a_flutter_driver_test) - [How do I find something?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_driver/how_do_i_find_something) - [How do I take a screenshot](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_driver/how_do_i_take_a_screenshot) - [How do I dismiss (i.e. pop) a dialog?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_driver/how_do_i_pop_dialog) - [How do I run a script inside of a test?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_driver/how_do_i_run_a_script) - [How I run multiple test files without restarting app?](https://github.com/gadfly361/flutter_test_cookbook/blob/master/recipes/flutter_driver/how_do_i_run_multiple_test_files_without_restarting_app) ## External Resources This section is a list of external resources that may be useful when exploring how to test your flutter application. *Written* - [Flutter UI Testing (with codemagic)](https://blog.codemagic.io/flutter-ui-testing/) - [Mock dependencies using Mockito](https://flutter.dev/docs/cookbook/testing/unit/mocking) - [Flutter: Golden tests - compare Widgets with Snapshots](https://medium.com/flutter-community/flutter-golden-tests-compare-widgets-with-snapshots-27f83f266cea) - [Testing gestures using Flutter driver](https://medium.com/flutter-community/testing-gestures-using-flutter-driver-b37981c24366) - [60 Days of Flutter: Day 4-5: Widget Testing with Flutter](https://medium.com/@adityadroid/60-days-of-flutter-day-4-5-widget-testing-with-flutter-a30236dd04fc) - [Blazingly Fast Flutter Driver Tests](https://medium.com/flutter-community/blazingly-fast-flutter-driver-tests-5e375c833aa) - [Developing and testing accessible apps in Flutter](https://medium.com/flutter-community/developing-and-testing-accessible-app-in-flutter-1dc1d33c7eea) *Videos* - [Flutter: Deep Dive with Widget Tests and Mockito](https://www.youtube.com/watch?v=75i5VmTI6A0) - [Bloc Test Tutorial - Easier Way to Test Blocs in Dart & Flutter](https://resocoder.com/2019/11/29/bloc-test-tutorial-easier-way-to-test-blocs-in-dart-flutter/) ## Want to contribute? First of all, thank you. Contributions are encouraged! Please follow the guidelines below. ### Want to suggest a recipe? If you'd like to suggest a recipe, please open an issue and add `[recipe-suggestion]` to the beginning of the title. ### Want to add your own recipe? If you'd like to add a recipe, please add `[new-recipe]` to the beginning of your PR's title. Each recipe should: - be focused on a specific topic - be concise - have runnable tests - only check in 'meaningful' files Note: if you want to get an early sense of whether or not your recipe will be accepted, please open a `[recipe-suggestion]` issue first. ### Want to fix a typo? If you'd like to fix a typo, please add `[fix-typo]` to the beginning of your PR's title. ### Want to correct an error in an existing recipe? If you'd like to correct an error in an existing recipe, please add `[fix-recipe]` to the beginning of your PR's title. ### Want to add a link to an external resource? If you'd like to add a link to an external resource, please add `[add-resource]` to the beginning of your PR's title. ## LICENSE Copyright © 2020 Matthew Jaoudi Distributed under the The MIT License (MIT). ================================================ FILE: recipes/flutter_driver/how_do_i_find_something/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (Driver) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test/ ================================================ FILE: recipes/flutter_driver/how_do_i_find_something/README.md ================================================ # Question How do I find something ... whether it be a widget, some text, etc? # Answer ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Add [flutter_driver](https://api.flutter.dev/flutter/flutter_driver/flutter_driver-library.html) and [test](https://pub.dev/packages/test) to your `pubspec.yaml` file. ```yaml dev_dependencies: flutter_driver: sdk: flutter test: any ``` Then get the dependencies by running: ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Column( children: [ RaisedButton( onPressed: () => print("rasied button was clicked"), child: Text("we will find this by searching for a type"), ), Text( "we will find this by searching for text", ), Text( "will will find this by searching for a key", key: Key("mykey"), ), ], ), ), ); } } ``` ## 4) Create a `test_driver` directory. ```sh mkdir test_driver cd test_driver ``` ## 5) Add an `example.dart` file. Create a `test_driver/example.dart` file, and add the following to it: ```dart import 'package:flutter_driver/driver_extension.dart'; import 'package:ftc/main.dart' as app; void main() { // Add the following to leverage flutter_driver enableFlutterDriverExtension(); app.main(); } ``` ## 6) Add an `example_test.dart` file. Create a `test_driver/example_test.dart` file, and add the following to it: ```dart import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; void main() { FlutterDriver driver; setUpAll(() async { driver = await FlutterDriver.connect(); }); tearDownAll(() async { if (driver != null) { await driver.close(); } }); test("let's find a widget by its type", () async { // There is a RaisedButton in the main.dart file SerializableFinder raisedButtonFinder = find.byType("RaisedButton"); await driver.waitFor(raisedButtonFinder); await driver.tap(raisedButtonFinder); }); test("let's find a specific string of text", () async { // This is the exact string of text found in a Text widget in the main.dart file SerializableFinder textFinder = find.text("we will find this by searching for text"); await driver.waitFor(textFinder); }); test("let's find a widget by its key", () async { // There is a widget with its key defined as `Key("mykey")` in the main.dart file SerializableFinder keyFinder = find.byValueKey("mykey"); await driver.waitFor(keyFinder); }); } ``` ## 7) Run the flutter driver tests ```sh flutter driver -t test_driver/example.dart ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter driver -t test_driver/example.dart ``` # Outputs when recipe was made / updated ## Output of running flutter driver tests ```sh $ flutter driver -t test_driver/example.dart Using device iPhone 8. Starting application: test_driver/example.dart Running Xcode build... ├─Assembling Flutter resources... 9.5s └─Compiling, linking and signing... 4.4s Xcode build done. 15.4s flutter: Observatory listening on http://127.0.0.1:62625/uVmgCkrhJno=/ 00:00 +0: (setUpAll) [info ] FlutterDriver: Connecting to Flutter application at http://127.0.0.1:62625/uVmgCkrhJno=/ [trace] FlutterDriver: Isolate found with number: 2547406183923599 [trace] FlutterDriver: Isolate is paused at start. [trace] FlutterDriver: Attempting to resume isolate [trace] FlutterDriver: Waiting for service extension [info ] FlutterDriver: Connected to Flutter application. 00:00 +0: let's find a widget by its type flutter: rasied button was clicked 00:00 +1: let's find a specific string of text 00:00 +2: let's find a widget by its key 00:00 +3: (tearDownAll) 00:00 +3: All tests passed! Stopping application instance. ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [✓] Connected device (1 available) • iPhone 8 • AD7A90EB-5E73-427E-B9B7-DD3B07E2FEF1 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-3 (simulator) • No issues found! ``` ================================================ FILE: recipes/flutter_driver/how_do_i_find_something/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Column( children: [ RaisedButton( onPressed: () => print("rasied button was clicked"), child: Text("we will find this by searching for a type"), ), Text( "we will find this by searching for text", ), Text( "will will find this by searching for a key", key: Key("mykey"), ), ], ), ), ); } } ================================================ FILE: recipes/flutter_driver/how_do_i_find_something/pubspec.yaml ================================================ name: ftc description: A new Flutter project. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_driver: sdk: flutter test: any ================================================ FILE: recipes/flutter_driver/how_do_i_find_something/test_driver/example.dart ================================================ import 'package:flutter_driver/driver_extension.dart'; import 'package:ftc/main.dart' as app; void main() { // Add the following to leverage flutter_driver enableFlutterDriverExtension(); app.main(); } ================================================ FILE: recipes/flutter_driver/how_do_i_find_something/test_driver/example_test.dart ================================================ import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; void main() { FlutterDriver driver; setUpAll(() async { driver = await FlutterDriver.connect(); }); tearDownAll(() async { if (driver != null) { await driver.close(); } }); test("let's find a widget by its type", () async { // There is a RaisedButton in the main.dart file SerializableFinder raisedButtonFinder = find.byType("RaisedButton"); await driver.waitFor(raisedButtonFinder); await driver.tap(raisedButtonFinder); }); test("let's find a specific string of text", () async { // This is the exact string of text found in a Text widget in the main.dart file SerializableFinder textFinder = find.text("we will find this by searching for text"); await driver.waitFor(textFinder); }); test("let's find a widget by its key", () async { // There is a widget with its key defined as `Key("mykey")` in the main.dart file SerializableFinder keyFinder = find.byValueKey("mykey"); await driver.waitFor(keyFinder); }); } ================================================ FILE: recipes/flutter_driver/how_do_i_pop_dialog/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (Driver) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test/ ================================================ FILE: recipes/flutter_driver/how_do_i_pop_dialog/README.md ================================================ # Question How do I dismiss a [Dialog](https://api.flutter.dev/flutter/material/Dialog-class.html) that doesn't have an explicit widget to do so? # Answer You may find yourself creating a Dialog that relies on a user pressing on the [ModalBarrier](https://api.flutter.dev/flutter/widgets/ModalBarrier-class.html) to dismiss it (as opposed to them clicking on an explicit widget like a button). In this situation, we can use the [Navigator](https://api.flutter.dev/flutter/dart-html/Navigator-class.html) to pop the Dialog from the stack (i.e. dismiss the Dialog). To do so, we can to take advantage of the [DataHandler](https://api.flutter.dev/flutter/flutter_driver_extension/DataHandler.html) found in the [enableFlutterDriverExtension](https://api.flutter.dev/flutter/flutter_driver_extension/enableFlutterDriverExtension.html) function. ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Add [flutter_driver](https://api.flutter.dev/flutter/flutter_driver/flutter_driver-library.html) and [test](https://pub.dev/packages/test) to your `pubspec.yaml` file. ```yaml dev_dependencies: flutter_driver: sdk: flutter test: any ``` Then get the dependencies by running: ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); GlobalKey appNavigatorKey = GlobalKey(); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( // Note: we are adding a navigatorKey here navigatorKey: appNavigatorKey, home: Scaffold( body: Body(), ), ); } } class Body extends StatelessWidget { @override Widget build(BuildContext context) { return Center( child: RaisedButton( child: Text("Open Dialog"), onPressed: () { showDialog( context: context, builder: (BuildContext _context) { return Dialog( child: SizedBox( height: 100, child: Center( child: Text("This is a Dialog"), ), ), ); }, ); }, ), ); } } ``` ## 4) Create a `test_driver` directory. ```sh mkdir test_driver cd test_driver ``` ## 5) Add an `example.dart` file. Create a `test_driver/example.dart` file, and add the following to it: ```dart import 'package:flutter_driver/driver_extension.dart'; import 'package:ftc/main.dart' as app; Future dataHandler(String message) async { // We are using the data handler to execute a pop side-effect if (message == "pop") { app.appNavigatorKey.currentState.pop(); } return null; } void main() { enableFlutterDriverExtension( // we are adding the dataHandler here handler: dataHandler, ); app.main(); } ``` ## 6) Add an `example_test.dart` file. Create a `test_driver/example_test.dart` file, and add the following to it: ```dart import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; void main() { FlutterDriver driver; setUpAll(() async { driver = await FlutterDriver.connect(); }); tearDownAll(() async { if (driver != null) { await driver.close(); } }); test("let's open a dialog and then close it", () async { SerializableFinder raisedButtonFinder = find.byType("RaisedButton"); await driver.waitFor(raisedButtonFinder); // tapping the button opens the Dialog await driver.tap(raisedButtonFinder); // make sure the the Dialog is open SerializableFinder dialogFinder = find.byType("Dialog"); await driver.waitFor(dialogFinder); // now, let's close the dialog using the dataHandler we defined in // our [enableFlutterDriverExtension] function. await driver.requestData("pop"); // finally, let's wait to make sure the Dialog is gone await driver.waitForAbsent(dialogFinder); }); } ``` ## 7) Run the flutter driver tests ```sh flutter driver -t test_driver/example.dart ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter driver -t test_driver/example.dart ``` # Outputs when recipe was made / updated ## Output of running flutter driver tests ```sh $ flutter driver -t test_driver/example.dart Using device iPhone 8. Starting application: test_driver/example.dart Running Xcode build... ├─Assembling Flutter resources... 2.6s └─Compiling, linking and signing... 2.9s Xcode build done. 6.6s flutter: Observatory listening on http://127.0.0.1:51796/uIFIjnNgNMs=/ 00:00 +0: (setUpAll) [info ] FlutterDriver: Connecting to Flutter application at http://127.0.0.1:51796/uIFIjnNgNMs=/ [trace] FlutterDriver: Isolate found with number: 491196511285567 [trace] FlutterDriver: Isolate is paused at start. [trace] FlutterDriver: Attempting to resume isolate [trace] FlutterDriver: Waiting for service extension [info ] FlutterDriver: Connected to Flutter application. 00:00 +0: let's open a dialog and then close it 00:00 +1: (tearDownAll) 00:00 +1: All tests passed! Stopping application instance. ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [✓] Connected device (1 available) • iPhone 8 • AD7A90EB-5E73-427E-B9B7-DD3B07E2FEF1 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-3 (simulator) • No issues found! ``` ================================================ FILE: recipes/flutter_driver/how_do_i_pop_dialog/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); GlobalKey appNavigatorKey = GlobalKey(); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( // Note: we are adding a navigatorKey here navigatorKey: appNavigatorKey, home: Scaffold( body: Body(), ), ); } } class Body extends StatelessWidget { @override Widget build(BuildContext context) { return Center( child: RaisedButton( child: Text("Open Dialog"), onPressed: () { showDialog( context: context, builder: (BuildContext _context) { return Dialog( child: SizedBox( height: 100, child: Center( child: Text("This is a Dialog"), ), ), ); }, ); }, ), ); } } ================================================ FILE: recipes/flutter_driver/how_do_i_pop_dialog/pubspec.yaml ================================================ name: ftc description: A new Flutter project. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_driver: sdk: flutter test: any ================================================ FILE: recipes/flutter_driver/how_do_i_pop_dialog/test_driver/example.dart ================================================ import 'package:flutter_driver/driver_extension.dart'; import 'package:ftc/main.dart' as app; Future dataHandler(String message) async { // We are using the data handler to execute a pop side-effect if (message == "pop") { app.appNavigatorKey.currentState.pop(); } return null; } void main() { enableFlutterDriverExtension( // we are adding the dataHandler here handler: dataHandler, ); app.main(); } ================================================ FILE: recipes/flutter_driver/how_do_i_pop_dialog/test_driver/example_test.dart ================================================ import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; void main() { FlutterDriver driver; setUpAll(() async { driver = await FlutterDriver.connect(); }); tearDownAll(() async { if (driver != null) { await driver.close(); } }); test("let's open a dialog and then close it", () async { SerializableFinder raisedButtonFinder = find.byType("RaisedButton"); await driver.waitFor(raisedButtonFinder); // tapping the button opens the Dialog await driver.tap(raisedButtonFinder); // make sure the the Dialog is open SerializableFinder dialogFinder = find.byType("Dialog"); await driver.waitFor(dialogFinder); // now, let's close the dialog using the dataHandler we defined in // our [enableFlutterDriverExtension] function. await driver.requestData("pop"); // finally, let's wait to make sure the Dialog is gone await driver.waitForAbsent(dialogFinder); }); } ================================================ FILE: recipes/flutter_driver/how_do_i_run_a_flutter_driver_test/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (Driver) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test/ ================================================ FILE: recipes/flutter_driver/how_do_i_run_a_flutter_driver_test/README.md ================================================ # Question How do I run a [flutter driver](https://api.flutter.dev/flutter/flutter_driver/flutter_driver-library.html) test? # Answer ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Add [flutter_driver](https://api.flutter.dev/flutter/flutter_driver/flutter_driver-library.html) and [test](https://pub.dev/packages/test) to your `pubspec.yaml` file. ```yaml dev_dependencies: flutter_driver: sdk: flutter test: any ``` Then get the dependencies by running: ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Text("Hello world"), ), ), ); } } ``` ## 4) Create a `test_driver` directory. ```sh mkdir test_driver cd test_driver ``` ## 5) Add an `example.dart` file. Create a `test_driver/example.dart` file, and add the following to it: ```dart import 'package:flutter_driver/driver_extension.dart'; import 'package:ftc/main.dart' as app; void main() { // Add the following to leverage flutter_driver enableFlutterDriverExtension(); app.main(); } ``` [Reference](https://flutter.dev/docs/cookbook/testing/integration/introduction#4-instrument-the-app) ## 6) Add an `example_test.dart` file. Create a `test_driver/example_test.dart` file, and add the following to it: ```dart import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; void main() { FlutterDriver driver; setUpAll(() async { driver = await FlutterDriver.connect(); }); tearDownAll(() async { if (driver != null) { await driver.close(); } }); test("'Hello world' text exists", () async { SerializableFinder helloWorldTextFinder = find.text("Hello world"); await driver.waitFor(helloWorldTextFinder); }); } ``` ## 7) Run the flutter driver tests ```sh flutter driver -t test_driver/example.dart ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter driver -t test_driver/example.dart ``` # Outputs when recipe was made / updated ## Output of running flutter driver tests ```sh $ flutter driver -t test_driver/example.dart Using device iPhone 8. Starting application: test_driver/example.dart Running Xcode build... ├─Assembling Flutter resources... 7.9s └─Compiling, linking and signing... 4.1s Xcode build done. 13.2s flutter: Observatory listening on http://127.0.0.1:60787/uPVFLEOkdqo=/ 00:00 +0: (setUpAll) [info ] FlutterDriver: Connecting to Flutter application at http://127.0.0.1:60787/uPVFLEOkdqo=/ [trace] FlutterDriver: Isolate found with number: 4366875479017451 [trace] FlutterDriver: Isolate is paused at start. [trace] FlutterDriver: Attempting to resume isolate [trace] FlutterDriver: Waiting for service extension [info ] FlutterDriver: Connected to Flutter application. 00:00 +0: 'Hello world' text exists 00:00 +1: (tearDownAll) 00:00 +1: All tests passed! Stopping application instance. ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (7 weeks ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.2) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 42.1.4 • Dart plugin version 193.6015.9 [✓] VS Code (version 1.40.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [✓] Connected device (1 available) • iPhone 8 • AD7A90EB-5E73-427E-B9B7-DD3B07E2FEF1 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-3 (simulator) • No issues found! ``` ================================================ FILE: recipes/flutter_driver/how_do_i_run_a_flutter_driver_test/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Text("Hello world"), ), ), ); } } ================================================ FILE: recipes/flutter_driver/how_do_i_run_a_flutter_driver_test/pubspec.yaml ================================================ name: ftc version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_driver: sdk: flutter test: any ================================================ FILE: recipes/flutter_driver/how_do_i_run_a_flutter_driver_test/test_driver/example.dart ================================================ import 'package:flutter_driver/driver_extension.dart'; import 'package:ftc/main.dart' as app; void main() { // Add the following to leverage flutter_driver enableFlutterDriverExtension(); app.main(); } ================================================ FILE: recipes/flutter_driver/how_do_i_run_a_flutter_driver_test/test_driver/example_test.dart ================================================ import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; void main() { FlutterDriver driver; setUpAll(() async { driver = await FlutterDriver.connect(); }); tearDownAll(() async { if (driver != null) { await driver.close(); } }); test("'Hello world' text exists", () async { SerializableFinder helloWorldTextFinder = find.text("Hello world"); await driver.waitFor(helloWorldTextFinder); }); } ================================================ FILE: recipes/flutter_driver/how_do_i_run_a_script/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (Driver) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test/ ================================================ FILE: recipes/flutter_driver/how_do_i_run_a_script/README.md ================================================ # Question How do I run a script inside of a test? # Answer Use [Process.run](https://api.dart.dev/stable/2.7.1/dart-io/Process/run.html) ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Add [flutter_driver](https://api.flutter.dev/flutter/flutter_driver/flutter_driver-library.html) and [test](https://pub.dev/packages/test) to your `pubspec.yaml` file. ```yaml dev_dependencies: flutter_driver: sdk: flutter test: any ``` Then get the dependencies by running: ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Text("A script will be run during the test"), ), ), ); } } ``` ## 4) Create a `test_driver` directory. ```sh mkdir test_driver cd test_driver ``` ## 5) Add an `example.dart` file. Create a `test_driver/example.dart` file, and add the following to it: ```dart import 'package:flutter_driver/driver_extension.dart'; import 'package:ftc/main.dart' as app; void main() { // Add the following to leverage flutter_driver enableFlutterDriverExtension(); app.main(); } ``` ## 6) Add an `example_test.dart` file. Create a `test_driver/example_test.dart` file, and add the following to it: ```dart import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; import 'dart:io'; void main() { FlutterDriver driver; setUpAll(() async { driver = await FlutterDriver.connect(); }); tearDownAll(() async { if (driver != null) { await driver.close(); } }); test("How do I run a script inside of a test?", () async { ProcessResult result = await Process.run('./echo.sh', ['1']); // Note: echo appends a newline to the result expect(result.stdout, '1\n'); }); } ``` ## 7) Add an `echo.sh` script Create a file called `echo.sh` and add the following to it: ```sh #!/bin/bash echo "$1" ``` Then run: ```sh chmod +x echo.sh ``` ## 8) Run the flutter driver tests ```sh flutter driver -t test_driver/example.dart ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter driver -t test_driver/example.dart ``` # Outputs when recipe was made / updated ## Output of running flutter driver tests ```sh $ flutter driver -t test_driver/example.dart Using device iPhone 8. Starting application: test_driver/example.dart Running Xcode build... ├─Assembling Flutter resources... 2.5s └─Compiling, linking and signing... ⣷^R 3.0s Xcode build done. 6.7s flutter: Observatory listening on http://127.0.0.1:63926/-gi_tJzC8oY=/ 00:00 +0: (setUpAll) [info ] FlutterDriver: Connecting to Flutter application at http://127.0.0.1:63926/-gi_tJzC8oY=/ [trace] FlutterDriver: Isolate found with number: 3688768521236175 [trace] FlutterDriver: Isolate is paused at start. [trace] FlutterDriver: Attempting to resume isolate [trace] FlutterDriver: Waiting for service extension [info ] FlutterDriver: Connected to Flutter application. 00:00 +0: How do I run a script inside of a test? 00:00 +1: (tearDownAll) 00:00 +1: All tests passed! ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [✓] Connected device (1 available) • iPhone 8 • AD7A90EB-5E73-427E-B9B7-DD3B07E2FEF1 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-3 (simulator) • No issues found! ``` ================================================ FILE: recipes/flutter_driver/how_do_i_run_a_script/echo.sh ================================================ #!/bin/bash echo "$1" ================================================ FILE: recipes/flutter_driver/how_do_i_run_a_script/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Text("A script will be run during the test"), ), ), ); } } ================================================ FILE: recipes/flutter_driver/how_do_i_run_a_script/pubspec.yaml ================================================ name: ftc version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_driver: sdk: flutter test: any ================================================ FILE: recipes/flutter_driver/how_do_i_run_a_script/test_driver/example.dart ================================================ import 'package:flutter_driver/driver_extension.dart'; import 'package:ftc/main.dart' as app; void main() { // Add the following to leverage flutter_driver enableFlutterDriverExtension(); app.main(); } ================================================ FILE: recipes/flutter_driver/how_do_i_run_a_script/test_driver/example_test.dart ================================================ import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; import 'dart:io'; void main() { FlutterDriver driver; setUpAll(() async { driver = await FlutterDriver.connect(); }); tearDownAll(() async { if (driver != null) { await driver.close(); } }); test("How do I run a script inside of a test?", () async { ProcessResult result = await Process.run('./echo.sh', ['1']); // Note: echo appends a newline to the result expect(result.stdout, '1\n'); }); } ================================================ FILE: recipes/flutter_driver/how_do_i_run_multiple_test_files_without_restarting_app/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (Driver) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test/ ================================================ FILE: recipes/flutter_driver/how_do_i_run_multiple_test_files_without_restarting_app/README.md ================================================ # Question How do I run multiple test files without restarting the app? # Answer We are going to start an app, record its uri, then run our test suites referencing an existing app at the uri. ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Add [flutter_driver](https://api.flutter.dev/flutter/flutter_driver/flutter_driver-library.html) and [test](https://pub.dev/packages/test) to your `pubspec.yaml` file. ```yaml dev_dependencies: flutter_driver: sdk: flutter test: any ``` Then get the dependencies by running: ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Column(children: [ Text("Suite 1 will check this"), Text("Suite 2 will check this"), ]), ), ); } } ``` ## 4) Create a `test_driver` directory. ```sh mkdir test_driver cd test_driver ``` ## 5) Add a `start_app.dart` file. Create a `test_driver/start_app.dart` file, and add the following to it: ```dart import 'package:flutter_driver/driver_extension.dart'; import 'package:ftc/main.dart' as app; void main() { enableFlutterDriverExtension(); app.main(); } ``` ## 6) Add a `suite1.dart` file and a `suite1_test.dart` file Create a `test_driver/suite1.dart` file, and add the following to it: ```dart // Note: this is intentionally blank, // but the existence of this file is still needed // for flutter drive to run the tests ``` Then create a `test_driver/suite1_test.dart` file, and add the following to it: ```dart import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; void main() { FlutterDriver driver; setUpAll(() async { driver = await FlutterDriver.connect(); }); tearDownAll(() async { if (driver != null) { await driver.close(); } }); test("Suite 1", () async { SerializableFinder textFinder = find.text("Suite 1 will check this"); await driver.waitFor(textFinder); }); } ``` ## 7) Add a `suite2.dart` file and a `suite2_test.dart` file Create a `test_driver/suite2.dart` file, and add the following to it: ```dart // Note: this is intentionally blank, // but the existence of this file is still needed // for flutter drive to run the tests ``` Then create a `test_driver/suite2_test.dart` file, and add the following to it: ```dart import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; void main() { FlutterDriver driver; setUpAll(() async { driver = await FlutterDriver.connect(); }); tearDownAll(() async { if (driver != null) { await driver.close(); } }); test("Suite 2", () async { SerializableFinder textFinder = find.text("Suite 2 will check this"); await driver.waitFor(textFinder); }); } ``` ## 8) Add a `run_all_tests.sh` file Create a `run_all_tests.sh` file and add the following to it: ```sh #!/bin/bash # start the app and write the uri to a file flutter run --target=test_driver/start_app.dart --vmservice-out-file="test_driver/uri.txt" --start-paused --no-resident # run the test suites using the uri in the aforementioned file flutter driver --target=test_driver/suite1.dart --use-existing-app="$(cat test_driver/uri.txt)" flutter driver --target=test_driver/suite2.dart --use-existing-app="$(cat test_driver/uri.txt)" ``` Then make it executable by running ```sh chmod +x run_all_tests.sh ``` ## 8) Run the flutter driver tests ```sh ./run_all_tests.sh ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get ./run_all_tests.sh ``` # Outputs when recipe was made / updated ## Output of running flutter driver tests ```sh $ ./run_all_tests.sh Launching test_driver/start_app.dart on iPhone 8 in debug mode... Running Xcode build... ├─Assembling Flutter resources... 2.6s └─Compiling, linking and signing... 2.9s Xcode build done. 6.7s Syncing files to device iPhone 8... 4,776ms (!) Using device iPhone 8. Will connect to already running application instance. 00:00 +0: (setUpAll) [info ] FlutterDriver: Connecting to Flutter application at ws://127.0.0.1:56503/87Z5gLVG5E8=/ws [trace] FlutterDriver: Isolate found with number: 1576235581101003 [trace] FlutterDriver: Isolate is paused at start. [trace] FlutterDriver: Attempting to resume isolate [trace] FlutterDriver: Waiting for service extension [info ] FlutterDriver: Connected to Flutter application. 00:00 +0: Suite 1 00:00 +1: (tearDownAll) 00:00 +1: All tests passed! Leaving the application running. Using device iPhone 8. Will connect to already running application instance. 00:00 +0: (setUpAll) [info ] FlutterDriver: Connecting to Flutter application at ws://127.0.0.1:56503/87Z5gLVG5E8=/ws [trace] FlutterDriver: Isolate found with number: 1576235581101003 [trace] FlutterDriver: Isolate is not paused. Assuming application is ready. [info ] FlutterDriver: Connected to Flutter application. 00:00 +0: Suite 2 00:00 +1: (tearDownAll) 00:00 +1: All tests passed! Leaving the application running. ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [✓] Connected device (1 available) • iPhone 8 • AD7A90EB-5E73-427E-B9B7-DD3B07E2FEF1 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-3 (simulator) • No issues found! ``` ================================================ FILE: recipes/flutter_driver/how_do_i_run_multiple_test_files_without_restarting_app/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Column(children: [ Text("Suite 1 will check this"), Text("Suite 2 will check this"), ]), ), ); } } ================================================ FILE: recipes/flutter_driver/how_do_i_run_multiple_test_files_without_restarting_app/pubspec.yaml ================================================ name: ftc version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_driver: sdk: flutter test: any ================================================ FILE: recipes/flutter_driver/how_do_i_run_multiple_test_files_without_restarting_app/run_all_tests.sh ================================================ #!/bin/bash # start the app and write the uri to a file flutter run --target=test_driver/start_app.dart --vmservice-out-file="test_driver/uri.txt" --start-paused --no-resident # run the test suites using the uri in the aforementioned file flutter driver --target=test_driver/suite1.dart --use-existing-app="$(cat test_driver/uri.txt)" flutter driver --target=test_driver/suite2.dart --use-existing-app="$(cat test_driver/uri.txt)" ================================================ FILE: recipes/flutter_driver/how_do_i_run_multiple_test_files_without_restarting_app/test_driver/start_app.dart ================================================ import 'package:flutter_driver/driver_extension.dart'; import 'package:ftc/main.dart' as app; void main() { // Add the following to leverage flutter_driver enableFlutterDriverExtension(); app.main(); } ================================================ FILE: recipes/flutter_driver/how_do_i_run_multiple_test_files_without_restarting_app/test_driver/suite1.dart ================================================ // Note: this is intentionally blank, // but the existence of this file is still needed // for flutter drive to run the tests ================================================ FILE: recipes/flutter_driver/how_do_i_run_multiple_test_files_without_restarting_app/test_driver/suite1_test.dart ================================================ import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; void main() { FlutterDriver driver; setUpAll(() async { driver = await FlutterDriver.connect(); }); tearDownAll(() async { if (driver != null) { await driver.close(); } }); test("Suite 1", () async { SerializableFinder textFinder = find.text("Suite 1 will check this"); await driver.waitFor(textFinder); }); } ================================================ FILE: recipes/flutter_driver/how_do_i_run_multiple_test_files_without_restarting_app/test_driver/suite2.dart ================================================ // Note: this is intentionally blank, // but the existence of this file is still needed // for flutter drive to run the tests ================================================ FILE: recipes/flutter_driver/how_do_i_run_multiple_test_files_without_restarting_app/test_driver/suite2_test.dart ================================================ import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; void main() { FlutterDriver driver; setUpAll(() async { driver = await FlutterDriver.connect(); }); tearDownAll(() async { if (driver != null) { await driver.close(); } }); test("Suite 2", () async { SerializableFinder textFinder = find.text("Suite 2 will check this"); await driver.waitFor(textFinder); }); } ================================================ FILE: recipes/flutter_driver/how_do_i_take_a_screenshot/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (Driver) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test/ ================================================ FILE: recipes/flutter_driver/how_do_i_take_a_screenshot/README.md ================================================ # Question How do I take a screenshot? # Answer ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Add [flutter_driver](https://api.flutter.dev/flutter/flutter_driver/flutter_driver-library.html) and [test](https://pub.dev/packages/test) to your `pubspec.yaml` file. ```yaml dev_dependencies: flutter_driver: sdk: flutter test: any ``` Then get the dependencies by running: ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Text("Take a screenshot of me"), ), ), ); } } ``` ## 4) Create a `test_driver` directory. ```sh mkdir test_driver cd test_driver ``` ## 5) Add an `example.dart` file. Create a `test_driver/example.dart` file, and add the following to it: ```dart import 'package:flutter_driver/driver_extension.dart'; import 'package:ftc/main.dart' as app; void main() { // Add the following to leverage flutter_driver enableFlutterDriverExtension(); app.main(); } ``` ## 6) Add an `example_test.dart` file. Create a `test_driver/example_test.dart` file, and add the following to it: ```dart import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; import 'dart:io' show File; void main() { FlutterDriver driver; setUpAll(() async { driver = await FlutterDriver.connect(); }); tearDownAll(() async { if (driver != null) { await driver.close(); } }); test("How do I take a screenshot?", () async { // It is good practice to call this before taking a screenshot // to ensure everything has settled await driver.waitUntilNoTransientCallbacks(); // Take the screenshot and store as a list of ints // Note: the image will be returned as a PNG final List screenshotPixels = await driver.screenshot(); // Write to a file final File screenshotFile = new File("my_screenshot.png"); await screenshotFile.writeAsBytes(screenshotPixels); }); } ``` ## 7) Run the flutter driver tests ```sh flutter driver -t test_driver/example.dart ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter driver -t test_driver/example.dart ``` # Outputs when recipe was made / updated ## Output of running flutter driver tests ```sh $ flutter driver -t test_driver/example.dart Using device iPhone 8. Starting application: test_driver/example.dart Running Xcode build... ├─Assembling Flutter resources... 2.5s └─Compiling, linking and signing... 2.8s Xcode build done. 6.5s flutter: Observatory listening on http://127.0.0.1:57202/-lHi4AILSr8=/ 00:00 +0: (setUpAll) [info ] FlutterDriver: Connecting to Flutter application at http://127.0.0.1:57202/-lHi4AILSr8=/ [trace] FlutterDriver: Isolate found with number: 2332930742028219 [trace] FlutterDriver: Isolate is paused at start. [trace] FlutterDriver: Attempting to resume isolate [trace] FlutterDriver: Waiting for service extension [info ] FlutterDriver: Connected to Flutter application. 00:00 +0: How do I take a screenshot? 00:02 +1: (tearDownAll) 00:02 +1: All tests passed! Stopping application instance. ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [✓] Connected device (1 available) • iPhone 8 • AD7A90EB-5E73-427E-B9B7-DD3B07E2FEF1 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-3 (simulator) • No issues found! ``` ================================================ FILE: recipes/flutter_driver/how_do_i_take_a_screenshot/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Text("Take a screenshot of me"), ), ), ); } } ================================================ FILE: recipes/flutter_driver/how_do_i_take_a_screenshot/pubspec.yaml ================================================ name: ftc version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_driver: sdk: flutter test: any ================================================ FILE: recipes/flutter_driver/how_do_i_take_a_screenshot/test_driver/example.dart ================================================ import 'package:flutter_driver/driver_extension.dart'; import 'package:ftc/main.dart' as app; void main() { // Add the following to leverage flutter_driver enableFlutterDriverExtension(); app.main(); } ================================================ FILE: recipes/flutter_driver/how_do_i_take_a_screenshot/test_driver/example_test.dart ================================================ import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; import 'dart:io' show File; void main() { FlutterDriver driver; setUpAll(() async { driver = await FlutterDriver.connect(); }); tearDownAll(() async { if (driver != null) { await driver.close(); } }); test("How do I take a screenshot?", () async { // It is good practice to call this before taking a screenshot // to ensure everything has settled await driver.waitUntilNoTransientCallbacks(); // Take the screenshot and store as a list of ints // Note: the image will be returned as a PNG final List screenshotPixels = await driver.screenshot(); // Write to a file final File screenshotFile = new File("my_screenshot.png"); await screenshotFile.writeAsBytes(screenshotPixels); }); } ================================================ FILE: recipes/flutter_test/how_do_i_drag_something/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (flutter_test) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test_driver/ ================================================ FILE: recipes/flutter_test/how_do_i_drag_something/README.md ================================================ # Question How do I drag something? # Answer ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Get dependencies ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(), body: Body(), ), ); } } class Body extends StatefulWidget { @override _BodyState createState() => _BodyState(); } class _BodyState extends State { bool isDragAccepted = false; @override Widget build(BuildContext context) { return Column( children: [ Draggable( feedback: Container( height: 100, width: 100, decoration: BoxDecoration( border: Border.all(width: 2.0, color: Colors.black), ), ), child: Container( height: 100, width: 100, decoration: BoxDecoration( border: Border.all(width: 2.0, color: Colors.black), ), child: Center( child: Text("Draggable"), ), ), childWhenDragging: Container( height: 100, width: 100, decoration: BoxDecoration( border: Border.all(width: 2.0, color: Colors.grey), ), ), ), DragTarget( onAccept: (data) { setState(() { isDragAccepted = true; }); }, builder: (BuildContext context, candidateData, rejectedData) { return Container( height: 100, width: 100, decoration: BoxDecoration( border: Border.all( width: 2.0, color: isDragAccepted ? Colors.green : Colors.black), ), child: Center( child: Text(isDragAccepted ? "Successful drag!" : "Drag Target"), ), ); }, ), ], ); } } ``` ## 4) Replace the `test/widget_test.dart` file. Replace the `test/widget_test.dart` file with the following: ```dart import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets("How do I drag something?", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); Finder draggableFinder = find.text("Draggable"); Finder dragTargetFinder = find.text("Drag Target"); expect(draggableFinder, findsOneWidget); expect(dragTargetFinder, findsOneWidget); await tester.drag(draggableFinder, Offset(0, 100)); await tester.pump(); expect(dragTargetFinder, findsNothing); Finder successfulDragFinder = find.text("Successful drag!"); expect(successfulDragFinder, findsOneWidget); }); } ``` ## 5) Run the flutter tests ```sh flutter test ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter test ``` # Outputs when recipe was made / updated ## Output of running flutter tests ```sh $ flutter test 00:02 +1: All tests passed! ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [!] Connected device • Device 9C251FFBA00174 is not authorized. You might need to check your device for an authorization dialog. ! Doctor found issues in 1 category. ``` ================================================ FILE: recipes/flutter_test/how_do_i_drag_something/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(), body: Body(), ), ); } } class Body extends StatefulWidget { @override _BodyState createState() => _BodyState(); } class _BodyState extends State { bool isDragAccepted = false; @override Widget build(BuildContext context) { return Column( children: [ Draggable( feedback: Container( height: 100, width: 100, decoration: BoxDecoration( border: Border.all(width: 2.0, color: Colors.black), ), ), child: Container( height: 100, width: 100, decoration: BoxDecoration( border: Border.all(width: 2.0, color: Colors.black), ), child: Center( child: Text("Draggable"), ), ), childWhenDragging: Container( height: 100, width: 100, decoration: BoxDecoration( border: Border.all(width: 2.0, color: Colors.grey), ), ), ), DragTarget( onAccept: (data) { setState(() { isDragAccepted = true; }); }, builder: (BuildContext context, candidateData, rejectedData) { return Container( height: 100, width: 100, decoration: BoxDecoration( border: Border.all( width: 2.0, color: isDragAccepted ? Colors.green : Colors.black), ), child: Center( child: Text(isDragAccepted ? "Successful drag!" : "Drag Target"), ), ); }, ), ], ); } } ================================================ FILE: recipes/flutter_test/how_do_i_drag_something/pubspec.yaml ================================================ name: ftc description: A new Flutter project. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter ================================================ FILE: recipes/flutter_test/how_do_i_drag_something/test/widget_test.dart ================================================ import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets("How do I drag something?", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); Finder draggableFinder = find.text("Draggable"); Finder dragTargetFinder = find.text("Drag Target"); expect(draggableFinder, findsOneWidget); expect(dragTargetFinder, findsOneWidget); await tester.drag(draggableFinder, Offset(0, 100)); await tester.pump(); expect(dragTargetFinder, findsNothing); Finder successfulDragFinder = find.text("Successful drag!"); expect(successfulDragFinder, findsOneWidget); }); } ================================================ FILE: recipes/flutter_test/how_do_i_find_something/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (flutter_test) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test_driver/ ================================================ FILE: recipes/flutter_test/how_do_i_find_something/README.md ================================================ # Question How do I find something ... whether it be a widget, some text, etc? # Answer ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Get dependencies ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Column( children: [ RaisedButton( onPressed: () => print("rasied button was clicked"), child: Text("we will find this by searching for a type"), ), Text( "we will find this by searching for text", ), Text( "will will find this by searching for a key", key: Key("mykey"), ), ], ), ), ); } } ``` ## 4) Replace the `test/widget_test.dart` file. Replace the `test/widget_test.dart` file with the following: ```dart import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets('how do i find something?', (WidgetTester tester) async { await tester.pumpWidget(MyApp()); // Let's find a widget by its type Finder raisedButtonFinder = find.byType(RaisedButton); expect(raisedButtonFinder, findsOneWidget); // Let's find a specific string of text Finder textFinder = find.text("we will find this by searching for text"); expect(textFinder, findsOneWidget); // Let's find a widget by its key Finder keyFinder = find.byKey(Key("mykey")); expect(keyFinder, findsOneWidget); }); } ``` ## 5) Run the flutter tests ```sh flutter test ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter test ``` # Outputs when recipe was made / updated ## Output of running flutter tests ```sh $ flutter test 00:01 +1: All tests passed! ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [!] Connected device ! No devices available ! Doctor found issues in 1 category. ``` ================================================ FILE: recipes/flutter_test/how_do_i_find_something/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Column( children: [ RaisedButton( onPressed: () => print("rasied button was clicked"), child: Text("we will find this by searching for a type"), ), Text( "we will find this by searching for text", ), Text( "will will find this by searching for a key", key: Key("mykey"), ), ], ), ), ); } } ================================================ FILE: recipes/flutter_test/how_do_i_find_something/pubspec.yaml ================================================ name: ftc description: A new Flutter project. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter ================================================ FILE: recipes/flutter_test/how_do_i_find_something/test/widget_test.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets('how do i find something?', (WidgetTester tester) async { await tester.pumpWidget(MyApp()); // Let's find a widget by its type Finder raisedButtonFinder = find.byType(RaisedButton); expect(raisedButtonFinder, findsOneWidget); // Let's find a specific string of text Finder textFinder = find.text("we will find this by searching for text"); expect(textFinder, findsOneWidget); // Let's find a widget by its key Finder keyFinder = find.byKey(Key("mykey")); expect(keyFinder, findsOneWidget); }); } ================================================ FILE: recipes/flutter_test/how_do_i_mock_async_http_request/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Symbolication related app.*.symbols # Obfuscation related app.*.map.json # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (flutter_test) .metadata android/ ios/ pubspec.lock ftc.iml *.*~ test_driver/ ================================================ FILE: recipes/flutter_test/how_do_i_mock_async_http_request/README.md ================================================ # Question How do I mock an async http request? # Answer We will be using the [http](https://pub.dev/packages/http) package to make an http request, and [mockito](https://pub.dev/packages/mockito) to mock it. ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Add http and mockito to your `pubspec.yaml` file ```yaml dependencies: flutter: sdk: flutter http: 0.12.1 dev_dependencies: flutter_test: sdk: flutter mockito: 4.1.1 ``` Then get the dependencies by running: ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { MyApp(); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Body(), ), ); } } class Body extends StatefulWidget { @override BodyState createState() => BodyState(); } class BodyState extends State { Todo todo; Future asyncOnPressed() async { http.Response response = await http.get('https://jsonplaceholder.typicode.com/todos/1'); setState(() { todo = Todo.fromJson(jsonDecode(response.body)); }); } @override Widget build(BuildContext context) { return ListView( children: [ RaisedButton( child: Text('Fetch todo'), onPressed: asyncOnPressed, ), SizedBox( height: 16, ), todo == null ? Container() : Text('Todo: ${todo.title}', key: Key("todo-${todo.id}")), ], ); } } class Todo { final String title; final int id; Todo({ @required this.title, @required this.id, }); Todo.fromJson(Map json) : title = json['title'], id = json['id']; } ``` ## 4) Replace the `test/widget_test.dart` file. Replace the `test/widget_test.dart` file with the following: ```dart import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; import 'package:ftc/main.dart'; import 'package:mockito/mockito.dart'; class MockAppHttpClient extends Mock implements http.Client {} const String applicationJson = 'application/json; charset=utf-8'; void main() { testWidgets("A todo item should appear on the screen", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); // A todo should not be shown when the page loads expect(find.byKey(Key('todo-1')), findsNothing); // Use mockito to mock an http request's response httpClient = MockAppHttpClient(); when( httpClient.get( 'https://jsonplaceholder.typicode.com/todos/1', ), ).thenAnswer((_) async { return http.Response( jsonEncode({'id': 1, 'title': 'Do the laundry'}), 200, headers: {'content-type': 'application/json; charset=utf-8'}); }); // Make the http request // // IMPORTANT NOTE: We are *not* tapping the [RaisedButton] directly. // Instead, we are finding the state object, and then running the asyncOnPressed function // which is passed to the onPressed of the RaisedButton. If we were to tap the RaisedButton directly, // the test wouldn't wait properly because the onPressed signature is a VoidCallback instead // of an AsyncCallback. await tester.state(find.byType(Body)).asyncOnPressed(); await tester.pump(); // A todo should be shown after the http request receives a response expect(find.byKey(Key('todo-1')), findsOneWidget); }); } ``` ## 5) Run the flutter tests ```sh flutter test ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter test ``` # Outputs when recipe was made / updated ## Output of running flutter tests ```sh $ flutter test 00:02 +1: All tests passed! ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.17.2, on Mac OS X 10.15.5 19F101, locale en-US) • Flutter version 1.17.2 at /Users/matthew/gadfly/flutter_versions/flutter_1.17.2 • Framework revision 5f21edf8b6 (2 weeks ago), 2020-05-28 12:44:12 -0700 • Engine revision b851c71829 • Dart version 2.8.3 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.5) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.5, Build version 11E608c • CocoaPods version 1.9.1 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [!] IntelliJ IDEA Ultimate Edition (version 2020.1.2) • IntelliJ at /Applications/IntelliJ IDEA.app ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. • For information about installing plugins, see https://flutter.dev/intellij-setup/#installing-the-plugins [✓] VS Code (version 1.45.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.10.2 [✓] Connected device (1 available) • iPhone 8 • C9868AFF-E4CE-4C0B-AC2B-9600508F6C1F • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-5 (simulator) ! Doctor found issues in 1 category. ``` ================================================ FILE: recipes/flutter_test/how_do_i_mock_async_http_request/lib/main.dart ================================================ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() => runApp(MyApp()); http.Client httpClient = http.Client(); class MyApp extends StatelessWidget { MyApp(); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Body(), ), ); } } class Body extends StatefulWidget { @override BodyState createState() => BodyState(); } class BodyState extends State { Todo todo; Future asyncOnPressed() async { http.Response response = await httpClient.get('https://jsonplaceholder.typicode.com/todos/1'); setState(() { todo = Todo.fromJson(jsonDecode(response.body)); }); } @override Widget build(BuildContext context) { return ListView( children: [ RaisedButton( child: Text('Fetch todo'), onPressed: asyncOnPressed, ), SizedBox( height: 16, ), todo == null ? Container() : Text('Todo: ${todo.title}', key: Key("todo-${todo.id}")), ], ); } } class Todo { final String title; final int id; Todo({ @required this.title, @required this.id, }); Todo.fromJson(Map json) : title = json['title'], id = json['id']; } ================================================ FILE: recipes/flutter_test/how_do_i_mock_async_http_request/pubspec.yaml ================================================ name: ftc description: A new Flutter project. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter http: 0.12.1 dev_dependencies: flutter_test: sdk: flutter mockito: 4.1.1 ================================================ FILE: recipes/flutter_test/how_do_i_mock_async_http_request/test/widget_test.dart ================================================ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; import 'package:ftc/main.dart'; import 'package:mockito/mockito.dart'; class MockAppHttpClient extends Mock implements http.Client {} const String applicationJson = 'application/json; charset=utf-8'; void main() { testWidgets("A todo item should appear on the screen", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); // A todo should not be shown when the page loads expect(find.byKey(Key('todo-1')), findsNothing); // Use mockito to mock an http request's response httpClient = MockAppHttpClient(); when( httpClient.get( 'https://jsonplaceholder.typicode.com/todos/1', ), ).thenAnswer((_) async { return http.Response( jsonEncode({'id': 1, 'title': 'Do the laundry'}), 200, headers: {'content-type': 'application/json; charset=utf-8'}); }); // Make the http request // // IMPORTANT NOTE: We are *not* tapping the [RaisedButton] directly. // Instead, we are finding the state object, and then running the asyncOnPressed function // which is passed to the onPressed of the RaisedButton. If we were to tap the RaisedButton directly, // the test wouldn't wait properly because the onPressed signature is a VoidCallback instead // of an AsyncCallback. await tester.state(find.byType(Body)).asyncOnPressed(); await tester.pump(); // A todo should be shown after the http request receives a response expect(find.byKey(Key('todo-1')), findsOneWidget); }); } ================================================ FILE: recipes/flutter_test/how_do_i_mock_shared_preferences/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (flutter_test) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test_driver/ ================================================ FILE: recipes/flutter_test/how_do_i_mock_shared_preferences/README.md ================================================ # Question How do I mock [shared_preferences](https://pub.dev/packages/shared_preferences)? # Answer There are a few subtle things that can go wrong when testing shared_preferences. a) If you are grabbing a value from shared_preferences during `initState`, then there is the need for an extra `pump` when testing. b) If you try to get shared_preferences in your main file before your call to `runApp`, you may experience an error. If so, you will need to add a call to [WidgetsFlutterBinding.ensureInitialized](https://api.flutter.dev/flutter/widgets/WidgetsFlutterBinding/ensureInitialized.html) (as well as [TestWidgetsFlutterBinding.ensureInitialized](https://api.flutter.dev/flutter/flutter_test/TestWidgetsFlutterBinding/ensureInitialized.html) to your tests). This recipe covers a). ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Add shared_preferences to your `pubspec.yaml` file ```yaml dependencies: flutter: sdk: flutter shared_preferences: 0.5.6+2 ``` Then get the dependencies by running: ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { MyApp(); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Body(), ), ); } } class Body extends StatefulWidget { @override _BodyState createState() => _BodyState(); } class _BodyState extends State { int spValue = 0; @override void initState() { super.initState(); SharedPreferences.getInstance().then((SharedPreferences prefs) { setState(() { spValue = prefs.getInt("myValue") ?? 0; }); }); } @override Widget build(BuildContext context) { return Center( child: Text("The shared_preferences value is: $spValue"), ); } } ``` ## 4) Replace the `test/widget_test.dart` file. Replace the `test/widget_test.dart` file with the following: ```dart import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:ftc/main.dart'; void main() { // If you're running a test, you can call the `TestWidgetsFlutterBinding.ensureInitialized()` as the first line in your test's `main()` method to initialize the binding. TestWidgetsFlutterBinding.ensureInitialized(); testWidgets( "The value displayed should fallback to 0 if the shared_preferences value isn't mocked", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); expect(find.text("The shared_preferences value is: 0"), findsOneWidget); }); testWidgets( "The value displayed should be updated when mocking initial shared_preferences values", (WidgetTester tester) async { // We are setting the initial value to 10 SharedPreferences.setMockInitialValues({"myValue": 10}); // then we are pumping our top-level widget await tester.pumpWidget(MyApp()); // However, because we are grabbing shared_preferences value in our initState, and then using setState // to set the value displayed in our app, we need to pump one more time! await tester.pump(); // Then we expect out mock value to be displayed expect(find.text("The shared_preferences value is: 10"), findsOneWidget); }); } ``` ## 5) Run the flutter tests ```sh flutter test ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter test ``` # Outputs when recipe was made / updated ## Output of running flutter tests ```sh $ flutter test 00:06 +1: All tests passed! ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [✓] Connected device (1 available) • iPhone 8 • AD7A90EB-5E73-427E-B9B7-DD3B07E2FEF1 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-3 (simulator) • No issues found! ``` ================================================ FILE: recipes/flutter_test/how_do_i_mock_shared_preferences/lib/main.dart ================================================ import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { MyApp(); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Body(), ), ); } } class Body extends StatefulWidget { @override _BodyState createState() => _BodyState(); } class _BodyState extends State { int spValue = 0; @override void initState() { super.initState(); SharedPreferences.getInstance().then((SharedPreferences prefs) { setState(() { spValue = prefs.getInt("myValue") ?? 0; }); }); } @override Widget build(BuildContext context) { return Center( child: Text("The shared_preferences value is: $spValue"), ); } } ================================================ FILE: recipes/flutter_test/how_do_i_mock_shared_preferences/pubspec.yaml ================================================ name: ftc description: A new Flutter project. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter shared_preferences: 0.5.6+2 dev_dependencies: flutter_test: sdk: flutter ================================================ FILE: recipes/flutter_test/how_do_i_mock_shared_preferences/test/widget_test.dart ================================================ import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:ftc/main.dart'; void main() { // If you're running a test, you can call the `TestWidgetsFlutterBinding.ensureInitialized()` as the first line in your test's `main()` method to initialize the binding. TestWidgetsFlutterBinding.ensureInitialized(); testWidgets( "The value displayed should fallback to 0 if the shared_preferences value isn't mocked", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); expect(find.text("The shared_preferences value is: 0"), findsOneWidget); }); testWidgets( "The value displayed should be updated when mocking initial shared_preferences values", (WidgetTester tester) async { // We are setting the initial value to 10 SharedPreferences.setMockInitialValues({"myValue": 10}); // then we are pumping our top-level widget await tester.pumpWidget(MyApp()); // However, because we are grabbing shared_preferences value in our initState, and then using setState // to set the value displayed in our app, we need to pump one more time! await tester.pump(); // Then we expect out mock value to be displayed expect(find.text("The shared_preferences value is: 10"), findsOneWidget); }); } ================================================ FILE: recipes/flutter_test/how_do_i_open_a_drawer/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (flutter_test) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test_driver/ ================================================ FILE: recipes/flutter_test/how_do_i_open_a_drawer/README.md ================================================ # Question How do I open a [Drawer](https://api.flutter.dev/flutter/material/Drawer-class.html)? # Answer There are several methods to open a Drawer: a) Open Drawer by tapping the menu icon in the Appbar b) Open Drawer by using scaffoldKey c) Open Drawer by using a BuildContext and finding a Scaffold with Scaffold.of d) Open Drawer by swiping from the left edge ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Get dependencies ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); GlobalKey scaffoldKey = GlobalKey(); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( key: scaffoldKey, appBar: AppBar(), drawer: Drawer(), body: Body(), ), ); } } class Body extends StatelessWidget { @override Widget build(BuildContext context) { return Center( child: Text("There is a drawer"), ); } } ``` ## 4) Replace the `test/widget_test.dart` file. Replace the `test/widget_test.dart` file with the following: ```dart import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets('How do I open a Drawer?', (WidgetTester tester) async { await tester.pumpWidget(MyApp()); Finder drawerFinder = find.byType(Drawer); expect(drawerFinder, findsNothing); // // Method a) // // open Drawer by tapping the menu icon in the Appbar Finder menuIconFinder = find.byIcon(Icons.menu); await tester.tap(menuIconFinder); await tester.pumpAndSettle(); // confirm that the Drawer is open expect(drawerFinder, findsOneWidget); // close Drawer Navigator.of(tester.element(drawerFinder)).pop(); await tester.pumpAndSettle(); expect(drawerFinder, findsNothing); // // Method b) // // open Drawer by using scaffoldKey scaffoldKey.currentState.openDrawer(); await tester.pumpAndSettle(); // confirm that the Drawer is open expect(drawerFinder, findsOneWidget); // close Drawer Navigator.of(tester.element(drawerFinder)).pop(); await tester.pumpAndSettle(); expect(drawerFinder, findsNothing); // // Method c) // // open Drawer by using a BuildContext and finding a Scaffold with Scaffold.of Finder bodyFinder = find.byType(Body); Scaffold.of(tester.element(bodyFinder)).openDrawer(); await tester.pumpAndSettle(); // confirm that the Drawer is open expect(drawerFinder, findsOneWidget); // close Drawer Navigator.of(tester.element(drawerFinder)).pop(); await tester.pumpAndSettle(); expect(drawerFinder, findsNothing); // // Method d) // // open Drawer by swiping from the left edge await tester.dragFrom(Offset(0, 100), Offset(300, 100)); await tester.pumpAndSettle(); // confirm that the Drawer is open expect(drawerFinder, findsOneWidget); // close Drawer Navigator.of(tester.element(drawerFinder)).pop(); await tester.pumpAndSettle(); expect(drawerFinder, findsNothing); }); } ``` ## 5) Run the flutter tests ```sh flutter test ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter test ``` # Outputs when recipe was made / updated ## Output of running flutter tests ```sh $ flutter test 00:02 +1: All tests passed! ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [✓] Connected device (1 available) • iPhone 8 • AD7A90EB-5E73-427E-B9B7-DD3B07E2FEF1 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-3 (simulator) • No issues found! ``` ================================================ FILE: recipes/flutter_test/how_do_i_open_a_drawer/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); GlobalKey scaffoldKey = GlobalKey(); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( key: scaffoldKey, appBar: AppBar(), drawer: Drawer(), body: Body(), ), ); } } class Body extends StatelessWidget { @override Widget build(BuildContext context) { return Center( child: Text("There is a drawer"), ); } } ================================================ FILE: recipes/flutter_test/how_do_i_open_a_drawer/pubspec.yaml ================================================ name: ftc description: A new Flutter project. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter # needed to show menu icon in AppBar flutter: uses-material-design: true ================================================ FILE: recipes/flutter_test/how_do_i_open_a_drawer/test/widget_test.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets('How do I open a Drawer?', (WidgetTester tester) async { await tester.pumpWidget(MyApp()); Finder drawerFinder = find.byType(Drawer); expect(drawerFinder, findsNothing); // // Method a) // // open Drawer by tapping the menu icon in the Appbar Finder menuIconFinder = find.byIcon(Icons.menu); await tester.tap(menuIconFinder); await tester.pumpAndSettle(); // confirm that the Drawer is open expect(drawerFinder, findsOneWidget); // close Drawer Navigator.of(tester.element(drawerFinder)).pop(); await tester.pumpAndSettle(); expect(drawerFinder, findsNothing); // // Method b) // // open Drawer by using scaffoldKey scaffoldKey.currentState.openDrawer(); await tester.pumpAndSettle(); // confirm that the Drawer is open expect(drawerFinder, findsOneWidget); // close Drawer Navigator.of(tester.element(drawerFinder)).pop(); await tester.pumpAndSettle(); expect(drawerFinder, findsNothing); // // Method c) // // open Drawer by using a BuildContext and finding a Scaffold with Scaffold.of Finder bodyFinder = find.byType(Body); Scaffold.of(tester.element(bodyFinder)).openDrawer(); await tester.pumpAndSettle(); // confirm that the Drawer is open expect(drawerFinder, findsOneWidget); // close Drawer Navigator.of(tester.element(drawerFinder)).pop(); await tester.pumpAndSettle(); expect(drawerFinder, findsNothing); // // Method d) // // open Drawer by swiping from the left edge await tester.dragFrom(Offset(0, 100), Offset(300, 100)); await tester.pumpAndSettle(); // confirm that the Drawer is open expect(drawerFinder, findsOneWidget); // close Drawer Navigator.of(tester.element(drawerFinder)).pop(); await tester.pumpAndSettle(); expect(drawerFinder, findsNothing); }); } ================================================ FILE: recipes/flutter_test/how_do_i_run_a_flutter_test/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (flutter_test) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test_driver/ ================================================ FILE: recipes/flutter_test/how_do_i_run_a_flutter_test/README.md ================================================ # Question How do I run a [flutter test](https://api.flutter.dev/flutter/flutter_test/flutter_test-library.html) test? # Answer ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Get dependencies ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Text("Hello world"), ), ), ); } } ``` ## 4) Replace the `test/widget_test.dart` file. Replace the `test/widget_test.dart` file with the following: ```dart import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets("'Hello world' text exists", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); expect(find.text('Hello world'), findsOneWidget); }); } ``` ## 5) Run the flutter tests ```sh flutter test ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter test ``` # Outputs when recipe was made / updated ## Output of running flutter tests ```sh $ flutter test 00:06 +1: All tests passed! ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [!] Connected device ! No devices available ! Doctor found issues in 1 category. ``` ================================================ FILE: recipes/flutter_test/how_do_i_run_a_flutter_test/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Text("Hello world"), ), ), ); } } ================================================ FILE: recipes/flutter_test/how_do_i_run_a_flutter_test/pubspec.yaml ================================================ name: ftc description: A new Flutter project. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter ================================================ FILE: recipes/flutter_test/how_do_i_run_a_flutter_test/test/widget_test.dart ================================================ import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets("'Hello world' text exists", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); expect(find.text('Hello world'), findsOneWidget); }); } ================================================ FILE: recipes/flutter_test/how_do_i_run_a_script/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (flutter_test) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test_driver/ ================================================ FILE: recipes/flutter_test/how_do_i_run_a_script/README.md ================================================ # Question How do I run a script inside of a test? # Answer Use [Process.run](https://api.dart.dev/stable/2.7.1/dart-io/Process/run.html) ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Get dependencies ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Text("A script will be run during the test"), ), ), ); } } ``` ## 4) Replace the `test/widget_test.dart` file. Replace the `test/widget_test.dart` file with the following: ```dart import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; import 'dart:io'; void main() async { testWidgets("How do I run a script?", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); // Running a script inside of flutter_test is different than with flutter_driver. // With flutter_test, we need to: // a) use tester.runAsync, and // b) write the path of the script from the perspective of this file ProcessResult result = await tester.runAsync(() async { return await Process.run('../echo.sh', ['1']); }); //Note: echo appends a newline to the result expect(result.stdout, '1\n'); }); } ``` ## 5) Add an `echo.sh` script Create a file called `echo.sh` and add the following to it: ```sh #!/bin/bash echo "$1" ``` Then run: ```sh chmod +x echo.sh ``` ## 6) Run the flutter tests ```sh flutter test ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter test ``` # Outputs when recipe was made / updated ## Output of running flutter tests ```sh $ flutter test 00:01 +1: All tests passed! ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [✓] Connected device (1 available) • iPhone 8 • AD7A90EB-5E73-427E-B9B7-DD3B07E2FEF1 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-3 (simulator) • No issues found! ``` ================================================ FILE: recipes/flutter_test/how_do_i_run_a_script/echo.sh ================================================ #!/bin/bash echo "$1" ================================================ FILE: recipes/flutter_test/how_do_i_run_a_script/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Text("Hello world"), ), ), ); } } ================================================ FILE: recipes/flutter_test/how_do_i_run_a_script/pubspec.yaml ================================================ name: ftc description: A new Flutter project. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter ================================================ FILE: recipes/flutter_test/how_do_i_run_a_script/test/widget_test.dart ================================================ import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; import 'dart:io'; void main() async { testWidgets("How do I run a script?", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); // Running a script inside of flutter_test is different than with flutter_driver. // With flutter_test, we need to: // a) use tester.runAsync, and // b) write the path of the script from the perspective of this file ProcessResult result = await tester.runAsync(() async { return await Process.run('../echo.sh', ['1']); }); //Note: echo appends a newline to the result expect(result.stdout, '1\n'); }); } ================================================ FILE: recipes/flutter_test/how_do_i_send_a_keyboard_action/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (flutter_test) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test_driver/ ================================================ FILE: recipes/flutter_test/how_do_i_send_a_keyboard_action/README.md ================================================ # Question How do I send a keyboard action like `done` or `next`? # Answer ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Get dependencies ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: MyForm(), ), ); } } class MyForm extends StatefulWidget { @override _MyFormState createState() => _MyFormState(); } class _MyFormState extends State { // We are creating controllers and focus nodes for our two text fields TextEditingController firstNameController; FocusNode firstNameFocusNode; TextEditingController lastNameController; FocusNode lastNameFocusNode; @override void initState() { super.initState(); firstNameController = TextEditingController(); firstNameFocusNode = FocusNode(); lastNameController = TextEditingController(); lastNameFocusNode = FocusNode(); } // and we are cleaning up after ourselves by disposing the controllers and focus nodes @override void dispose() { firstNameController.dispose(); firstNameFocusNode.dispose(); lastNameController.dispose(); lastNameFocusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Column( children: [ TextField( decoration: InputDecoration(labelText: "First name"), textInputAction: TextInputAction.next, controller: firstNameController, focusNode: firstNameFocusNode, // When a user hits 'next' on the keyboard, it will unfocus firstName and focus lastName onSubmitted: (String _firstName) { firstNameFocusNode.unfocus(); FocusScope.of(context).requestFocus(lastNameFocusNode); }, ), TextField( decoration: InputDecoration(labelText: "Last name"), textInputAction: TextInputAction.done, controller: lastNameController, focusNode: lastNameFocusNode, // When a user hits 'done' on the keyboard, it will unfocus lastName and then show a SnackBar with the full name onSubmitted: (String _lastName) { lastNameFocusNode.unfocus(); Scaffold.of(context).showSnackBar(SnackBar( content: Text( "Your name is: ${firstNameController.text} ${lastNameController.text}"), )); }, ), ], ); } } ``` ## 4) Replace the `test/widget_test.dart` file. Replace the `test/widget_test.dart` file with the following: ```dart import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets("How do I send a keyboard action?", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); // First, let's confirm we have two TextFields on the page Finder firstNameFinder = find.byType(TextField).at(0); Finder lastNameFinder = find.byType(TextField).at(1); expect(firstNameFinder, findsOneWidget); expect(lastNameFinder, findsOneWidget); // Next, let's enter our first name await tester.showKeyboard(firstNameFinder); tester.testTextInput.enterText("John"); // Tap the 'next' action in the keyboard await tester.testTextInput.receiveAction(TextInputAction.next); // This should automatically focus the last name // which means we don't need to show a new keyboard with a new finder tester.testTextInput.enterText("Doe"); // Tap the 'done' action in the keyboard await tester.testTextInput.receiveAction(TextInputAction.done); // This should open a SnackBar with the entered name await tester.pumpAndSettle(); expect(find.text("Your name is: John Doe"), findsOneWidget); }); } ``` ## 5) Run the flutter tests ```sh flutter test ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter test ``` # Outputs when recipe was made / updated ## Output of running flutter tests ```sh $ flutter test 00:02 +1: All tests passed! ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [!] Connected device ! No devices available ! Doctor found issues in 1 category. ``` ================================================ FILE: recipes/flutter_test/how_do_i_send_a_keyboard_action/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: MyForm(), ), ); } } class MyForm extends StatefulWidget { @override _MyFormState createState() => _MyFormState(); } class _MyFormState extends State { // We are creating controllers and focus nodes for our two text fields TextEditingController firstNameController; FocusNode firstNameFocusNode; TextEditingController lastNameController; FocusNode lastNameFocusNode; @override void initState() { super.initState(); firstNameController = TextEditingController(); firstNameFocusNode = FocusNode(); lastNameController = TextEditingController(); lastNameFocusNode = FocusNode(); } // and we are cleaning up after ourselves by disposing the controllers and focus nodes @override void dispose() { firstNameController.dispose(); firstNameFocusNode.dispose(); lastNameController.dispose(); lastNameFocusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Column( children: [ TextField( decoration: InputDecoration(labelText: "First name"), textInputAction: TextInputAction.next, controller: firstNameController, focusNode: firstNameFocusNode, // When a user hits 'next' on the keyboard, it will unfocus firstName and focus lastName onSubmitted: (String _firstName) { firstNameFocusNode.unfocus(); FocusScope.of(context).requestFocus(lastNameFocusNode); }, ), TextField( decoration: InputDecoration(labelText: "Last name"), textInputAction: TextInputAction.done, controller: lastNameController, focusNode: lastNameFocusNode, // When a user hits 'done' on the keyboard, it will unfocus lastName and then show a SnackBar with the full name onSubmitted: (String _lastName) { lastNameFocusNode.unfocus(); Scaffold.of(context).showSnackBar(SnackBar( content: Text( "Your name is: ${firstNameController.text} ${lastNameController.text}"), )); }, ), ], ); } } ================================================ FILE: recipes/flutter_test/how_do_i_send_a_keyboard_action/pubspec.yaml ================================================ name: ftc description: A new Flutter project. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter ================================================ FILE: recipes/flutter_test/how_do_i_send_a_keyboard_action/test/widget_test.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets("How do I send a keyboard event?", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); // First, let's confirm we have two TextFields on the page Finder firstNameFinder = find.byType(TextField).at(0); Finder lastNameFinder = find.byType(TextField).at(1); expect(firstNameFinder, findsOneWidget); expect(lastNameFinder, findsOneWidget); // Next, let's enter our first name await tester.showKeyboard(firstNameFinder); tester.testTextInput.enterText("John"); // Tap the 'next' action in the keyboard await tester.testTextInput.receiveAction(TextInputAction.next); // This should automatically focus the last name // which means we don't need to show a new keyboard with a new finder tester.testTextInput.enterText("Doe"); // Tap the 'done' action in the keyboard await tester.testTextInput.receiveAction(TextInputAction.done); // This should open a SnackBar with the entered name await tester.pumpAndSettle(); expect(find.text("Your name is: John Doe"), findsOneWidget); }); } ================================================ FILE: recipes/flutter_test/how_do_i_test_an_animation/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (flutter_test) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test_driver/ ================================================ FILE: recipes/flutter_test/how_do_i_test_an_animation/README.md ================================================ # Question How do I test an animation? # Answer In this example, we will be taking a box, with a height of 0, and growing it to 100 over the course of 1000 milliseconds. Since flutter test doesn't automatically pump the widget, we can do it manually and check the box size along the way. ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Get dependencies ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { MyApp(); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Body(), ), ), ); } } class Body extends StatefulWidget { Body(); @override _BodyState createState() => _BodyState(); } class _BodyState extends State with SingleTickerProviderStateMixin { Animation animation; AnimationController controller; @override void initState() { super.initState(); controller = AnimationController( vsync: this, duration: Duration(milliseconds: 1000), ); animation = Tween(begin: 0, end: 100).animate(controller); } @override void dispose() { controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Column( children: [ RaisedButton( onPressed: () { controller.forward(); }, child: Text("Start animation"), ), AnimatedBuilder( animation: animation, builder: (BuildContext _context, _child) { return Container( key: Key("animatedBox"), height: animation.value, width: animation.value, decoration: BoxDecoration( border: Border.all( color: Colors.black, width: 2, ), ), ); }, ) ], ); } } ``` ## 4) Replace the `test/widget_test.dart` file. Replace the `test/widget_test.dart` file with the following: ```dart import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets("How do I test an animation?", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); Finder startAnimationFinder = find.text("Start animation"); Finder animatedBoxFinder = find.byKey(Key("animatedBox")); expect(startAnimationFinder, findsOneWidget); expect(animatedBoxFinder, findsOneWidget); // The box starts off with a height of 0 RenderConstrainedBox animatedBox = tester.renderObject(animatedBoxFinder); expect(animatedBox.size.height, 0); // Once we start the animation await tester.tap(startAnimationFinder); await tester.pump(); // and wait 100 milliseconds await tester.pump(Duration(milliseconds: 100)); // we expect the height to grow from 0 to 10 expect(animatedBox.size.height, 10); // after another 100 milliseconds it should grow to 20 await tester.pump(Duration(milliseconds: 100)); expect(animatedBox.size.height, 20); await tester.pump(Duration(milliseconds: 100)); // and then 30 expect(animatedBox.size.height, 30); await tester.pump(Duration(milliseconds: 100)); // and then 40 expect(animatedBox.size.height, 40); await tester.pump(Duration(milliseconds: 100)); // and then 50 expect(animatedBox.size.height, 50); await tester.pump(Duration(milliseconds: 500)); // and then after another 500 milliseconds, the animation should be // complete and be a total height of 100 expect(animatedBox.size.height, 100); }); } ``` ## 5) Run the flutter tests ```sh flutter test ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter test ``` # Outputs when recipe was made / updated ## Output of running flutter tests ```sh $ flutter test 00:02 +1: All tests passed! ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [!] Connected device • Device 9C251FFBA00174 is not authorized. You might need to check your device for an authorization dialog. ! Doctor found issues in 1 category. ``` ================================================ FILE: recipes/flutter_test/how_do_i_test_an_animation/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { MyApp(); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Body(), ), ), ); } } class Body extends StatefulWidget { Body(); @override _BodyState createState() => _BodyState(); } class _BodyState extends State with SingleTickerProviderStateMixin { Animation animation; AnimationController controller; @override void initState() { super.initState(); controller = AnimationController( vsync: this, duration: Duration(milliseconds: 1000), ); animation = Tween(begin: 0, end: 100).animate(controller); } @override void dispose() { controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Column( children: [ RaisedButton( onPressed: () { controller.forward(); }, child: Text("Start animation"), ), AnimatedBuilder( animation: animation, builder: (BuildContext _context, _child) { return Container( key: Key("animatedBox"), height: animation.value, width: animation.value, decoration: BoxDecoration( border: Border.all( color: Colors.black, width: 2, ), ), ); }, ) ], ); } } ================================================ FILE: recipes/flutter_test/how_do_i_test_an_animation/pubspec.yaml ================================================ name: ftc description: A new Flutter project. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter ================================================ FILE: recipes/flutter_test/how_do_i_test_an_animation/test/widget_test.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets("How do I test an animation?", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); Finder startAnimationFinder = find.text("Start animation"); Finder animatedBoxFinder = find.byKey(Key("animatedBox")); expect(startAnimationFinder, findsOneWidget); expect(animatedBoxFinder, findsOneWidget); // The box starts off with a height of 0 RenderConstrainedBox animatedBox = tester.renderObject(animatedBoxFinder); expect(animatedBox.size.height, 0); // Once we start the animation await tester.tap(startAnimationFinder); await tester.pump(); // and wait 100 milliseconds await tester.pump(Duration(milliseconds: 100)); // we expect the height to grow from 0 to 10 expect(animatedBox.size.height, 10); // after another 100 milliseconds it should grow to 20 await tester.pump(Duration(milliseconds: 100)); expect(animatedBox.size.height, 20); await tester.pump(Duration(milliseconds: 100)); // and then 30 expect(animatedBox.size.height, 30); await tester.pump(Duration(milliseconds: 100)); // and then 40 expect(animatedBox.size.height, 40); await tester.pump(Duration(milliseconds: 100)); // and then 50 expect(animatedBox.size.height, 50); await tester.pump(Duration(milliseconds: 500)); // and then after another 500 milliseconds, the animation should be // complete and be a total height of 100 expect(animatedBox.size.height, 100); }); } ================================================ FILE: recipes/flutter_test/how_do_i_test_an_exception/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (flutter_test) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test_driver/ ================================================ FILE: recipes/flutter_test/how_do_i_test_an_exception/README.md ================================================ # Question How do I test an Exception? # Answer ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Get dependencies ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Column(children: [ RaisedButton( child: Text("Throw Exception"), onPressed: () { throw Exception(); }, ), RaisedButton( child: Text("Throw MyCustomException"), onPressed: () { throw MyCustomException(); }, ), ]), ), ); } } class MyCustomException implements Exception { MyCustomException(); } ``` ## 4) Replace the `test/widget_test.dart` file. Replace the `test/widget_test.dart` file with the following: ```dart import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets("How do I test for an exception?", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); Finder exceptionButtonFinder = find.byType(RaisedButton).at(0); Finder customExceptionButtonFinder = find.byType(RaisedButton).at(1); await tester.tap(exceptionButtonFinder); Exception exception = tester.takeException(); expect(exception, isException); await tester.tap(customExceptionButtonFinder); Exception customException = tester.takeException(); expect(customException, isInstanceOf()); }); } ``` ## 5) Run the flutter tests ```sh flutter test ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter test ``` # Outputs when recipe was made / updated ## Output of running flutter tests ```sh $ flutter test 00:02 +1: All tests passed! ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [✓] Connected device (1 available) • iPhone 8 • AD7A90EB-5E73-427E-B9B7-DD3B07E2FEF1 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-3 (simulator) • No issues found! ``` ================================================ FILE: recipes/flutter_test/how_do_i_test_an_exception/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Column(children: [ RaisedButton( child: Text("Throw Exception"), onPressed: () { throw Exception(); }, ), RaisedButton( child: Text("Throw MyCustomException"), onPressed: () { throw MyCustomException(); }, ), ]), ), ); } } class MyCustomException implements Exception { MyCustomException(); } ================================================ FILE: recipes/flutter_test/how_do_i_test_an_exception/pubspec.yaml ================================================ name: ftc description: A new Flutter project. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter ================================================ FILE: recipes/flutter_test/how_do_i_test_an_exception/test/widget_test.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets("How do I test for an exception?", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); Finder exceptionButtonFinder = find.byType(RaisedButton).at(0); Finder customExceptionButtonFinder = find.byType(RaisedButton).at(1); await tester.tap(exceptionButtonFinder); Exception exception = tester.takeException(); expect(exception, isException); await tester.tap(customExceptionButtonFinder); Exception customException = tester.takeException(); expect(customException, isInstanceOf()); }); } ================================================ FILE: recipes/flutter_test/how_do_i_test_routes/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (flutter_test) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test_driver/ ================================================ FILE: recipes/flutter_test/how_do_i_test_routes/README.md ================================================ # Question How do I test routes? # Answer ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Get dependencies ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( initialRoute: "/page1", routes: { "/page1": (BuildContext context) => Page1(), "/page2": (BuildContext context) => Page2(), "/page3": (BuildContext context) => Page3(), }, ); } } class Page1 extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Page 1"), ), body: Column( children: [ RaisedButton( onPressed: () => Navigator.of(context).pushNamed("/page2"), child: Text("pushNamed to page2"), ), RaisedButton( onPressed: () => Navigator.of(context).pushReplacementNamed("/page2"), child: Text("pushReplacementNamed to page2"), ) ], ), ); } } class Page2 extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Page 2"), ), body: Column( children: [ RaisedButton( onPressed: () => Navigator.of(context).pushNamed("/page3"), child: Text("pushNamed to page3"), ), ], ), ); } } class Page3 extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Page 3"), ), body: Column( children: [ RaisedButton( onPressed: () => Navigator.of(context).pop(), child: Text("pop"), ), RaisedButton( onPressed: () => Navigator.of(context).popUntil((Route route) { return route.settings.name == "/page1"; }), child: Text("popUntil page1"), ) ], ), ); } } ``` ## 4) Replace the `test/widget_test.dart` file. Replace the `test/widget_test.dart` file with the following: ```dart import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets("How do I test routes?", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); // First, let's make sure we are on /page1 expect(find.byType(Page1), findsOneWidget); expect(find.byType(Page2), findsNothing); expect(find.byType(Page3), findsNothing); // // Next, let's navigate to /page2 // await tester.tap(find.text("pushNamed to page2")); await tester.pumpAndSettle(); // Confirm we are on /page2 expect(find.byType(Page1), findsNothing); expect(find.byType(Page2), findsOneWidget); expect(find.byType(Page3), findsNothing); // However, since routes are in a stack, and we pushed page2 on top of page1, // we should confirm that page1 still exists. // We can do this by setting `skipOffstage` to false. expect(find.byType(Page1, skipOffstage: false), findsOneWidget); expect(find.byType(Page2, skipOffstage: false), findsOneWidget); expect(find.byType(Page3, skipOffstage: false), findsNothing); // // Next, let's navigate to /page3 // await tester.tap(find.text("pushNamed to page3")); await tester.pumpAndSettle(); // Confirm we are on /page3 expect(find.byType(Page1), findsNothing); expect(find.byType(Page2), findsNothing); expect(find.byType(Page3), findsOneWidget); expect(find.byType(Page1, skipOffstage: false), findsOneWidget); expect(find.byType(Page2, skipOffstage: false), findsOneWidget); expect(find.byType(Page3, skipOffstage: false), findsOneWidget); // // Next, let's navigate back to /page2 // await tester.tap(find.text("pop")); await tester.pumpAndSettle(); // confirm we are on /page2 expect(find.byType(Page1), findsNothing); expect(find.byType(Page2), findsOneWidget); expect(find.byType(Page3), findsNothing); expect(find.byType(Page1, skipOffstage: false), findsOneWidget); expect(find.byType(Page2, skipOffstage: false), findsOneWidget); expect(find.byType(Page3, skipOffstage: false), findsNothing); // // Finally, let's navigate back to /page3 and then popUntil we are on /page1 // await tester.tap(find.text("pushNamed to page3")); await tester.pumpAndSettle(); // Confirm we are on /page3 expect(find.byType(Page1), findsNothing); expect(find.byType(Page2), findsNothing); expect(find.byType(Page3), findsOneWidget); expect(find.byType(Page1, skipOffstage: false), findsOneWidget); expect(find.byType(Page2, skipOffstage: false), findsOneWidget); expect(find.byType(Page3, skipOffstage: false), findsOneWidget); await tester.tap(find.text("popUntil page1")); await tester.pumpAndSettle(); // Confirm we are on /page1 expect(find.byType(Page1), findsOneWidget); expect(find.byType(Page2), findsNothing); expect(find.byType(Page3), findsNothing); expect(find.byType(Page1, skipOffstage: false), findsOneWidget); expect(find.byType(Page2, skipOffstage: false), findsNothing); expect(find.byType(Page3, skipOffstage: false), findsNothing); }); } ``` ## 5) Run the flutter tests ```sh flutter test ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter test ``` # Outputs when recipe was made / updated ## Output of running flutter tests ```sh $ flutter test 00:02 +1: All tests passed! ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [✓] Connected device (1 available) • iPhone 8 • AD7A90EB-5E73-427E-B9B7-DD3B07E2FEF1 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-3 (simulator) • No issues found! ``` ================================================ FILE: recipes/flutter_test/how_do_i_test_routes/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( initialRoute: "/page1", routes: { "/page1": (BuildContext context) => Page1(), "/page2": (BuildContext context) => Page2(), "/page3": (BuildContext context) => Page3(), }, ); } } class Page1 extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Page 1"), ), body: Column( children: [ RaisedButton( onPressed: () => Navigator.of(context).pushNamed("/page2"), child: Text("pushNamed to page2"), ), RaisedButton( onPressed: () => Navigator.of(context).pushReplacementNamed("/page2"), child: Text("pushReplacementNamed to page2"), ) ], ), ); } } class Page2 extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Page 2"), ), body: Column( children: [ RaisedButton( onPressed: () => Navigator.of(context).pushNamed("/page3"), child: Text("pushNamed to page3"), ), ], ), ); } } class Page3 extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Page 3"), ), body: Column( children: [ RaisedButton( onPressed: () => Navigator.of(context).pop(), child: Text("pop"), ), RaisedButton( onPressed: () => Navigator.of(context).popUntil((Route route) { return route.settings.name == "/page1"; }), child: Text("popUntil page1"), ) ], ), ); } } ================================================ FILE: recipes/flutter_test/how_do_i_test_routes/pubspec.yaml ================================================ name: ftc description: A new Flutter project. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter ================================================ FILE: recipes/flutter_test/how_do_i_test_routes/test/widget_test.dart ================================================ import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets("How do I test routes?", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); // First, let's make sure we are on /page1 expect(find.byType(Page1), findsOneWidget); expect(find.byType(Page2), findsNothing); expect(find.byType(Page3), findsNothing); // // Next, let's navigate to /page2 // await tester.tap(find.text("pushNamed to page2")); await tester.pumpAndSettle(); // Confirm we are on /page2 expect(find.byType(Page1), findsNothing); expect(find.byType(Page2), findsOneWidget); expect(find.byType(Page3), findsNothing); // However, since routes are in a stack, and we pushed page2 on top of page1, // we should confirm that page1 still exists. // We can do this by setting `skipOffstage` to false. expect(find.byType(Page1, skipOffstage: false), findsOneWidget); expect(find.byType(Page2, skipOffstage: false), findsOneWidget); expect(find.byType(Page3, skipOffstage: false), findsNothing); // // Next, let's navigate to /page3 // await tester.tap(find.text("pushNamed to page3")); await tester.pumpAndSettle(); // Confirm we are on /page3 expect(find.byType(Page1), findsNothing); expect(find.byType(Page2), findsNothing); expect(find.byType(Page3), findsOneWidget); expect(find.byType(Page1, skipOffstage: false), findsOneWidget); expect(find.byType(Page2, skipOffstage: false), findsOneWidget); expect(find.byType(Page3, skipOffstage: false), findsOneWidget); // // Next, let's navigate back to /page2 // await tester.tap(find.text("pop")); await tester.pumpAndSettle(); // confirm we are on /page2 expect(find.byType(Page1), findsNothing); expect(find.byType(Page2), findsOneWidget); expect(find.byType(Page3), findsNothing); expect(find.byType(Page1, skipOffstage: false), findsOneWidget); expect(find.byType(Page2, skipOffstage: false), findsOneWidget); expect(find.byType(Page3, skipOffstage: false), findsNothing); // // Finally, let's navigate back to /page3 and then popUntil we are on /page1 // await tester.tap(find.text("pushNamed to page3")); await tester.pumpAndSettle(); // Confirm we are on /page3 expect(find.byType(Page1), findsNothing); expect(find.byType(Page2), findsNothing); expect(find.byType(Page3), findsOneWidget); expect(find.byType(Page1, skipOffstage: false), findsOneWidget); expect(find.byType(Page2, skipOffstage: false), findsOneWidget); expect(find.byType(Page3, skipOffstage: false), findsOneWidget); await tester.tap(find.text("popUntil page1")); await tester.pumpAndSettle(); // Confirm we are on /page1 expect(find.byType(Page1), findsOneWidget); expect(find.byType(Page2), findsNothing); expect(find.byType(Page3), findsNothing); expect(find.byType(Page1, skipOffstage: false), findsOneWidget); expect(find.byType(Page2, skipOffstage: false), findsNothing); expect(find.byType(Page3, skipOffstage: false), findsNothing); }); } ================================================ FILE: recipes/flutter_test/what_if_i_need_build_context/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages # Flutter Test Cookbook (flutter_test) .dart_tool/ .metadata .packages android/ ios/ pubspec.lock ftc.iml *.*~ test_driver/ ================================================ FILE: recipes/flutter_test/what_if_i_need_build_context/README.md ================================================ # Question What do I do if I need a [BuildContext](https://api.flutter.dev/flutter/widgets/BuildContext-class.html)? # Answer There are several reasons we might _want_ to use a BuildContext in our tests (it is a matter of opinion if we actually should). There are two main methods to get a BuildContext when using flutter_test. a) Finding an [Element](https://api.flutter.dev/flutter/widgets/Element-class.html) and taking advantage of the fact that [an Element can be used as a BuildContext](https://www.reddit.com/r/Flutter/comments/bcmj70/please_tell_me_simply_what_is_context_and_build/eldf63d?utm_source=share&utm_medium=web2x) b) Using a [GlobalKey](https://api.flutter.dev/flutter/widgets/GlobalKey-class.html) For the sake of this recipe, we are going to use a _contrived_ example. We have two pages, Page1 and Page2, and we want to navigate between them in our tests using a [Navigator](https://api.flutter.dev/flutter/dart-html/Navigator-class.html). ## 1) Create a flutter application. ```sh flutter create ftc cd ftc ``` ## 2) Get dependencies ```sh flutter packages get ``` ## 3) Replace the `lib/main.dart` file Replace the `lib/main.dart` file with the following: ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( initialRoute: "/page1", routes: { "/page1": (BuildContext context) => Page1(), "/page2": (BuildContext context) => Page2(), }, ); } } class Page1 extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center(child: Text("Page 1")), ); } } class Page2 extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center(child: Text("Page 2")), ); } } ``` ## 4) Replace the `test/widget_test.dart` file. Replace the `test/widget_test.dart` file with the following: ```dart import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets("What if I need a build context?", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); Finder page1Finder = find.byType(Page1); Finder page2Finder = find.byType(Page2); // Since the initial route was for /page1 // we expect to see a [Page1] widget and not a [Page2] widget expect(page1Finder, findsOneWidget); expect(page2Finder, findsNothing); // // Method a) // // get [BuildContext] from an element BuildContext page1BuildContext = tester.element(page1Finder); // find the closest [Navigator] (which is made available because of [MaterialApp]) // and pushNamed to /page2 Navigator.of(page1BuildContext).pushNamed("/page2"); // Note, since we are using a [MaterialApp] and its named routes use the [MaterialPageRoute], // there is a transition of 300 ms // https://github.com/flutter/flutter/blob/e58dc16d7bec7199190f1408667e24e38328cc3b/packages/flutter/lib/src/material/page.dart#L61 // ... so we will need to pump until that transition has settled await tester.pumpAndSettle(); // We now expect to be on [Page2] expect(page1Finder, findsNothing); expect(page2Finder, findsOneWidget); // // Method b) // // get [BuildContext] from a [GlobalKey] BuildContext page2BuildContext = page2ScaffoldKey.currentContext; // Let's navigate back to [Page1] Navigator.of(page2BuildContext).pushNamed("/page1"); await tester.pumpAndSettle(); // We now expect to be on [Page1] again expect(page1Finder, findsOneWidget); expect(page2Finder, findsNothing); }); } ``` ## 5) Run the flutter tests ```sh flutter test ``` # Run tests from example code in cookbook itself If you have cloned [flutter_test_cookbook](https://github.com/gadfly361/flutter_test_cookbook/tree/master) and simply want to run the tests from this recipe, then: ```sh flutter create . flutter packages get flutter test ``` # Outputs when recipe was made / updated ## Output of running flutter tests ```sh $ flutter test 00:02 +1: All tests passed! ``` ## Output of running `flutter doctor -v` ```sh $ flutter doctor -v [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US) • Flutter version 1.12.13+hotfix.5 at /Users/matthew/gadfly/flutter_versions/flutter_1.12.13+hotfix.5 • Framework revision 27321ebbad (3 months ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0 [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/matthew/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.3.1, Build version 11C504 • CocoaPods version 1.8.4 [✓] Android Studio (version 3.4) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 35.2.1 • Dart plugin version 183.6270 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01) [✓] IntelliJ IDEA Community Edition (version 2019.3.3) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 44.0.3 • Dart plugin version 193.6494.35 [✓] VS Code (version 1.41.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.4.1 [!] Connected device ! No devices available ! Doctor found issues in 1 category. ``` ================================================ FILE: recipes/flutter_test/what_if_i_need_build_context/lib/main.dart ================================================ import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( initialRoute: "/page1", routes: { "/page1": (BuildContext context) => Page1(), "/page2": (BuildContext context) => Page2(), }, ); } } class Page1 extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center(child: Text("Page 1")), ); } } GlobalKey page2ScaffoldKey = GlobalKey(); class Page2 extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( key: page2ScaffoldKey, body: Center(child: Text("Page 2")), ); } } ================================================ FILE: recipes/flutter_test/what_if_i_need_build_context/pubspec.yaml ================================================ name: ftc description: A new Flutter project. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter ================================================ FILE: recipes/flutter_test/what_if_i_need_build_context/test/widget_test.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:ftc/main.dart'; void main() { testWidgets("What if I need a build context?", (WidgetTester tester) async { await tester.pumpWidget(MyApp()); Finder page1Finder = find.byType(Page1); Finder page2Finder = find.byType(Page2); // Since the initial route was for /page1 // we expect to see a [Page1] widget and not a [Page2] widget expect(page1Finder, findsOneWidget); expect(page2Finder, findsNothing); // // Method a) // // get [BuildContext] from an element BuildContext page1BuildContext = tester.element(page1Finder); // find the closest [Navigator] (which is made available because of [MaterialApp]) // and pushNamed to /page2 Navigator.of(page1BuildContext).pushNamed("/page2"); // Note, since we are using a [MaterialApp] and its named routes use the [MaterialPageRoute], // there is a transition of 300 ms // https://github.com/flutter/flutter/blob/e58dc16d7bec7199190f1408667e24e38328cc3b/packages/flutter/lib/src/material/page.dart#L61 // ... so we will need to pump until that transition has settled await tester.pumpAndSettle(); // We now expect to be on [Page2] expect(page1Finder, findsNothing); expect(page2Finder, findsOneWidget); // // Method b) // // get [BuildContext] from a [GlobalKey] BuildContext page2BuildContext = page2ScaffoldKey.currentContext; // Let's navigate back to [Page1] Navigator.of(page2BuildContext).pushNamed("/page1"); await tester.pumpAndSettle(); // We now expect to be on [Page1] again expect(page1Finder, findsOneWidget); expect(page2Finder, findsNothing); }); }