feat(utils): added well know step and driver helper method to long press a widget

This commit is contained in:
Jon Samwell 2020-08-11 10:20:31 +10:00
parent 26dc2e4463
commit cc1196b2e2
12 changed files with 172 additions and 62 deletions

View File

@ -1,3 +1,12 @@
## [1.1.8+7] - 11/08/2020
- Added well know steps and a driver helper method to long press a widget
```
When I long press "controlKey" button
When I long press "controlKey" icon for 1500 milliseconds
```
## [1.1.8+6] - 05/08/2020
- Upgraded to latest Gherkin library version which fixes issues with non-alpha-numeric characters in multiline strings and comments https://github.com/jonsamwell/dart_gherkin/issues/14 https://github.com/jonsamwell/dart_gherkin/issues/15 https://github.com/jonsamwell/dart_gherkin/issues/16

View File

@ -926,16 +926,19 @@ For convenience the library defines a number of pre-defined steps so you can get
| I restart the app | Restarts the app under test | `Then I restart the app` |
| I tap the back button | Taps the page default back button widget | `Then I tap the back button` |
| I expect a {string} that contains the text {string} to also contain the text {string} | Discovers a sibling based on its parent widget type and asserts that the both text string exist within the parent. | `Then I expect a "Row" that contains the text "X" to also contain the text "Y"` |
| I swipe [down\|left\|right\|up] by {int} pixels on the {string} | Swipes in a cardinal direction on a widget discovered by its key. | `Then I swipe up by 800 pixels on the "login_screen"`, `Then I swipe left by 200 pixels on the "dismissible_list_item"` |
| I swipe [down\|left\|right\|up] by {int} pixels on the {string} | Swipes in a cardinal direction on a widget discovered by its key. | `Then I swipe up by 800 pixels on the "login_screen"` , `Then I swipe left by 200 pixels on the "dismissible_list_item"` |
| I swipe [down\|left\|right\|up] by {int} pixels on the on the [button\|element\|label\|field\|text\|widget\|dialog\|popup] that contains the text {string} | Swipes in a cardinal direction on a widget discovered by its test. | `Then I swipe left by 400 pixels on the widget that contains the text "Dismiss Me"` |
| I tap the [button\|element\|label\|field\|text\|widget] that contains the text {string} within the {string} | Taps a widget that contains the text within another widget. If the text is not visible, the ancestor will be scrolled. | `Then I tap the label that contains the text "Logout" within the "user_settings_list"` |
| I tap the [button\|element\|label\|icon\|field\|text\|widget] of type {string} | Taps a widget of type. | `Then I tap the element of type "MaterialButton"`, `Then I tap the label of type "ListTile"`, `Then I tap the field of type "TextField"` |
| I tap the [button\|element\|label\|icon\|field\|text\|widget] of type {string} | Taps a widget of type. | `Then I tap the element of type "MaterialButton"` , `Then I tap the label of type "ListTile"` , `Then I tap the field of type "TextField"` |
| I tap the [button\|element\|label\|icon\|field\|text\|widget] of type {string} within the {string} | Taps a widget of type within another widget. | `Then I tap the element of type "MaterialButton" within the "user_settings_list"` |
| I tap the [button\|element\|label\|icon\|field\|text\|widget] that contains the text {string} | Taps a widget that contains text. | `Then I tap the label that contains the text "Logout"`, `Then I tap the button that contains the text "Sign up"`, `Then I tap the widget that contains the text "My User Profile"` |
| I expect the text {string} to be [present\|absent] | Asserts the existence of text on the screen. | `Then I expect the text "Logout" to be present`, `But I expect the text "Signup" to be absent` |
| I expect the text {string} to be [present\|absent] within the {string} | Asserts the existence of text within a parent widget. | `Then I expect the text "Logout" to be present within the "user_settings_list"`, `But I expect the text "Signup" to be absent within the "login_screen"` |
| I wait until the {string} is [present\absent] | Delays until a widget is present or absent. | `Then I wait until the "login_loading_indicator" is absent`, `And I wait until the "login_screen" is present` |
| I wait until the [button\|element\|label\|icon\|field\|text\|widget] of type {string} is [present\absent] | Waits until a widget type is present or absent. | `Then I wait until the element of type "ProgressIndicator" is absent`, `And I wait until the button of type "MaterialButton" is present` |
| I tap the [button\|element\|label\|icon\|field\|text\|widget] that contains the text {string} | Taps a widget that contains text. | `Then I tap the label that contains the text "Logout"` , `Then I tap the button that contains the text "Sign up"` , `Then I tap the widget that contains the text "My User Profile"` |
| I expect the text {string} to be [present\|absent] | Asserts the existence of text on the screen. | `Then I expect the text "Logout" to be present` , `But I expect the text "Signup" to be absent` |
| I expect the text {string} to be [present\|absent] within the {string} | Asserts the existence of text within a parent widget. | `Then I expect the text "Logout" to be present within the "user_settings_list"` , `But I expect the text "Signup" to be absent within the "login_screen"` |
| I wait until the {string} is [present\absent] | Delays until a widget is present or absent. | `Then I wait until the "login_loading_indicator" is absent` , `And I wait until the "login_screen" is present` |
| I wait until the [button\|element\|label\|icon\|field\|text\|widget] of type {string} is [present\absent] | Waits until a widget type is present or absent. | `Then I wait until the element of type "ProgressIndicator" is absent` , `And I wait until the button of type "MaterialButton" is present` |
| I long press the {string} [button\|element\|label\|icon\|field\|text\|widget] | Scrolls into view and long presses the widget for 500 milliseconds. | `When I long press "controlKey" button` |
| I long press the {string} [button\|element\|label\|icon\|field\|text\|widget] without scrolling it into view | Long presses the widget for 500 milliseconds. | `When I long press "controlKey" button without scrolling it into view` |
| I long press the {string} [button\|element\|label\|icon\|field\|text\|widget] for {int} milliseconds | Scrolls into view and long presses the widget for the give number of milliseconds. | `When I long press "controlKey" button without scrolling it into view for 1500 milliseconds` |
#### Flutter Driver Utilities

View File

@ -9,3 +9,7 @@ export "OTHER_LDFLAGS=$(inherited) -framework Flutter"
export "FLUTTER_FRAMEWORK_DIR=C:\Google\flutter\bin\cache\artifacts\engine\ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=false"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.packages"

View File

@ -23,6 +23,7 @@ class MyHomePage extends StatefulWidget {
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
bool hasLongPressedText = false;
void _incrementCounter() {
setState(() {
@ -91,7 +92,24 @@ class _MyHomePageState extends State<MyHomePage> {
MaterialPageRoute(builder: (context) => PageTwo()),
);
},
)
),
GestureDetector(
onLongPress: () {
setState(() {
hasLongPressedText = true;
});
},
child: Container(
color:
hasLongPressedText ? Colors.blueGrey : Colors.transparent,
child: Text(
hasLongPressedText
? 'Text has been long pressed!'
: 'Text that has not been long pressed',
key: const Key('longPressText'),
),
),
),
],
),
),

View File

@ -0,0 +1,6 @@
Feature: Interaction
Scenario: Widget can be long pressed
Given I expect the "longPressText" to be "Text that has not been long pressed"
When I long press the "longPressText" text
Then I expect the "longPressText" to be "Text has been long pressed!"

File diff suppressed because one or more lines are too long

View File

@ -27,6 +27,7 @@ import 'package:gherkin/gherkin.dart';
import 'package:glob/glob.dart';
import 'steps/then_expect_widget_to_be_present_step.dart';
import 'steps/when_long_press_widget_step.dart';
class FlutterTestConfiguration extends TestConfiguration {
String _observatoryDebuggerUri;
@ -194,6 +195,9 @@ class FlutterTestConfiguration extends TestConfiguration {
WhenTapBackButtonWidget(),
WhenTapWidget(),
WhenTapWidgetWithoutScroll(),
WhenLongPressWidget(),
WhenLongPressWidgetWithoutScroll(),
WhenLongPressWidgetForDuration(),
GivenOpenDrawer(),
WhenPauseStep(),
WhenFillFieldStep(),

View File

@ -0,0 +1,70 @@
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.
///
/// Parameters:
/// 1 - {string} the control key
///
/// Examples:
///
/// `When I long press "controlKey" button`
/// `When I long press "controlKey" element`
/// `When I long press "controlKey" label`
/// `When I long press "controlKey" icon`
/// `When I long press "controlKey" field`
/// `When I long press "controlKey" text`
/// `When I long press "controlKey" widget`
StepDefinitionGeneric WhenLongPressWidget() {
return when1<String, FlutterWorld>(
RegExp(
r'I long press the {string} (?:button|element|label|icon|field|text|widget)$'),
(key, context) async {
final finder = find.byValueKey(key);
await context.world.driver.scrollIntoView(
finder,
);
await FlutterDriverUtils.longPress(
context.world.driver,
finder,
);
},
);
}
StepDefinitionGeneric WhenLongPressWidgetWithoutScroll() {
return when1<String, FlutterWorld>(
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);
await FlutterDriverUtils.tap(
context.world.driver,
finder,
);
},
);
}
StepDefinitionGeneric WhenLongPressWidgetForDuration() {
return when2<String, int, FlutterWorld>(
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);
await context.world.driver.scrollIntoView(
finder,
);
await FlutterDriverUtils.longPress(
context.world.driver,
finder,
pressDuration: Duration(milliseconds: milliseconds),
);
},
);
}

