feat(drivers): added typed driver flutter world
This commit is contained in:
parent
c372525e42
commit
2727535321
|
@ -1 +1 @@
|
|||
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"integration_test","path":"C:\\\\Google\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\integration_test-1.0.1\\\\","dependencies":[]}],"android":[{"name":"integration_test","path":"C:\\\\Google\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\integration_test-1.0.1\\\\","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"integration_test","dependencies":[]}],"date_created":"2021-01-13 12:57:44.197577","version":"1.22.5"}
|
||||
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"integration_test","path":"C:\\\\Google\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\integration_test-1.0.1\\\\","dependencies":[]}],"android":[{"name":"integration_test","path":"C:\\\\Google\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\integration_test-1.0.1\\\\","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"integration_test","dependencies":[]}],"date_created":"2021-01-14 08:07:08.545183","version":"1.22.5"}
|
|
@ -2,6 +2,7 @@
|
|||
"cSpell.words": [
|
||||
"Errored",
|
||||
"Serializable",
|
||||
"agnostically",
|
||||
"microtask",
|
||||
"multiline",
|
||||
"pubspec",
|
||||
|
|
|
@ -107,7 +107,7 @@ flutter drive --driver=test_driver/integration_test_driver.dart --target=integra
|
|||
}
|
||||
```
|
||||
11. Custom world need to extend `FlutterWorld` note `FlutterDriverWorld`.
|
||||
12. If you change any of the feature files you will need to regenerate the tests using the below command
|
||||
12. If you change any of the feature files you will need to re-generate the tests using the below command
|
||||
```
|
||||
flutter pub run build_runner build
|
||||
```
|
||||
|
|
|
@ -12,12 +12,13 @@ Feature: Creating todos
|
|||
Scenario: User can create multiple new todo items
|
||||
Given I fill the "todo" field with "Buy carrots"
|
||||
When I tap the "add" button
|
||||
Given I fill the "todo" field with "Buy apples"
|
||||
And I fill the "todo" field with "Buy apples"
|
||||
When I tap the "add" button
|
||||
Given I fill the "todo" field with "Buy blueberries"
|
||||
And I fill the "todo" field with "Buy blueberries"
|
||||
When I tap the "add" button
|
||||
Then I expect the todo list
|
||||
| Todo |
|
||||
| Buy blueberries |
|
||||
| Buy apples |
|
||||
| Buy carrots |
|
||||
| Buy carrots |
|
||||
Given I wait 5 seconds for the animation to complete
|
|
@ -7,12 +7,16 @@ import 'package:gherkin/gherkin.dart';
|
|||
|
||||
import 'hooks/reset_app_hook.dart';
|
||||
import 'steps/expect_todos_step.dart';
|
||||
import 'steps/when_await_animation.dart';
|
||||
import 'world/custom_world.dart';
|
||||
|
||||
FlutterTestConfiguration gherkinTestConfiguration =
|
||||
FlutterTestConfiguration.DEFAULT([
|
||||
thenIExpectTheTodos(),
|
||||
])
|
||||
FlutterTestConfiguration.DEFAULT(
|
||||
[
|
||||
thenIExpectTheTodos,
|
||||
whenAnAnimationIsAwaited,
|
||||
],
|
||||
)
|
||||
..hooks = [
|
||||
ResetAppHook(),
|
||||
]
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,32 +1,36 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
||||
import 'package:flutter_gherkin/flutter_gherkin_integration_test.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:gherkin/gherkin.dart';
|
||||
|
||||
StepDefinitionGeneric thenIExpectTheTodos() {
|
||||
return then1<GherkinTable, FlutterWorld>(
|
||||
'I expect the todo list',
|
||||
(table, context) async {
|
||||
// get the parent list
|
||||
final listTileFinder = context.world.appDriver.findBy(
|
||||
ListTile,
|
||||
FindType.type,
|
||||
final thenIExpectTheTodos = then1<GherkinTable, FlutterWorld>(
|
||||
'I expect the todo list',
|
||||
(table, context) async {
|
||||
expect(context.configuration.timeout, isNotNull);
|
||||
expect(context.configuration.timeout.inSeconds, 5);
|
||||
|
||||
// get the parent list
|
||||
final listTileFinder = context.world.appDriver.findBy(
|
||||
ListTile,
|
||||
FindType.type,
|
||||
);
|
||||
|
||||
for (final row in table.rows) {
|
||||
final todoText = row.columns.elementAt(0);
|
||||
final listTileTextFinder = context.world.appDriver.findBy(
|
||||
todoText,
|
||||
FindType.text,
|
||||
);
|
||||
// find the todo by the expected text
|
||||
final finder = await context.world.appDriver
|
||||
.findByDescendant(listTileFinder, listTileTextFinder);
|
||||
|
||||
for (final row in table.rows) {
|
||||
final todoText = row.columns.elementAt(0);
|
||||
final listTileTextFinder = context.world.appDriver.findBy(
|
||||
todoText,
|
||||
FindType.text,
|
||||
);
|
||||
// find the todo by the expected text
|
||||
final finder = await context.world.appDriver
|
||||
.findByDescendant(listTileFinder, listTileTextFinder);
|
||||
final text = await context.world.appDriver.getText(finder);
|
||||
|
||||
final text = await context.world.appDriver.getText(finder);
|
||||
|
||||
context.expect(todoText, text);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
context.expect(todoText, text);
|
||||
}
|
||||
},
|
||||
configuration: StepDefinitionConfiguration()
|
||||
..timeout = const Duration(seconds: 5),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import 'package:flutter/widgets.dart';
|
||||
import 'package:gherkin/gherkin.dart';
|
||||
import 'package:flutter_gherkin/flutter_gherkin_integration_test.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
final whenAnAnimationIsAwaited = when1<int, FlutterWidgetTesterWorld>(
|
||||
'I wait {int} seconds for the animation to complete',
|
||||
(duration, context) async {
|
||||
final tester = context.world.appDriver.rawDriver;
|
||||
|
||||
try {
|
||||
await tester.pumpAndSettle(
|
||||
const Duration(milliseconds: 100),
|
||||
EnginePhase.sendSemanticsUpdate,
|
||||
Duration(seconds: duration),
|
||||
);
|
||||
// ignore: avoid_catching_errors
|
||||
} on FlutterError {
|
||||
// pump for 2 seconds and stop
|
||||
}
|
||||
},
|
||||
configuration: StepDefinitionConfiguration()
|
||||
..timeout = const Duration(minutes: 5),
|
||||
);
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:example_with_integration_test/services/external_application_manager.dart';
|
||||
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
||||
import 'package:flutter_gherkin/flutter_gherkin_integration_test.dart';
|
||||
|
||||
class CustomWorld extends FlutterWorld {
|
||||
class CustomWorld extends FlutterWidgetTesterWorld {
|
||||
ExternalApplicationManager _externalApplicationManager;
|
||||
|
||||
ExternalApplicationManager get externalApplicationManager =>
|
||||
|
|
|
@ -68,7 +68,7 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
|||
);
|
||||
|
||||
await runStep(
|
||||
'Given I fill the "todo" field with "Buy apples"',
|
||||
'And I fill the "todo" field with "Buy apples"',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
|
@ -82,7 +82,7 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
|||
);
|
||||
|
||||
await runStep(
|
||||
'Given I fill the "todo" field with "Buy blueberries"',
|
||||
'And I fill the "todo" field with "Buy blueberries"',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
|
@ -102,6 +102,13 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
|||
'[{"Todo":"Buy blueberries"},{"Todo":"Buy apples"},{"Todo":"Buy carrots"}]'),
|
||||
dependencies,
|
||||
);
|
||||
|
||||
await runStep(
|
||||
'Given I wait 5 seconds for the animation to complete',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
|
|
@ -32,3 +32,4 @@ export 'src/flutter/hooks/attach_screenshot_on_failed_step_hook.dart';
|
|||
export 'src/flutter/configuration/flutter_driver_test_configuration.dart';
|
||||
export 'src/flutter/adapters/flutter_driver_app_driver_adapter.dart';
|
||||
export 'src/flutter/reporters/flutter_driver_reporter.dart';
|
||||
export 'src/flutter/world/flutter_driver_world.dart';
|
||||
|
|
|
@ -37,3 +37,4 @@ export 'src/flutter/hooks/attach_screenshot_on_failed_step_hook.dart';
|
|||
export 'src/flutter/adapters/widget_tester_app_driver_adapter.dart';
|
||||
export 'src/flutter/code_generation/annotations/gherkin_full_test_suite_annotation.dart';
|
||||
export 'src/flutter/runners/gherkin_integration_test_runner.dart';
|
||||
export 'src/flutter/world/flutter_widget_tester_world.dart';
|
||||
|
|
|
@ -3,11 +3,9 @@ import 'package:flutter_gherkin/flutter_gherkin.dart';
|
|||
|
||||
import '../runners/flutter_run_process_handler.dart';
|
||||
|
||||
class FlutterDriverWorld extends FlutterWorld {
|
||||
class FlutterDriverWorld extends FlutterWorld<FlutterDriver> {
|
||||
FlutterRunProcessHandler _flutterRunProcessHandler;
|
||||
|
||||
FlutterDriver get driver => appDriver.rawDriver as FlutterDriver;
|
||||
|
||||
void setFlutterDriver(FlutterDriver flutterDriver) {
|
||||
setAppAdapter(FlutterDriverAppDriverAdapter(flutterDriver));
|
||||
}
|
||||
|
@ -47,8 +45,8 @@ class FlutterDriverWorld extends FlutterWorld {
|
|||
Future<void> _closeDriver({
|
||||
Duration timeout = const Duration(seconds: 60),
|
||||
}) async {
|
||||
if (driver != null) {
|
||||
await driver.close().catchError(
|
||||
if (rawAppDriver != null) {
|
||||
await rawAppDriver.close().catchError(
|
||||
(e, st) {
|
||||
// Avoid an unhandled error
|
||||
return null;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
||||
|
||||
/// The world object that can be used to store state during a single test.
|
||||
/// It also allows interaction with the app under test through the `appDriver`
|
||||
/// which exposes an instance of `AppDriverAdapter` and an
|
||||
/// instance of `WidgetTester` via the property `rawAppDriver`
|
||||
class FlutterWidgetTesterWorld<WidgetTester>
|
||||
extends FlutterWorld<WidgetTester> {}
|
|
@ -3,15 +3,27 @@ import 'package:gherkin/gherkin.dart';
|
|||
|
||||
import '../adapters/app_driver_adapter.dart';
|
||||
|
||||
class FlutterWorld extends World {
|
||||
/// The world object that can be used to store state during a single test.
|
||||
/// It also allows interaction with the app under test through the `appDriver`
|
||||
/// which exposes an instance of `AppDriverAdapter`
|
||||
class FlutterWorld<TDriver> extends World {
|
||||
AppDriverAdapter _adapter;
|
||||
|
||||
/// The adapter that is used to agnostically drive the app under test
|
||||
AppDriverAdapter get appDriver => _adapter;
|
||||
|
||||
/// The underlying driver that is able to instrument the app under test
|
||||
/// It is suggested you use `appDriver` for all interactions with the app under tests
|
||||
/// however if you need a specific api not available on `appDriver` this property
|
||||
/// exposes the actual class that can interact with the app under test
|
||||
TDriver get rawAppDriver => _adapter.rawDriver as TDriver;
|
||||
|
||||
/// Sets the app driver that is used to control the app under test
|
||||
void setAppAdapter(AppDriverAdapter appAdapter) {
|
||||
_adapter = appAdapter;
|
||||
}
|
||||
|
||||
/// Restart the app under test
|
||||
Future<bool> restartApp({
|
||||
Duration timeout = const Duration(seconds: 60),
|
||||
}) {
|
||||
|
|
Loading…
Reference in New Issue