- BREAKING CHANGE: Made `appMainFunction` return a `Future<void>` so it can be async

- Fix: #159: Swipe step not working
- Ensure Hook.onBeforeRun is called before the run starts
- Set Frame policy- defaults to `LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive` to slightly improve performance
This commit is contained in:
Jon Samwell 2021-10-27 20:13:49 +11:00
parent 3c0e1c6270
commit 2db755d23b
15 changed files with 78 additions and 104 deletions

View File

@ -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\\\\packages\\\\integration_test\\\\","dependencies":[]}],"android":[{"name":"integration_test","path":"C:\\\\Google\\\\flutter\\\\packages\\\\integration_test\\\\","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"integration_test","dependencies":[]}],"date_created":"2021-09-16 11:36:24.117283","version":"2.5.0"} {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"integration_test","path":"C:\\\\Google\\\\flutter\\\\packages\\\\integration_test\\\\","dependencies":[]}],"android":[{"name":"integration_test","path":"C:\\\\Google\\\\flutter\\\\packages\\\\integration_test\\\\","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"integration_test","dependencies":[]}],"date_created":"2021-10-27 20:12:58.071212","version":"2.5.3"}

View File

@ -1,3 +1,10 @@
## [3.0.0-rc.6] - 27/10/2021
- BREAKING CHANGE: Made `appMainFunction` return a `Future<void>` so it can be async
- Fix: #159: Swipe step not working
- Ensure Hook.onBeforeRun is called before the run starts
- Set Frame policy- defaults to `LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive` to slightly improve performance
## [3.0.0-rc.5] - 22/06/2021 ## [3.0.0-rc.5] - 22/06/2021
- Ensure scenario support files (world etc) as always disposed ensure when test throws error - Ensure scenario support files (world etc) as always disposed ensure when test throws error

View File

@ -1,16 +1,7 @@
# example_with_integration_test ```
# generate the test suite
flutter pub run build_runner build
A new Flutter project. # run the tests
flutter drive --driver=test_driver/integration_test_driver.dart --target=integration_test/gherkin_suite_test.dart
## Getting Started ```
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

View File

@ -41,7 +41,7 @@ FlutterTestConfiguration gherkinTestConfiguration =
] ]
..createWorld = (config) => Future.value(CustomWorld()); ..createWorld = (config) => Future.value(CustomWorld());
void Function(World) appInitializationFn = (World world) { Future<void> Function(World) appInitializationFn = (World world) async {
// ensure a new injector instance is created each time // ensure a new injector instance is created each time
final injector = Injector(DateTime.now().microsecondsSinceEpoch.toString()); final injector = Injector(DateTime.now().microsecondsSinceEpoch.toString());
final externalApplicationManager = ExternalApplicationManager(injector); final externalApplicationManager = ExternalApplicationManager(injector);

View File

@ -9,7 +9,7 @@ part of 'gherkin_suite_test.dart';
class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner { class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
_CustomGherkinIntegrationTestRunner( _CustomGherkinIntegrationTestRunner(
TestConfiguration configuration, TestConfiguration configuration,
void Function(World) appMainFunction, Future<void> Function(World) appMainFunction,
) : super(configuration, appMainFunction); ) : super(configuration, appMainFunction);
@override @override
@ -182,7 +182,7 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
void executeTestSuite( void executeTestSuite(
TestConfiguration configuration, TestConfiguration configuration,
void Function(World) appMainFunction, Future<void> Function(World) appMainFunction,
) { ) {
_CustomGherkinIntegrationTestRunner(configuration, appMainFunction).run(); _CustomGherkinIntegrationTestRunner(configuration, appMainFunction).run();
} }

View File

@ -10,7 +10,7 @@ Todo _$TodoFromJson(Map<String, dynamic> json) => Todo(
id: json['id'] as String, id: json['id'] as String,
created: DateTime.parse(json['created'] as String), created: DateTime.parse(json['created'] as String),
updated: DateTime.parse(json['updated'] as String), updated: DateTime.parse(json['updated'] as String),
status: _$enumDecode(_$TodoStatusEnumMap, json['status']), status: $enumDecode(_$TodoStatusEnumMap, json['status']),
action: json['action'] as String?, action: json['action'] as String?,
); );
@ -22,32 +22,6 @@ Map<String, dynamic> _$TodoToJson(Todo instance) => <String, dynamic>{
'status': _$TodoStatusEnumMap[instance.status], 'status': _$TodoStatusEnumMap[instance.status],
}; };
K _$enumDecode<K, V>(
Map<K, V> enumValues,
Object? source, {
K? unknownValue,
}) {
if (source == null) {
throw ArgumentError(
'A value must be provided. Supported values: '
'${enumValues.values.join(', ')}',
);
}
return enumValues.entries.singleWhere(
(e) => e.value == source,
orElse: () {
if (unknownValue == null) {
throw ArgumentError(
'`$source` is not one of the supported values: '
'${enumValues.values.join(', ')}',
);
}
return MapEntry(unknownValue, enumValues.values.first);
},
).key;
}
const _$TodoStatusEnumMap = { const _$TodoStatusEnumMap = {
TodoStatus.pending: 'pending', TodoStatus.pending: 'pending',
TodoStatus.complete: 'complete', TodoStatus.complete: 'complete',

View File

@ -7,14 +7,14 @@ packages:
name: _fe_analyzer_shared name: _fe_analyzer_shared
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "25.0.0" version: "30.0.0"
analyzer: analyzer:
dependency: transitive dependency: transitive
description: description:
name: analyzer name: analyzer
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.2.0" version: "2.7.0"
archive: archive:
dependency: transitive dependency: transitive
description: description:
@ -49,7 +49,7 @@ packages:
name: build name: build
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.0" version: "2.1.1"
build_config: build_config:
dependency: transitive dependency: transitive
description: description:
@ -63,7 +63,7 @@ packages:
name: build_daemon name: build_daemon
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.0" version: "3.0.1"
build_resolvers: build_resolvers:
dependency: transitive dependency: transitive
description: description:
@ -77,14 +77,14 @@ packages:
name: build_runner name: build_runner
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.2" version: "2.1.4"
build_runner_core: build_runner_core:
dependency: transitive dependency: transitive
description: description:
name: build_runner_core name: build_runner_core
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "7.1.0" version: "7.2.2"
built_collection: built_collection:
dependency: transitive dependency: transitive
description: description:
@ -126,7 +126,7 @@ packages:
name: cli_util name: cli_util
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.3" version: "0.3.5"
clock: clock:
dependency: transitive dependency: transitive
description: description:
@ -168,7 +168,7 @@ packages:
name: dart_style name: dart_style
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.0" version: "2.2.0"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -213,7 +213,7 @@ packages:
path: ".." path: ".."
relative: true relative: true
source: path source: path
version: "3.0.0-rc.3" version: "3.0.0-rc.6"
flutter_simple_dependency_injection: flutter_simple_dependency_injection:
dependency: "direct main" dependency: "direct main"
description: description:
@ -256,7 +256,7 @@ packages:
name: glob name: glob
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.1" version: "2.0.2"
graphs: graphs:
dependency: transitive dependency: transitive
description: description:
@ -303,14 +303,14 @@ packages:
name: json_annotation name: json_annotation
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.1.0" version: "4.3.0"
json_serializable: json_serializable:
dependency: "direct main" dependency: "direct main"
description: description:
name: json_serializable name: json_serializable
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "5.0.0" version: "6.0.1"
logging: logging:
dependency: transitive dependency: transitive
description: description:
@ -338,7 +338,7 @@ packages:
name: mime name: mime
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.0.1"
package_config: package_config:
dependency: transitive dependency: transitive
description: description:
@ -374,13 +374,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.3" version: "2.0.3"
pedantic:
dependency: transitive
description:
name: pedantic
url: "https://pub.dartlang.org"
source: hosted
version: "1.11.1"
platform: platform:
dependency: transitive dependency: transitive
description: description:
@ -394,7 +387,7 @@ packages:
name: plugin_platform_interface name: plugin_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.1" version: "2.0.2"
pool: pool:
dependency: transitive dependency: transitive
description: description:
@ -422,7 +415,7 @@ packages:
name: pubspec_parse name: pubspec_parse
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.1.0"
rxdart: rxdart:
dependency: "direct main" dependency: "direct main"
description: description:
@ -436,7 +429,7 @@ packages:
name: shared_preferences name: shared_preferences
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.7" version: "2.0.8"
shared_preferences_linux: shared_preferences_linux:
dependency: transitive dependency: transitive
description: description:
@ -497,14 +490,14 @@ packages:
name: source_gen name: source_gen
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "1.1.1"
source_helper: source_helper:
dependency: transitive dependency: transitive
description: description:
name: source_helper name: source_helper
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.1" version: "1.3.0"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
@ -581,7 +574,7 @@ packages:
name: uuid name: uuid
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.4" version: "3.0.5"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@ -602,7 +595,7 @@ packages:
name: watcher name: watcher
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.0.1"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
@ -623,7 +616,7 @@ packages:
name: win32 name: win32
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.2.9" version: "2.2.10"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:

View File

@ -12,11 +12,11 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
json_serializable: ^5.0.0 json_serializable: ^6.0.1
json_annotation: ^4.1.0 json_annotation: ^4.3.0
rxdart: ^0.27.2 rxdart: ^0.27.2
shared_preferences: ^2.0.7 shared_preferences: ^2.0.8
uuid: ^3.0.4 uuid: ^3.0.5
flutter_simple_dependency_injection: ^2.0.0 flutter_simple_dependency_injection: ^2.0.0
dev_dependencies: dev_dependencies:

View File

@ -18,9 +18,13 @@ class WidgetTesterAppDriverAdapter
Duration? timeout = const Duration(seconds: 30), Duration? timeout = const Duration(seconds: 30),
}) async { }) async {
try { try {
return await nativeDriver.pumpAndSettle( final pumps = await nativeDriver.pumpAndSettle(
duration!, duration ?? const Duration(milliseconds: 100),
EnginePhase.sendSemanticsUpdate,
timeout ?? const Duration(seconds: 30),
); );
return pumps;
} catch (_) { } catch (_) {
return 1; return 1;
} }

View File

@ -16,7 +16,7 @@ class GherkinSuiteTestGenerator
class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner { class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
_CustomGherkinIntegrationTestRunner( _CustomGherkinIntegrationTestRunner(
TestConfiguration configuration, TestConfiguration configuration,
void Function(World) appMainFunction, Future<void> Function(World) appMainFunction,
) : super(configuration, appMainFunction); ) : super(configuration, appMainFunction);
@override @override
@ -29,7 +29,7 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
void executeTestSuite( void executeTestSuite(
TestConfiguration configuration, TestConfiguration configuration,
void Function(World) appMainFunction, Future<void> Function(World) appMainFunction,
) { ) {
_CustomGherkinIntegrationTestRunner(configuration, appMainFunction).run(); _CustomGherkinIntegrationTestRunner(configuration, appMainFunction).run();
} }

View File

@ -21,7 +21,7 @@ abstract class GherkinIntegrationTestRunner {
final TagExpressionEvaluator _tagExpressionEvaluator = final TagExpressionEvaluator _tagExpressionEvaluator =
TagExpressionEvaluator(); TagExpressionEvaluator();
final TestConfiguration configuration; final TestConfiguration configuration;
final void Function(World world) appMainFunction; final Future<void> Function(World world) appMainFunction;
Reporter? _reporter; Reporter? _reporter;
Hook? _hook; Hook? _hook;
Iterable<ExecutableStep>? _executableSteps; Iterable<ExecutableStep>? _executableSteps;
@ -31,6 +31,7 @@ abstract class GherkinIntegrationTestRunner {
Reporter get reporter => _reporter!; Reporter get reporter => _reporter!;
Hook get hook => _hook!; Hook get hook => _hook!;
LiveTestWidgetsFlutterBindingFramePolicy? get framePolicy => null;
Timeout scenarioExecutionTimeout = const Timeout(Duration(minutes: 10)); Timeout scenarioExecutionTimeout = const Timeout(Duration(minutes: 10));
@ -53,7 +54,8 @@ abstract class GherkinIntegrationTestRunner {
_binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() _binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized()
as IntegrationTestWidgetsFlutterBinding; as IntegrationTestWidgetsFlutterBinding;
_safeInvokeFuture(() async => await reporter.onTestRunStarted()); _binding!.framePolicy =
framePolicy ?? LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive;
tearDownAll( tearDownAll(
() { () {
@ -61,6 +63,9 @@ abstract class GherkinIntegrationTestRunner {
}, },
); );
_safeInvokeFuture(() async => await hook.onBeforeRun(configuration));
_safeInvokeFuture(() async => await reporter.onTestRunStarted());
onRun(); onRun();
} }
@ -217,7 +222,7 @@ abstract class GherkinIntegrationTestRunner {
WidgetTester tester, WidgetTester tester,
World world, World world,
) async { ) async {
appMainFunction(world); await appMainFunction(world);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
} }

View File

@ -1,4 +1,4 @@
import 'package:flutter_driver/flutter_driver.dart'; import 'package:flutter_gherkin/flutter_gherkin.dart';
import 'package:flutter_gherkin/src/flutter/world/flutter_world.dart'; import 'package:flutter_gherkin/src/flutter/world/flutter_world.dart';
import 'package:gherkin/gherkin.dart'; import 'package:gherkin/gherkin.dart';
@ -7,7 +7,7 @@ import '../parameters/swipe_direction_parameter.dart';
mixin _SwipeHelper mixin _SwipeHelper
on When3WithWorld<SwipeDirection, int, String, FlutterWorld> { on When3WithWorld<SwipeDirection, int, String, FlutterWorld> {
Future<void> swipeOnFinder( Future<void> swipeOnFinder(
SerializableFinder finder, dynamic finder,
SwipeDirection direction, SwipeDirection direction,
int swipeAmount, int swipeAmount,
) async { ) async {
@ -52,7 +52,7 @@ class SwipeOnKeyStep
int swipeAmount, int swipeAmount,
String key, String key,
) async { ) async {
final finder = find.byValueKey(key); final finder = this.world.appDriver.findBy(key, FindType.key);
await swipeOnFinder(finder, direction, swipeAmount); await swipeOnFinder(finder, direction, swipeAmount);
} }
@ -75,7 +75,7 @@ class SwipeOnTextStep
int swipeAmount, int swipeAmount,
String text, String text,
) async { ) async {
final finder = find.text(text); final finder = this.world.appDriver.findBy(text, FindType.text);
await swipeOnFinder(finder, direction, swipeAmount); await swipeOnFinder(finder, direction, swipeAmount);
} }

View File

@ -7,14 +7,14 @@ packages:
name: _fe_analyzer_shared name: _fe_analyzer_shared
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "26.0.0" version: "30.0.0"
analyzer: analyzer:
dependency: "direct main" dependency: "direct main"
description: description:
name: analyzer name: analyzer
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.3.0" version: "2.7.0"
archive: archive:
dependency: transitive dependency: transitive
description: description:
@ -49,7 +49,7 @@ packages:
name: build name: build
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.0" version: "2.1.1"
build_config: build_config:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -84,7 +84,7 @@ packages:
name: cli_util name: cli_util
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.3" version: "0.3.5"
clock: clock:
dependency: transitive dependency: transitive
description: description:
@ -119,7 +119,7 @@ packages:
name: dart_style name: dart_style
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.0" version: "2.2.0"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -167,7 +167,7 @@ packages:
name: glob name: glob
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.1" version: "2.0.2"
integration_test: integration_test:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -179,7 +179,7 @@ packages:
name: json_annotation name: json_annotation
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.1.0" version: "4.3.0"
logging: logging:
dependency: transitive dependency: transitive
description: description:
@ -261,7 +261,7 @@ packages:
name: source_gen name: source_gen
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "1.1.1"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
@ -338,7 +338,7 @@ packages:
name: watcher name: watcher
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.0.1"
webdriver: webdriver:
dependency: transitive dependency: transitive
description: description:
@ -354,5 +354,5 @@ packages:
source: hosted source: hosted
version: "3.1.0" version: "3.1.0"
sdks: sdks:
dart: ">=2.12.3 <3.0.0" dart: ">=2.14.0 <3.0.0"
flutter: ">=2.2.0" flutter: ">=2.2.0"

View File

@ -1,6 +1,6 @@
name: flutter_gherkin name: flutter_gherkin
description: A Gherkin / Cucumber parser and test runner for Dart and Flutter description: A Gherkin / Cucumber parser and test runner for Dart and Flutter
version: 3.0.0-rc.5 version: 3.0.0-rc.6
homepage: https://github.com/jonsamwell/flutter_gherkin homepage: https://github.com/jonsamwell/flutter_gherkin
environment: environment:
@ -19,9 +19,9 @@ dependencies:
analyzer: ">=1.7.1 <3.0.0" analyzer: ">=1.7.1 <3.0.0"
collection: ^1.15.0 collection: ^1.15.0
gherkin: ^2.0.5+1 gherkin: ^2.0.5+1
source_gen: ^1.1.0 source_gen: ^1.1.1
build: ^2.1.0 build: ^2.1.1
glob: ^2.0.1 glob: ^2.0.2
# gherkin: # gherkin:
# path: ../dart_gherkin # path: ../dart_gherkin