feat(integration_test): added concept of an app driver adapter putting a facade over the Flutter driver and WidgetTester so driving the app becomes agnostic of implementation

This commit is contained in:
Jon Samwell 2021-01-07 12:43:26 +11:00
parent 1c6a9cba2a
commit 7ba52462c5
28 changed files with 530 additions and 163 deletions

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"cSpell.words": [
"Serializable"
]
}

View File

@ -610,6 +610,8 @@ StepDefinitionGeneric TapButtonNTimesStep() {
await FlutterDriverUtils.tap(context.world.driver, locator);
}
},
configuration: StepDefinitionConfiguration()
..timeout = const Duration(seconds: 10),
);
}
```

View File

@ -1,4 +1,3 @@
import 'package:flutter_driver/flutter_driver.dart';
import 'package:flutter_gherkin/flutter_gherkin.dart';
import 'package:gherkin/gherkin.dart';
@ -6,9 +5,9 @@ StepDefinitionGeneric TapButtonNTimesStep() {
return given2<String, int, FlutterWorld>(
'I tap the {string} button {int} times',
(key, count, context) async {
final locator = find.byValueKey(key);
final locator = context.world.appDriver.findBy(key, FindType.key);
for (var i = 0; i < count; i += 1) {
await FlutterDriverUtils.tap(context.world.driver, locator);
await context.world.appDriver.tap(locator);
}
},
);

View File

@ -5,6 +5,8 @@ export 'src/flutter/build_mode.dart';
export 'src/flutter/flutter_world.dart';
export 'src/flutter/flutter_test_configuration.dart';
export 'src/flutter/utils/driver_utils.dart';
export 'src/flutter/adapters/app_driver_adapter.dart';
export 'src/flutter/adapters/flutter_driver_app_driver_adapter.dart';
// Well known steps
export 'src/flutter/steps/given_i_open_the_drawer_step.dart';

View File

@ -0,0 +1,131 @@
import 'dart:async';
enum FindType {
key,
pageBack,
text,
tooltip,
type,
}
abstract class AppDriverAdapter<TRawAdapter, TFinderType, TWidgetBaseType> {
TRawAdapter _driver;
AppDriverAdapter(this._driver);
TRawAdapter get rawDriver => _driver;
void setRawDriver(TRawAdapter driver) {
_driver = driver;
}
TFinderType findBy(
String text,
FindType type,
);
TFinderType findByAncestor(
TFinderType of,
TFinderType matching, {
bool matchRoot = false,
bool firstMatchOnly = false,
});
TFinderType findByDescendant(
TFinderType of,
TFinderType matching, {
bool matchRoot = false,
bool firstMatchOnly = false,
});
Future<int> waitForAppToSettle({
Duration duration = const Duration(milliseconds: 100),
Duration timeout = const Duration(seconds: 30),
});
Future<T> widget<T extends TWidgetBaseType>(TFinderType finder);
Future<List<int>> screenshot();
Future<bool> isPresent(
TFinderType finder, {
Duration timeout = const Duration(seconds: 1),
});
Future<bool> isAbsent(
TFinderType finder, {
Duration timeout = const Duration(seconds: 1),
});
Future<void> enterText(
TFinderType finder,
String text, {
Duration timeout = const Duration(seconds: 30),
});
Future<String> getText(
TFinderType finder, {
Duration timeout = const Duration(seconds: 30),
});
Future<void> tap(
TFinderType finder, {
Duration timeout = const Duration(seconds: 30),
});
Future<void> longPress(
TFinderType finder, {
Duration pressDuration = const Duration(milliseconds: 500),
Duration timeout = const Duration(seconds: 30),
});
Future<void> scroll(
TFinderType finder, {
double dx = 0,
double dy = 0,
Duration duration = const Duration(seconds: 200),
Duration timeout = const Duration(seconds: 30),
});
Future<void> scrollUntilVisible(
TFinderType parent,
TFinderType item, {
double dx = 0,
double dy = 0,
Duration timeout = const Duration(seconds: 30),
});
Future<void> scrollIntoView(
TFinderType finder, {
Duration timeout = const Duration(seconds: 30),
});
Future<void> waitUntil(
Future<bool> Function() condition, {
Duration timeout = const Duration(seconds: 10),
Duration pollInterval = const Duration(milliseconds: 500),
}) async {
return Future.microtask(
() async {
final completer = Completer<void>();
var maxAttempts =
(timeout.inMilliseconds / pollInterval.inMilliseconds).round();
var attempts = 0;
while (attempts < maxAttempts) {
final result = await condition();
if (result) {
completer.complete();
break;
} else {
await Future.delayed(pollInterval);
}
}
},
).timeout(
timeout,
);
}
void dispose() {}
}

View File

@ -0,0 +1,225 @@
import 'dart:async';
import 'package:flutter_driver/flutter_driver.dart';
import 'app_driver_adapter.dart';
class FlutterDriverAppDriverAdapter
extends AppDriverAdapter<FlutterDriver, SerializableFinder, dynamic> {
FlutterDriverAppDriverAdapter(FlutterDriver rawAdapter) : super(rawAdapter);
@override
Future<int> waitForAppToSettle({
Duration duration = const Duration(milliseconds: 100),
Duration timeout = const Duration(seconds: 30),
}) async {
try {
await rawDriver.waitUntilNoTransientCallbacks(timeout: timeout);
} catch (_) {
return null;
}
return null;
}
@override
Future<T> widget<T extends Object>(SerializableFinder finder) {
throw UnimplementedError(
'Flutter driver does not support directly interacting with the widget tree');
}
@override
void dispose() {
rawDriver.close().catchError(
(e, st) {
// Avoid an unhandled error
return null;
},
);
}
@override
Future<List<int>> screenshot() {
return rawDriver.screenshot();
}
@override
Future<bool> isPresent(
SerializableFinder finder, {
Duration timeout = const Duration(seconds: 1),
}) async {
try {
await rawDriver.waitFor(
finder,
timeout: timeout,
);
return true;
} catch (_) {
return false;
}
}
@override
Future<bool> isAbsent(
SerializableFinder finder, {
Duration timeout = const Duration(seconds: 1),
}) async {
try {
await rawDriver.waitForAbsent(
finder,
timeout: timeout,
);
return true;
} catch (_) {
return false;
}
}
@override
Future<String> getText(
SerializableFinder finder, {
Duration timeout = const Duration(seconds: 30),
}) async {
await waitForAppToSettle(timeout: timeout);
return await rawDriver.getText(
finder,
timeout: timeout,
);
}
@override
Future<void> enterText(
SerializableFinder finder,
String text, {
Duration timeout = const Duration(seconds: 30),
}) async {
await tap(
finder,
timeout: timeout,
);
await rawDriver.enterText(
text,
timeout: timeout,
);
}
@override
Future<void> tap(
SerializableFinder finder, {
Duration timeout = const Duration(seconds: 30),
}) async {
await rawDriver.tap(finder, timeout: timeout);
await waitForAppToSettle(timeout: timeout);
}
@override
Future<void> longPress(
SerializableFinder finder, {
Duration pressDuration = const Duration(milliseconds: 500),
Duration timeout = const Duration(seconds: 30),
}) async {
await scroll(
finder,
dx: 0,
dy: 0,
duration: pressDuration,
timeout: timeout,
);
await waitForAppToSettle(timeout: timeout);
}
@override
Future<void> scroll(
SerializableFinder finder, {
double dx = 0,
double dy = 0,
Duration duration = const Duration(seconds: 200),
Duration timeout = const Duration(seconds: 30),
}) async {
await rawDriver.scroll(
finder,
dx,
dy,
duration,
timeout: timeout,
);
await waitForAppToSettle(timeout: timeout);
}
@override
SerializableFinder findBy(String data, FindType type) {
switch (type) {
case FindType.key:
return find.byValueKey(data);
case FindType.pageBack:
return find.pageBack();
case FindType.text:
return find.text(data);
case FindType.tooltip:
return find.byTooltip(data);
case FindType.type:
return find.byType(data);
}
throw Exception('unknown finder');
}
@override
SerializableFinder findByAncestor(
SerializableFinder of,
SerializableFinder matching, {
bool matchRoot = false,
bool firstMatchOnly = false,
}) {
return find.ancestor(
of: of,
matching: matching,
matchRoot: matchRoot,
firstMatchOnly: firstMatchOnly,
);
}
@override
SerializableFinder findByDescendant(
SerializableFinder of,
SerializableFinder matching, {
bool matchRoot = false,
bool firstMatchOnly = false,
}) {
return find.descendant(
of: of,
matching: matching,
matchRoot: matchRoot,
firstMatchOnly: firstMatchOnly,
);
}
@override
Future<void> scrollUntilVisible(
SerializableFinder parent,
SerializableFinder item, {
double dx = 0,
double dy = 0,
Duration timeout = const Duration(seconds: 30),
}) async {
await rawDriver.scrollUntilVisible(
parent,
item,
timeout: timeout,
dxScroll: dx,
dyScroll: dy,
);
}
@override
Future<void> scrollIntoView(
SerializableFinder finder, {
Duration timeout = const Duration(seconds: 30),
}) async {
await rawDriver.scrollIntoView(
finder,
timeout: timeout,
);
}
}

View File

@ -164,7 +164,7 @@ class FlutterTestConfiguration extends TestConfiguration {
FlutterWorld world,
) async {
var flutterConfig = config as FlutterTestConfiguration;
world = world ?? FlutterWorld();
world = world ?? FlutterDriverWorld();
final driver = await createFlutterDriver(
flutterConfig.runningAppProtocolEndpointUri != null &&
@ -173,7 +173,7 @@ class FlutterTestConfiguration extends TestConfiguration {
: null,
);
world.setFlutterDriver(driver);
(world as FlutterDriverWorld).setFlutterDriver(driver);
return world;
}

View File

@ -1,23 +1,40 @@
import 'package:flutter_driver/flutter_driver.dart';
import 'package:flutter_gherkin/flutter_gherkin.dart';
import 'package:gherkin/gherkin.dart';
import 'adapters/app_driver_adapter.dart';
import 'flutter_run_process_handler.dart';
class FlutterWorld extends World {
FlutterDriver _driver;
abstract class FlutterWorld extends World {
AppDriverAdapter _adapter;
AppDriverAdapter get appDriver => _adapter;
void setAppAdapter(AppDriverAdapter appAdapter) {
_adapter = appAdapter;
}
Future<bool> restartApp({
Duration timeout = const Duration(seconds: 60),
});
}
class FlutterDriverWorld extends FlutterWorld {
FlutterRunProcessHandler _flutterRunProcessHandler;
FlutterDriver get driver => _driver;
FlutterDriver get driver => appDriver.rawDriver as FlutterDriver;
void setFlutterDriver(FlutterDriver flutterDriver) {
_driver = flutterDriver;
setAppAdapter(FlutterDriverAppDriverAdapter(flutterDriver));
}
void setFlutterProcessHandler(
FlutterRunProcessHandler flutterRunProcessHandler) {
FlutterRunProcessHandler flutterRunProcessHandler,
) {
_flutterRunProcessHandler = flutterRunProcessHandler;
}
@override
Future<bool> restartApp({
Duration timeout = const Duration(seconds: 60),
}) async {
@ -26,16 +43,19 @@ class FlutterWorld extends World {
timeout: timeout,
);
_driver = await FlutterDriver.connect(
final driver = await FlutterDriver.connect(
dartVmServiceUrl: _flutterRunProcessHandler.currentObservatoryUri,
);
setFlutterDriver(driver);
return result;
}
@override
void dispose() async {
super.dispose();
appDriver.dispose();
_flutterRunProcessHandler = null;
await _closeDriver(timeout: const Duration(seconds: 5));
}
@ -43,17 +63,13 @@ class FlutterWorld extends World {
Future<void> _closeDriver({
Duration timeout = const Duration(seconds: 60),
}) async {
try {
if (_driver != null) {
await _driver.close().catchError(
(e, st) {
// Avoid an unhandled error
return null;
},
);
}
} finally {
_driver = null;
if (driver != null) {
await driver.close().catchError(
(e, st) {
// Avoid an unhandled error
return null;
},
);
}
}
}

View File

@ -55,7 +55,7 @@ class FlutterAppRunnerHook extends Hook {
String scenario,
Iterable<Tag> tags,
) async {
if (world is FlutterWorld) {
if (world is FlutterDriverWorld) {
world.setFlutterProcessHandler(_flutterRunProcessHandler);
}
}

View File

@ -25,7 +25,7 @@ class AttachScreenshotOnFailedStepHook extends Hook {
@protected
Future<String> takeScreenshot(World world) async {
final bytes = await (world as FlutterWorld).driver.screenshot();
final bytes = await (world as FlutterWorld).appDriver.screenshot();
return base64Encode(bytes);
}

View File

@ -1,6 +1,5 @@
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:flutter_gherkin/src/flutter/flutter_world.dart';
import 'package:flutter_gherkin/src/flutter/utils/driver_utils.dart';
import 'package:flutter_driver/flutter_driver.dart';
import 'package:gherkin/gherkin.dart';
/// Opens the applications main drawer
@ -12,18 +11,29 @@ StepDefinitionGeneric GivenOpenDrawer() {
return given1<String, FlutterWorld>(
RegExp(r'I (open|close) the drawer'),
(action, context) async {
final drawerFinder = find.byType('Drawer');
final isOpen = await FlutterDriverUtils.isPresent(
context.world.driver, drawerFinder);
final drawerFinder = context.world.appDriver.findBy(
'Drawer',
FindType.type,
);
final isOpen = await context.world.appDriver.isPresent(
drawerFinder,
);
// https://github.com/flutter/flutter/issues/9002#issuecomment-293660833
if (isOpen && action == 'close') {
// Swipe to the left across the whole app to close the drawer
await context.world.driver.scroll(
drawerFinder, -300.0, 0.0, const Duration(milliseconds: 300));
await context.world.appDriver.scroll(
drawerFinder,
dx: -300.0,
dy: 0.0,
duration: const Duration(milliseconds: 300),
);
} else if (!isOpen && action == 'open') {
await FlutterDriverUtils.tap(
context.world.driver,
find.byTooltip('Open navigation menu'),
await context.world.appDriver.tap(
context.world.appDriver.findBy(
'Open navigation menu',
FindType.tooltip,
),
timeout: context.configuration?.timeout,
);
}

View File

@ -1,5 +1,5 @@
import 'package:flutter_driver/flutter_driver.dart';
import 'package:flutter_gherkin/flutter_gherkin.dart';
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:flutter_gherkin/src/flutter/flutter_world.dart';
import 'package:gherkin/gherkin.dart';
@ -17,20 +17,19 @@ StepDefinitionGeneric SiblingContainsTextStep() {
return given3<String, String, String, FlutterWorld>(
'I expect a {string} that contains the text {string} to also contain the text {string}',
(ancestorType, leadingText, valueText, context) async {
final ancestor = await find.ancestor(
of: find.text(leadingText),
matching: find.byType(ancestorType),
final ancestor = await context.world.appDriver.findByAncestor(
context.world.appDriver.findBy(leadingText, FindType.text),
context.world.appDriver.findBy(ancestorType, FindType.type),
firstMatchOnly: true,
);
final valueWidget = await find.descendant(
of: ancestor,
matching: find.text(valueText),
final valueWidget = await context.world.appDriver.findByDescendant(
ancestor,
context.world.appDriver.findBy(valueText, FindType.text),
firstMatchOnly: true,
);
final isPresent = await FlutterDriverUtils.isPresent(
context.world.driver,
final isPresent = await context.world.appDriver.isPresent(
valueWidget,
timeout: context.configuration?.timeout ?? const Duration(seconds: 20),
);

View File

@ -17,22 +17,22 @@ mixin _SwipeHelper
final offset =
direction == SwipeDirection.right ? swipeAmount : (swipeAmount * -1);
await world.driver.scroll(
await world.appDriver.scroll(
finder,
offset.toDouble(),
0,
Duration(milliseconds: 500),
dx: offset.toDouble(),
dy: 0,
duration: Duration(milliseconds: 500),
timeout: timeout,
);
} else {
final offset =
direction == SwipeDirection.up ? swipeAmount : (swipeAmount * -1);
await world.driver.scroll(
await world.appDriver.scroll(
finder,
0,
offset.toDouble(),
Duration(milliseconds: 500),
dx: 0,
dy: offset.toDouble(),
duration: Duration(milliseconds: 500),
timeout: timeout,
);
}

View File

@ -1,5 +1,5 @@
import 'package:flutter_driver/flutter_driver.dart';
import 'package:flutter_gherkin/flutter_gherkin.dart';
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:gherkin/gherkin.dart';
/// Taps a widget that contains the text within another widget.
@ -15,29 +15,27 @@ StepDefinitionGeneric TapTextWithinWidgetStep() {
(text, ancestorKey, context) async {
final timeout =
context.configuration?.timeout ?? const Duration(seconds: 20);
final finder = find.descendant(
of: find.byValueKey(ancestorKey),
matching: find.text(text),
final finder = context.world.appDriver.findByDescendant(
context.world.appDriver.findBy(ancestorKey, FindType.key),
context.world.appDriver.findBy(text, FindType.text),
firstMatchOnly: true,
);
final isPresent = await FlutterDriverUtils.isPresent(
context.world.driver,
final isPresent = await context.world.appDriver.isPresent(
finder,
timeout: timeout * .2,
);
if (!isPresent) {
await context.world.driver.scrollUntilVisible(
find.byValueKey(ancestorKey),
find.text(text),
dyScroll: -100.0,
await context.world.appDriver.scrollUntilVisible(
context.world.appDriver.findBy(ancestorKey, FindType.key),
context.world.appDriver.findBy(text, FindType.text),
dy: -100.0,
timeout: timeout * .9,
);
}
await FlutterDriverUtils.tap(
context.world.driver,
await await context.world.appDriver.tap(
finder,
timeout: timeout,
);

View File

@ -1,5 +1,5 @@
import 'package:flutter_driver/flutter_driver.dart';
import 'package:flutter_gherkin/flutter_gherkin.dart';
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:gherkin/gherkin.dart';
/// Taps a widget of type.
@ -14,9 +14,11 @@ StepDefinitionGeneric TapWidgetOfTypeStep() {
RegExp(
r'I tap the (?:button|element|label|icon|field|text|widget) of type {string}$'),
(input1, context) async {
await FlutterDriverUtils.tap(
context.world.driver,
find.byType(input1),
await context.world.appDriver.tap(
context.world.appDriver.findBy(
input1,
FindType.type,
),
);
},
);

View File

@ -1,5 +1,5 @@
import 'package:flutter_driver/flutter_driver.dart';
import 'package:flutter_gherkin/flutter_gherkin.dart';
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:gherkin/gherkin.dart';
/// Taps a widget of type within another widget.
@ -12,13 +12,12 @@ StepDefinitionGeneric TapWidgetOfTypeWithinStep() {
RegExp(
r'I tap the (?:button|element|label|icon|field|text|widget) of type {string} within the {string}$'),
(widgetType, ancestorKey, context) async {
final finder = find.descendant(
of: find.byValueKey(ancestorKey),
matching: find.byType(widgetType),
final finder = context.world.appDriver.findByDescendant(
context.world.appDriver.findBy(ancestorKey, FindType.key),
context.world.appDriver.findBy(widgetType, FindType.type),
firstMatchOnly: true,
);
await FlutterDriverUtils.tap(
context.world.driver,
await context.world.appDriver.tap(
finder,
);
},

View File

@ -1,5 +1,5 @@
import 'package:flutter_driver/flutter_driver.dart';
import 'package:flutter_gherkin/flutter_gherkin.dart';
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:gherkin/gherkin.dart';
/// Taps a widget that contains text.
@ -14,10 +14,9 @@ StepDefinitionGeneric TapWidgetWithTextStep() {
RegExp(
r'I tap the (?:button|element|label|field|text|widget) that contains the text {string}$'),
(input1, context) async {
final finder = find.text(input1);
await context.world.driver.scrollIntoView(finder);
await FlutterDriverUtils.tap(
context.world.driver,
final finder = context.world.appDriver.findBy(input1, FindType.text);
await context.world.appDriver.scrollIntoView(finder);
await context.world.appDriver.tap(
finder,
);
},

View File

@ -1,5 +1,5 @@
import 'package:flutter_driver/flutter_driver.dart';
import 'package:flutter_gherkin/flutter_gherkin.dart';
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:gherkin/gherkin.dart';
import '../parameters/existence_parameter.dart';
@ -15,16 +15,14 @@ StepDefinitionGeneric TextExistsStep() {
RegExp(r'I expect the text {string} to be {existence}$'),
(text, exists, context) async {
if (exists == Existence.present) {
final isPresent = await FlutterDriverUtils.isPresent(
context.world.driver,
find.text(text),
final isPresent = await context.world.appDriver.isPresent(
context.world.appDriver.findBy(text, FindType.text),
);
context.expect(isPresent, true);
} else {
final isAbsent = await FlutterDriverUtils.isAbsent(
context.world.driver,
find.text(text),
final isAbsent = await context.world.appDriver.isAbsent(
context.world.appDriver.findBy(text, FindType.text),
);
context.expect(isAbsent, true);
}

View File

@ -1,5 +1,5 @@
import 'package:flutter_driver/flutter_driver.dart';
import 'package:flutter_gherkin/flutter_gherkin.dart';
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:gherkin/gherkin.dart';
import '../parameters/existence_parameter.dart';
@ -15,14 +15,13 @@ StepDefinitionGeneric TextExistsWithinStep() {
RegExp(
r'I expect the text {string} to be {existence} within the {string}$'),
(text, exists, ancestorKey, context) async {
final finder = find.descendant(
of: find.byValueKey(ancestorKey),
matching: find.text(text),
final finder = context.world.appDriver.findByDescendant(
context.world.appDriver.findBy(ancestorKey, FindType.key),
context.world.appDriver.findBy(text, FindType.text),
firstMatchOnly: true,
);
final isPresent = await FlutterDriverUtils.isPresent(
context.world.driver,
final isPresent = await context.world.appDriver.isPresent(
finder,
);

View File

@ -1,6 +1,5 @@
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:flutter_gherkin/src/flutter/flutter_world.dart';
import 'package:flutter_gherkin/src/flutter/utils/driver_utils.dart';
import 'package:flutter_driver/flutter_driver.dart';
import 'package:gherkin/gherkin.dart';
/// Expects the element found with the given control key to have the given string value.
@ -18,10 +17,10 @@ StepDefinitionGeneric ThenExpectElementToHaveValue() {
RegExp(r'I expect the {string} to be {string}$'),
(key, value, context) async {
try {
final text = await FlutterDriverUtils.getText(
context.world.driver,
find.byValueKey(key),
final text = await context.world.appDriver.getText(
context.world.appDriver.findBy(key, FindType.key),
);
context.expect(text, value);
} catch (e) {
await context.reporter.message('Step error: $e', MessageLevel.error);
@ -29,4 +28,4 @@ StepDefinitionGeneric ThenExpectElementToHaveValue() {
}
},
);
}
}

View File

@ -1,6 +1,5 @@
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:flutter_gherkin/src/flutter/flutter_world.dart';
import 'package:flutter_gherkin/src/flutter/utils/driver_utils.dart';
import 'package:flutter_driver/flutter_driver.dart';
import 'package:gherkin/gherkin.dart';
/// Expects a widget with the given key to be present within n seconds
@ -14,16 +13,16 @@ import 'package:gherkin/gherkin.dart';
/// `Then I expect the button 'save' to be present within 1 second`
StepDefinitionGeneric ThenExpectWidgetToBePresent() {
return given2<String, int, FlutterWorld>(
RegExp(
r'I expect the (?:button|element|label|icon|field|text|widget|dialog|popup) {string} to be present within {int} second(s)$'),
(key, seconds, context) async {
final isPresent = await FlutterDriverUtils.isPresent(
context.world.driver,
find.byValueKey(key),
timeout: Duration(seconds: seconds),
);
context.expect(isPresent, true);
},
configuration: StepDefinitionConfiguration()
..timeout = const Duration(days: 1));
RegExp(
r'I expect the (?:button|element|label|icon|field|text|widget|dialog|popup) {string} to be present within {int} second(s)$'),
(key, seconds, context) async {
final isPresent = await context.world.appDriver.isPresent(
context.world.appDriver.findBy(key, FindType.key),
timeout: Duration(seconds: seconds),
);
context.expect(isPresent, true);
},
configuration: StepDefinitionConfiguration()
..timeout = const Duration(days: 1),
);
}

View File

@ -1,6 +1,6 @@
import 'package:flutter_gherkin/flutter_gherkin.dart';
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:gherkin/gherkin.dart';
import 'package:flutter_driver/flutter_driver.dart';
import '../parameters/existence_parameter.dart';
@ -14,17 +14,14 @@ StepDefinitionGeneric WaitUntilKeyExistsStep() {
return then2<String, Existence, FlutterWorld>(
'I wait until the {string} is {existence}',
(keyString, existence, context) async {
await FlutterDriverUtils.waitUntil(
context.world.driver,
await context.world.appDriver.waitUntil(
() {
return existence == Existence.absent
? FlutterDriverUtils.isAbsent(
context.world.driver,
find.byValueKey(keyString),
? context.world.appDriver.isAbsent(
context.world.appDriver.findBy(keyString, FindType.key),
)
: FlutterDriverUtils.isPresent(
context.world.driver,
find.byValueKey(keyString),
: context.world.appDriver.isPresent(
context.world.appDriver.findBy(keyString, FindType.key),
);
},
);

View File

@ -1,6 +1,6 @@
import 'package:flutter_gherkin/flutter_gherkin.dart';
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:gherkin/gherkin.dart';
import 'package:flutter_driver/flutter_driver.dart';
import '../parameters/existence_parameter.dart';
@ -14,17 +14,14 @@ StepDefinitionGeneric WaitUntilTypeExistsStep() {
return then2<String, Existence, FlutterWorld>(
'I wait until the (?:button|element|label|icon|field|text|widget) of type {string} is {existence}',
(ofType, existence, context) async {
await FlutterDriverUtils.waitUntil(
context.world.driver,
await context.world.appDriver.waitUntil(
() {
return existence == Existence.absent
? FlutterDriverUtils.isAbsent(
context.world.driver,
find.byType(ofType),
? context.world.appDriver.isAbsent(
context.world.appDriver.findBy(ofType, FindType.type),
)
: FlutterDriverUtils.isPresent(
context.world.driver,
find.byType(ofType),
: context.world.appDriver.isPresent(
context.world.appDriver.findBy(ofType, FindType.type),
);
},
);

View File

@ -1,6 +1,5 @@
import 'package:flutter_driver/flutter_driver.dart';
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:flutter_gherkin/src/flutter/flutter_world.dart';
import 'package:flutter_gherkin/src/flutter/utils/driver_utils.dart';
import 'package:gherkin/gherkin.dart';
/// Enters the given text into the widget with the key provided
@ -12,10 +11,9 @@ StepDefinitionGeneric WhenFillFieldStep() {
return given2<String, String, FlutterWorld>(
'I fill the {string} field with {string}',
(key, value, context) async {
final finder = find.byValueKey(key);
await context.world.driver.scrollIntoView(finder);
await FlutterDriverUtils.enterText(
context.world.driver,
final finder = context.world.appDriver.findBy(key, FindType.key);
await context.world.appDriver.scrollIntoView(finder);
await context.world.appDriver.enterText(
finder,
value,
);

View File

@ -1,6 +1,5 @@
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:flutter_gherkin/src/flutter/flutter_world.dart';
import 'package:flutter_gherkin/src/flutter/utils/driver_utils.dart';
import 'package:flutter_driver/flutter_driver.dart';
import 'package:gherkin/gherkin.dart';
/// Long presses the widget found with the given control key.
@ -22,13 +21,12 @@ StepDefinitionGeneric WhenLongPressWidget() {
RegExp(
r'I long press the {string} (?:button|element|label|icon|field|text|widget)$'),
(key, context) async {
final finder = find.byValueKey(key);
final finder = context.world.appDriver.findBy(key, FindType.key);
await context.world.driver.scrollIntoView(
await context.world.appDriver.scrollIntoView(
finder,
);
await FlutterDriverUtils.longPress(
context.world.driver,
await context.world.appDriver.longPress(
finder,
);
},
@ -41,10 +39,9 @@ StepDefinitionGeneric WhenLongPressWidgetWithoutScroll() {
RegExp(
r'I long press the {string} (?:button|element|label|icon|field|text|widget) without scrolling it into view$'),
(key, context) async {
final finder = find.byValueKey(key);
final finder = context.world.appDriver.findBy(key, FindType.key);
await FlutterDriverUtils.longPress(
context.world.driver,
await context.world.appDriver.longPress(
finder,
);
},
@ -57,13 +54,12 @@ StepDefinitionGeneric WhenLongPressWidgetForDuration() {
RegExp(
r'I long press the {string} (?:button|element|label|icon|field|text|widget) for {int} milliseconds$'),
(key, milliseconds, context) async {
final finder = find.byValueKey(key);
final finder = context.world.appDriver.findBy(key, FindType.key);
await context.world.driver.scrollIntoView(
await context.world.appDriver.scrollIntoView(
finder,
);
await FlutterDriverUtils.longPress(
context.world.driver,
await context.world.appDriver.longPress(
finder,
pressDuration: Duration(milliseconds: milliseconds),
);

View File

@ -1,6 +1,5 @@
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:flutter_gherkin/src/flutter/flutter_world.dart';
import 'package:flutter_gherkin/src/flutter/utils/driver_utils.dart';
import 'package:flutter_driver/flutter_driver.dart';
import 'package:gherkin/gherkin.dart';
/// Taps the back button widget
@ -14,9 +13,8 @@ StepDefinitionGeneric WhenTapBackButtonWidget() {
return when<FlutterWorld>(
RegExp(r'I tap the back (?:button|element|widget|icon|text)$'),
(context) async {
await FlutterDriverUtils.tap(
context.world.driver,
find.pageBack(),
await context.world.appDriver.tap(
context.world.appDriver.findBy(null, FindType.pageBack),
);
},
);

View File

@ -1,6 +1,5 @@
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
import 'package:flutter_gherkin/src/flutter/flutter_world.dart';
import 'package:flutter_gherkin/src/flutter/utils/driver_utils.dart';
import 'package:flutter_driver/flutter_driver.dart';
import 'package:gherkin/gherkin.dart';
/// Taps the widget found with the given control key.
@ -22,13 +21,13 @@ StepDefinitionGeneric WhenTapWidget() {
RegExp(
r'I tap the {string} (?:button|element|label|icon|field|text|widget)$'),
(key, context) async {
final finder = find.byValueKey(key);
final finder =
context.world.appDriver.findByDescendant(key, FindType.key);
await context.world.driver.scrollIntoView(
await context.world.appDriver.scrollIntoView(
finder,
);
await FlutterDriverUtils.tap(
context.world.driver,
await context.world.appDriver.tap(
finder,
);
},
@ -40,10 +39,10 @@ StepDefinitionGeneric WhenTapWidgetWithoutScroll() {
RegExp(
r'I tap the {string} (?:button|element|label|icon|field|text|widget) without scrolling it into view$'),
(key, context) async {
final finder = find.byValueKey(key);
final finder =
context.world.appDriver.findByDescendant(key, FindType.key);
await FlutterDriverUtils.tap(
context.world.driver,
await context.world.appDriver.tap(
finder,
);
},

View File

@ -307,7 +307,7 @@ packages:
name: shelf_static
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.8"
version: "0.2.9+1"
shelf_web_socket:
dependency: transitive
description: