In order to progress this library and add support for the new integration_test package various things have had to be changed to enable this will still supporting Flutter Driver. The big of which is removing Flutter Driver instance from the `FlutterWorld` instance in favour of an adapter approach whereby driving of the app (whether that is via `flutter_driver` or `WidgetTester`) becomes agnostic see `https://github.com/jonsamwell/flutter_gherkin/blob/f1fb2d4a632362629f5d1a196a0c055f858ad1d7/lib/src/flutter/adapters/app_driver_adapter.dart`.
-`FlutterDriverUtils` has been removed, use `world.appDriver` instead. You can still access the raw driver if needed via `world.appDriver.rawDriver`
- If you are using a custom world object and still want to use Flutter Driver it will need to extend `FlutterDriverWorld` instead of `FlutterWorld`
The change to use the `integration_test` package is a fundamentally different approach. Where using the `flutter_driver` implementation your app is launch in a different process and then controlled by remote RPC calls from the flutter driver again in a different process. Using the new `integration_test` package your tests surround your app and become the app themselves. This removes the need for RPC communication from an external process into the app as well as giving you access to the internal state of your app. This is an altogether better approach, one that is quicker, more maintainable scalable to device testing labs. However, it brings with it, its own set of challenges when trying to make this library work with it. Traditionally this library has evaluated the Gherkin feature files at run time, then used that evaluation to invoke actions against the app under test. However, as the tests need to surround the app in the `integration_test` view of the world the Gherkin tests need to be generated at development time so they can be complied in to a test app. Much like `json_serializable` creates classes that are able to work with json data.
### Steps to get going
1. Add the following `dev_dependencies` to your app's `pubspec.yaml` file
- integration_test
- build_runner
- flutter_gherkin
2. Add the following `build.yaml` to the root of your project. This file allows the dart code generator to target files outside of your application's `lib` folder
```
targets:
$default:
sources:
- lib/**
- pubspec.*
- $package$
# Allows the code generator to target files outside of the lib folder
- integration_test/**.dart
```
3. Add the following file (and folder) `example_with_integration_test\test_driver\integration_test_driver.dart`. This file is the entry point to run your tests. See `https://flutter.dev/docs/testing/integration-tests` for more information.
4. Create a folder call `integration_test` this will eventually contain all your Gherkin feature files and the generated test files.
5. Add the following file (and folder) `integration_test\feature\counter.feature` with the following below contents. This is a basic feature file that will be transform in to a test file that can run a test against the sample app.
```
Feature: Counter
Scenario: User can increment the counter
Given I expect the "counter" to be "0"
When I tap the "increment" button
Then I expect the "counter" to be "1"
```
6. Add the following file (and folder) `integration_test\gherkin_suite_test.dart`. Notice the attribute `@GherkinTestSuite()` this indicates to the code generator to create a partial file for this file with the generated Gherkin tests in `part 'gherkin_suite_test.g.dart';`. Don't worry about the initial errors as this will disappear when the tests are generated.
import 'package:example_with_integration_test/main.dart' as app;
part 'gherkin_suite_test.g.dart';
@GherkinTestSuite()
void main() {
executeTestSuite(
FlutterTestConfiguration.DEFAULT([]),
app.main,
);
}
```
7. We now need to generate the test by running the builder command from the command line in the root of your project. Much like `json_serializable` this will create a `.g.dart` part file that will contain the Gherkin tests in code format which are able to via using the `integration_test` package.
```
flutter pub run build_runner build
```
8. The errors in the `integration_test\gherkin_suite_test.dart` file should have not gone away and it you look in `integration_test\gherkin_suite_test.g.dart` you will see the coded version of the Gherkin tests described in the feature file `integration_test\feature\counter.feature`.
9. We can now run the test using the below command from the root of your project.
10. You can debug the tests by adding a breakpoint to line 12 in `integration_test\gherkin_suite_test.dart` and adding the below to your `.vscode\launch.json` file:
* Upgraded to latest Gherkin library version which fixes issues with non-alpha-numeric characters in multiline strings and comments https://github.com/jonsamwell/dart_gherkin/issues/14 https://github.com/jonsamwell/dart_gherkin/issues/15 https://github.com/jonsamwell/dart_gherkin/issues/16
* Fixed issue where the connection attempt of Flutter driver would not retry before throwing a connection error. This was causing an error on some machines trying to connect to an Android emulator (x86 & x86_64) that runs the googleapis (see https://github.com/flutter/flutter/issues/42433)
* Added a before `onBeforeFlutterDriverConnect` and after `onAfterFlutterDriverConnect` Flutter driver connection method property to the test configuration `FlutterTestConfiguration` to enable custom logic before and after a driver connection attempt.
* Updated library to work with the new way the Flutter stable branch manages logging for Flutter driver
* Added the ability to test against an already running app; enabling you to debug a running application while it has tests executed against it. Setting the configuration property `runningAppProtocolEndpointUri` to the service protocol endpoint (found in stdout when an app has `--verbose` logging turned on) will ensure that the existing app is connected to rather than starting a new instance of the app. NOTE: ensure the app you are trying to connect to calls `enableFlutterDriverExtension()` when it starts up otherwise the Flutter Driver will not be able to connect to it.
* **BREAKING CHANGE** reverse order of `driver` and `finder` in `FlutterDriverUtils#isPresent` . This makes this method's arguments more consistent with all other instance methods in the class by including `driver` first.
*`expect` the presence of `ThenExpectWidgetToBePresent` . If the widget was not present, the method would simply timeout and not report an error for the step.
* Updated to latest Gherkin library (see https://github.com/jonsamwell/dart_gherkin/blob/master/CHANGELOG.md#117---04032020) - this includes a breaking change to the `Hook` interface that will need to be updated if any of the `Scenario` level methods are implemented
* Added a new well known step `Then I expect the widget 'notification' to be present within 2 seconds` which expects a widget with a given key to be present within n seconds
* When more than one connected device is present the device to run against was unknown causing a failure, now a message is logged saying the --device-id argument needs to be set
* Added configuration parameter `flutterBuildTimeout` to allow setting the app build wait timeout. Slower machines may need longer to build and start the Flutter app under test.
* Added Flutter driver reporter - the Flutter Driver logs all messages (even non-error ones) to stderr and will cause the process to be marked as failed by a CI server because of this. So this reporter redirects the messages to the appropriate output stream (stdout / stderr).
* Updated to latest Gherkin lib which implements languages - features can now be written in different languages / dialects! See https://cucumber.io/docs/gherkin/reference/#overview for supported dialects.
* Added ability to include a hook (see `AttachScreenshotOnFailedStepHook` ) that takes a screenshot after a failed step. If using the json reporter it include the screenshot in the report that can then be used to generate a HTML report.