View File

@ -70,6 +70,16 @@ class FlutterDriverUtils {
await FlutterDriverUtils.waitForFlutter(driver, timeout: timeout);
}
static Future<void> longPress(
FlutterDriver driver,
SerializableFinder finder, {
Duration pressDuration = const Duration(milliseconds: 500),
Duration timeout = const Duration(seconds: 30),
}) async {
await driver.scroll(finder, 0, 0, pressDuration, timeout: timeout);
await FlutterDriverUtils.waitForFlutter(driver, timeout: timeout);
}
/// Waits until the [condition] returns true
/// Will raise a complete with a [TimeoutException] if the
/// condition does not return true with the timeout period.

View File

@ -35,7 +35,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.1"
version: "2.4.2"
boolean_selector:
dependency: transitive
description:
@ -43,6 +43,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
charcode:
dependency: transitive
description:
@ -57,13 +64,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.14.12"
version: "1.14.13"
convert:
dependency: transitive
description:
@ -77,14 +91,14 @@ packages:
name: coverage
url: "https://pub.dartlang.org"
source: hosted
version: "0.13.11"
version: "0.14.0"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.4"
version: "2.1.5"
csslib:
dependency: transitive
description:
@ -92,13 +106,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.16.2"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.0"
version: "5.2.1"
flutter:
dependency: "direct main"
description: flutter
@ -161,13 +182,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.4"
image:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.12"
intl:
dependency: transitive
description:
@ -195,7 +209,7 @@ packages:
name: json_rpc_2
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.2.1"
logging:
dependency: transitive
description:
@ -209,7 +223,7 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.6"
version: "0.12.8"
meta:
dependency: "direct main"
description:
@ -224,13 +238,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.6+3"
multi_server_socket:
dependency: transitive
description:
name: multi_server_socket
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
node_interop:
dependency: transitive
description:
@ -265,7 +272,7 @@ packages:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.4"
version: "1.7.0"
pedantic:
dependency: "direct dev"
description:
@ -273,13 +280,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.0"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.0"
platform:
dependency: transitive
description:
@ -300,7 +300,7 @@ packages:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.12"
version: "3.0.13"
pub_semver:
dependency: transitive
description:
@ -308,13 +308,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.4"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
shelf:
dependency: transitive
description:
@ -375,7 +368,7 @@ packages:
name: stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.3"
version: "1.9.5"
stream_channel:
dependency: transitive
description:
@ -410,28 +403,28 @@ packages:
name: test
url: "https://pub.dartlang.org"
source: hosted
version: "1.14.4"
version: "1.15.2"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.15"
version: "0.2.17"
test_core:
dependency: transitive
description:
name: test_core
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.4"
version: "0.3.10"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.6"
version: "1.2.0"
vector_math:
dependency: transitive
description:
@ -481,13 +474,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.3"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "3.6.1"
yaml:
dependency: transitive
description:
@ -496,5 +482,5 @@ packages:
source: hosted
version: "2.2.1"
sdks:
dart: ">=2.7.0 <3.0.0"
dart: ">=2.9.0-14.0.dev <3.0.0"
flutter: ">=1.13.0"

View File

@ -1,6 +1,6 @@
name: flutter_gherkin
description: A Gherkin / Cucumber parser and test runner for Dart and Flutter
version: 1.1.8+6
version: 1.1.8+7
homepage: https://github.com/jonsamwell/flutter_gherkin
environment:

View File

@ -23,7 +23,7 @@ void main() {
config.prepare();
expect(config.stepDefinitions, isNotNull);
expect(config.stepDefinitions.length, 20);
expect(config.stepDefinitions.length, 23);
expect(config.customStepParameterDefinitions, isNotNull);
expect(config.customStepParameterDefinitions.length, 2);
});
@ -36,7 +36,7 @@ void main() {
config.prepare();
expect(config.stepDefinitions, isNotNull);
expect(config.stepDefinitions.length, 21);
expect(config.stepDefinitions.length, 24);
expect(config.stepDefinitions.elementAt(0),
(x) => x is MockStepDefinition);
expect(config.customStepParameterDefinitions, isNotNull);