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": [
|
"cSpell.words": [
|
||||||
"Errored",
|
"Errored",
|
||||||
"Serializable",
|
"Serializable",
|
||||||
|
"agnostically",
|
||||||
"microtask",
|
"microtask",
|
||||||
"multiline",
|
"multiline",
|
||||||
"pubspec",
|
"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`.
|
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
|
flutter pub run build_runner build
|
||||||
```
|
```
|
||||||
|
|
|
@ -12,12 +12,13 @@ Feature: Creating todos
|
||||||
Scenario: User can create multiple new todo items
|
Scenario: User can create multiple new todo items
|
||||||
Given I fill the "todo" field with "Buy carrots"
|
Given I fill the "todo" field with "Buy carrots"
|
||||||
When I tap the "add" button
|
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
|
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
|
When I tap the "add" button
|
||||||
Then I expect the todo list
|
Then I expect the todo list
|
||||||
| Todo |
|
| Todo |
|
||||||
| Buy blueberries |
|
| Buy blueberries |
|
||||||
| Buy apples |
|
| 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 'hooks/reset_app_hook.dart';
|
||||||
import 'steps/expect_todos_step.dart';
|
import 'steps/expect_todos_step.dart';
|
||||||
|
import 'steps/when_await_animation.dart';
|
||||||
import 'world/custom_world.dart';
|
import 'world/custom_world.dart';
|
||||||
|
|
||||||
FlutterTestConfiguration gherkinTestConfiguration =
|
FlutterTestConfiguration gherkinTestConfiguration =
|
||||||
FlutterTestConfiguration.DEFAULT([
|
FlutterTestConfiguration.DEFAULT(
|
||||||
thenIExpectTheTodos(),
|
[
|
||||||
])
|
thenIExpectTheTodos,
|
||||||
|
whenAnAnimationIsAwaited,
|
||||||
|
],
|
||||||
|
)
|
||||||
..hooks = [
|
..hooks = [
|
||||||
ResetAppHook(),
|
ResetAppHook(),
|
||||||
]
|
]
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,32 +1,36 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
||||||
import 'package:flutter_gherkin/flutter_gherkin_integration_test.dart';
|
import 'package:flutter_gherkin/flutter_gherkin_integration_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:gherkin/gherkin.dart';
|
import 'package:gherkin/gherkin.dart';
|
||||||
|
|
||||||
StepDefinitionGeneric thenIExpectTheTodos() {
|
final thenIExpectTheTodos = then1<GherkinTable, FlutterWorld>(
|
||||||
return then1<GherkinTable, FlutterWorld>(
|
'I expect the todo list',
|
||||||
'I expect the todo list',
|
(table, context) async {
|
||||||
(table, context) async {
|
expect(context.configuration.timeout, isNotNull);
|
||||||
// get the parent list
|
expect(context.configuration.timeout.inSeconds, 5);
|
||||||
final listTileFinder = context.world.appDriver.findBy(
|
|
||||||
ListTile,
|
// get the parent list
|
||||||
FindType.type,
|
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 text = await context.world.appDriver.getText(finder);
|
||||||
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);
|
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: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 _externalApplicationManager;
|
||||||
|
|
||||||
ExternalApplicationManager get externalApplicationManager =>
|
ExternalApplicationManager get externalApplicationManager =>
|
||||||
|
|
|
@ -68,7 +68,7 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
);
|
);
|
||||||
|
|
||||||
await runStep(
|
await runStep(
|
||||||
'Given I fill the "todo" field with "Buy apples"',
|
'And I fill the "todo" field with "Buy apples"',
|
||||||
<String>[],
|
<String>[],
|
||||||
null,
|
null,
|
||||||
dependencies,
|
dependencies,
|
||||||
|
@ -82,7 +82,7 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
);
|
);
|
||||||
|
|
||||||
await runStep(
|
await runStep(
|
||||||
'Given I fill the "todo" field with "Buy blueberries"',
|
'And I fill the "todo" field with "Buy blueberries"',
|
||||||
<String>[],
|
<String>[],
|
||||||
null,
|
null,
|
||||||
dependencies,
|
dependencies,
|
||||||
|
@ -102,6 +102,13 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
'[{"Todo":"Buy blueberries"},{"Todo":"Buy apples"},{"Todo":"Buy carrots"}]'),
|
'[{"Todo":"Buy blueberries"},{"Todo":"Buy apples"},{"Todo":"Buy carrots"}]'),
|
||||||
dependencies,
|
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/configuration/flutter_driver_test_configuration.dart';
|
||||||
export 'src/flutter/adapters/flutter_driver_app_driver_adapter.dart';
|
export 'src/flutter/adapters/flutter_driver_app_driver_adapter.dart';
|
||||||
export 'src/flutter/reporters/flutter_driver_reporter.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/adapters/widget_tester_app_driver_adapter.dart';
|
||||||
export 'src/flutter/code_generation/annotations/gherkin_full_test_suite_annotation.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/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';
|
import '../runners/flutter_run_process_handler.dart';
|
||||||
|
|
||||||
class FlutterDriverWorld extends FlutterWorld {
|
class FlutterDriverWorld extends FlutterWorld<FlutterDriver> {
|
||||||
FlutterRunProcessHandler _flutterRunProcessHandler;
|
FlutterRunProcessHandler _flutterRunProcessHandler;
|
||||||
|
|
||||||
FlutterDriver get driver => appDriver.rawDriver as FlutterDriver;
|
|
||||||
|
|
||||||
void setFlutterDriver(FlutterDriver flutterDriver) {
|
void setFlutterDriver(FlutterDriver flutterDriver) {
|
||||||
setAppAdapter(FlutterDriverAppDriverAdapter(flutterDriver));
|
setAppAdapter(FlutterDriverAppDriverAdapter(flutterDriver));
|
||||||
}
|
}
|
||||||
|
@ -47,8 +45,8 @@ class FlutterDriverWorld extends FlutterWorld {
|
||||||
Future<void> _closeDriver({
|
Future<void> _closeDriver({
|
||||||
Duration timeout = const Duration(seconds: 60),
|
Duration timeout = const Duration(seconds: 60),
|
||||||
}) async {
|
}) async {
|
||||||
if (driver != null) {
|
if (rawAppDriver != null) {
|
||||||
await driver.close().catchError(
|
await rawAppDriver.close().catchError(
|
||||||
(e, st) {
|
(e, st) {
|
||||||
// Avoid an unhandled error
|
// Avoid an unhandled error
|
||||||
return null;
|
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';
|
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;
|
AppDriverAdapter _adapter;
|
||||||
|
|
||||||
|
/// The adapter that is used to agnostically drive the app under test
|
||||||
AppDriverAdapter get appDriver => _adapter;
|
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) {
|
void setAppAdapter(AppDriverAdapter appAdapter) {
|
||||||
_adapter = appAdapter;
|
_adapter = appAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Restart the app under test
|
||||||
Future<bool> restartApp({
|
Future<bool> restartApp({
|
||||||
Duration timeout = const Duration(seconds: 60),
|
Duration timeout = const Duration(seconds: 60),
|
||||||
}) {
|
}) {
|
||||||
|
|
Loading…
Reference in New Issue