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:
parent
1c6a9cba2a
commit
7ba52462c5
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"cSpell.words": [
|
||||
"Serializable"
|
||||
]
|
||||
}
|
|
@ -610,6 +610,8 @@ StepDefinitionGeneric TapButtonNTimesStep() {
|
|||
await FlutterDriverUtils.tap(context.world.driver, locator);
|
||||
}
|
||||
},
|
||||
configuration: StepDefinitionConfiguration()
|
||||
..timeout = const Duration(seconds: 10),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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() {}
|
||||
}
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
},
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
||||
|
|
|
@ -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() {
|
|||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
},
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue