feat(config): re-worked configuration so it can stay mostly immutable
- Fix #195: Adding missing export for `wait_until_key_exists_step.dart` - Fix #226: Allow compatibility with dev and master flutter branches - Feat #218: Allow retry steps in case of intermittent failure by setting the configuration properties `stepMaxRetries` & `retryDelay` - Fix #210 & #191: Ability to take screenshots on web - Fix #198: Allow the use of implicit pumpAndSettle methods in the app driver to be turned off using the configuration property `waitImplicitlyAfterAction`
This commit is contained in:
parent
5c15f0c2c0
commit
0961916daa
|
@ -1,2 +1,2 @@
|
||||||
# This is a generated file; do not edit or check into version control.
|
# This is a generated file; do not edit or check into version control.
|
||||||
integration_test=C:\\Google\\flutter\\packages\\integration_test\\
|
integration_test=C:\\Development\\flutter\\packages\\integration_test\\
|
||||||
|
|
|
@ -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-11-24 07:12:59.207785","version":"2.5.3"}
|
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"integration_test","path":"C:\\\\Development\\\\flutter\\\\packages\\\\integration_test\\\\","native_build":true,"dependencies":[]}],"android":[{"name":"integration_test","path":"C:\\\\Development\\\\flutter\\\\packages\\\\integration_test\\\\","native_build":true,"dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"integration_test","dependencies":[]}],"date_created":"2022-06-17 15:37:47.695519","version":"3.0.2"}
|
|
@ -1,13 +1,23 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.dart_tool/
|
|
||||||
|
|
||||||
.packages
|
|
||||||
.pub/
|
|
||||||
|
|
||||||
build/
|
|
||||||
ios/.generated/
|
ios/.generated/
|
||||||
ios/Flutter/Generated.xcconfig
|
ios/Flutter/Generated.xcconfig
|
||||||
ios/Runner/GeneratedPluginRegistrant.*
|
ios/Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
**/generated_plugin_registrant.dart
|
||||||
|
.packages
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
build/
|
||||||
|
flutter_*.png
|
||||||
|
linked_*.ds
|
||||||
|
unlinked.ds
|
||||||
|
unlinked_spec.ds
|
|
@ -1,3 +1,12 @@
|
||||||
|
## [3.0.0] - 17/06/2022
|
||||||
|
|
||||||
|
- Fix #195: Adding missing export for `wait_until_key_exists_step.dart`
|
||||||
|
- Fix #226: Allow compatibility with dev and master flutter branches
|
||||||
|
- Feat #218: Allow retry steps in case of intermittent failure by setting the configuration properties `stepMaxRetries` & `retryDelay`
|
||||||
|
- Fix #210 & #191: Ability to take screenshots on web
|
||||||
|
- Fix #198: Allow the use of implicit pumpAndSettle methods in the app driver to be turned off using the configuration property `waitImplicitlyAfterAction`
|
||||||
|
|
||||||
|
|
||||||
## [3.0.0-rc.9] - 18/11/2021
|
## [3.0.0-rc.9] - 18/11/2021
|
||||||
|
|
||||||
- Fix: #172: Fix for the `StdoutReporter` when running against the web
|
- Fix: #172: Fix for the `StdoutReporter` when running against the web
|
||||||
|
|
|
@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
|
||||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
compileSdkVersion 31
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main.java.srcDirs += 'src/main/kotlin'
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.3.50'
|
ext.kotlin_version = '1.6.10'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
classpath 'com.android.tools.build:gradle:7.2.0'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,5 @@ distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
|
||||||
|
org.gradle.jvmargs=-Xmx4608m
|
||||||
|
|
|
@ -1,20 +1,41 @@
|
||||||
# Generated by pub
|
# Generated by pub
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
packages:
|
packages:
|
||||||
|
_fe_analyzer_shared:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: _fe_analyzer_shared
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "31.0.0"
|
||||||
|
analyzer:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: analyzer
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.8.0"
|
||||||
archive:
|
archive:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: archive
|
name: archive
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.11"
|
||||||
|
args:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: args
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.1"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: async
|
name: async
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.1"
|
version: "2.8.2"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -22,20 +43,34 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.0"
|
||||||
|
build:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.0"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: characters
|
name: characters
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.2.0"
|
||||||
charcode:
|
charcode:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: charcode
|
name: charcode
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.3.1"
|
||||||
|
cli_util:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cli_util
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.5"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -49,7 +84,14 @@ packages:
|
||||||
name: collection
|
name: collection
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.15.0"
|
version: "1.16.0"
|
||||||
|
convert:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: convert
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.2"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -57,20 +99,27 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.1"
|
version: "3.0.1"
|
||||||
|
dart_style:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dart_style
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: fake_async
|
name: fake_async
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.3.0"
|
||||||
file:
|
file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: file
|
name: file
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.0"
|
version: "6.1.2"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -87,7 +136,7 @@ packages:
|
||||||
path: ".."
|
path: ".."
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "2.0.0"
|
version: "3.0.0"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -104,59 +153,101 @@ packages:
|
||||||
name: gherkin
|
name: gherkin
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "3.0.0+1"
|
||||||
|
glob:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: glob
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
integration_test:
|
integration_test:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
logging:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: logging
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.2"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.10"
|
version: "0.12.11"
|
||||||
|
material_color_utilities:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: material_color_utilities
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.4"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.7.0"
|
||||||
|
package_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_config
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.0"
|
version: "1.8.1"
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: platform
|
name: platform
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.1.0"
|
||||||
process:
|
process:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: process
|
name: process
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.1"
|
version: "4.2.4"
|
||||||
|
pub_semver:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pub_semver
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.99"
|
version: "0.0.99"
|
||||||
|
source_gen:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_gen
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.2"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.1"
|
version: "1.8.2"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -198,7 +289,7 @@ packages:
|
||||||
name: test_api
|
name: test_api
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.0"
|
version: "0.4.9"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -206,20 +297,34 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.3.0"
|
||||||
|
uuid:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: uuid
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.6"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_math
|
name: vector_math
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.2"
|
||||||
vm_service:
|
vm_service:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.2.0"
|
version: "8.2.2"
|
||||||
|
watcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: watcher
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
webdriver:
|
webdriver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -227,6 +332,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.0"
|
||||||
|
yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: yaml
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.12.3 <3.0.0"
|
dart: ">=2.17.0 <3.0.0"
|
||||||
flutter: ">=2.2.0"
|
flutter: ">=2.2.0"
|
||||||
|
|
|
@ -6,7 +6,8 @@ publish_to: 'none'
|
||||||
version: 1.0.0+1
|
version: 1.0.0+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
sdk: '>=2.17.0 <3.0.0'
|
||||||
|
flutter: ">=2.2.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
|
|
|
@ -3,22 +3,26 @@ import 'package:flutter_gherkin/flutter_gherkin_with_driver.dart';
|
||||||
import 'package:gherkin/gherkin.dart';
|
import 'package:gherkin/gherkin.dart';
|
||||||
|
|
||||||
Future<void> main() {
|
Future<void> main() {
|
||||||
final config = FlutterDriverTestConfiguration.DEFAULT(
|
final config = FlutterDriverTestConfiguration(
|
||||||
Iterable.empty(),
|
features: [RegExp('features/**.feature')],
|
||||||
featurePath: 'features/**.feature',
|
|
||||||
targetAppPath: 'test_driver/app.dart',
|
targetAppPath: 'test_driver/app.dart',
|
||||||
)
|
targetAppWorkingDirectory: '../',
|
||||||
..restartAppBetweenScenarios = true
|
buildFlavor:
|
||||||
..targetAppWorkingDirectory = '../'
|
"staging", // uncomment when using build flavor and check android/ios flavor setup see android file android\app\build.gradle
|
||||||
..targetAppPath = 'test_driver/app.dart';
|
targetDeviceId:
|
||||||
// ..buildFlavor = "staging" // uncomment when using build flavor and check android/ios flavor setup see android file android\app\build.gradle
|
"all", // uncomment to run tests on all connected devices or set specific device target id
|
||||||
// ..targetDeviceId = "all" // uncomment to run tests on all connected devices or set specific device target id
|
tagExpression:
|
||||||
// ..tagExpression = '@smoke and not @ignore' // uncomment to see an example of running scenarios based on tag expressions
|
'@smoke and not @ignore', // uncomment to see an example of running scenarios based on tag expressions
|
||||||
// ..logFlutterProcessOutput = true // uncomment to see command invoked to start the flutter test app
|
logFlutterProcessOutput:
|
||||||
// ..verboseFlutterProcessLogs = true // uncomment to see the verbose output from the Flutter process
|
true, // uncomment to see command invoked to start the flutter test app
|
||||||
// ..flutterBuildTimeout = Duration(minutes: 3) // uncomment to change the default period that flutter is expected to build and start the app within
|
verboseFlutterProcessLogs:
|
||||||
// ..runningAppProtocolEndpointUri =
|
true, // uncomment to see the verbose output from the Flutter process
|
||||||
// 'http://127.0.0.1:51540/bkegoer6eH8=/' // already running app observatory / service protocol uri (with enableFlutterDriverExtension method invoked) to test against if you use this set `restartAppBetweenScenarios` to false
|
flutterBuildTimeout: Duration(
|
||||||
|
minutes:
|
||||||
|
3), // uncomment to change the default period that flutter is expected to build and start the app within
|
||||||
|
runningAppProtocolEndpointUri:
|
||||||
|
'http://127.0.0.1:51540/bkegoer6eH8=/', // already running app observatory / service protocol uri (with enableFlutterDriverExtension method invoked) to test against if you use this set `restartAppBetweenScenarios` to false
|
||||||
|
);
|
||||||
|
|
||||||
return GherkinRunner().execute(config);
|
return GherkinRunner().execute(config);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
|
||||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
compileSdkVersion 31
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main.java.srcDirs += 'src/main/kotlin'
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
|
@ -39,8 +39,8 @@ android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId "com.example.example_with_integration_test"
|
applicationId "com.example.example_with_integration_test"
|
||||||
minSdkVersion 16
|
minSdkVersion 23
|
||||||
targetSdkVersion 29
|
targetSdkVersion 31
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,12 @@
|
||||||
additional functionality it is fine to subclass or reimplement
|
additional functionality it is fine to subclass or reimplement
|
||||||
FlutterApplication and put your custom class here. -->
|
FlutterApplication and put your custom class here. -->
|
||||||
<application
|
<application
|
||||||
android:name="io.flutter.app.FlutterApplication"
|
android:name="${applicationName}"
|
||||||
android:label="example_with_integration_test"
|
android:label="example_with_integration_test"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.3.50'
|
ext.kotlin_version = '1.6.10'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
classpath 'com.android.tools.build:gradle:7.2.0'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,5 @@ distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
|
||||||
|
org.gradle.jvmargs=-Xmx4608m
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
@tag
|
@tag
|
||||||
Feature: Creating todos
|
Feature: Creating todos
|
||||||
|
|
||||||
@tag1 @tag_two
|
|
||||||
Scenario: User can create a new todo item
|
|
||||||
Given I fill the "todo" field with "Buy carrots"
|
|
||||||
When I tap the 'add' button
|
|
||||||
Then I expect the todo list
|
|
||||||
| Todo |
|
|
||||||
| Buy carrots |
|
|
||||||
|
|
||||||
@debug
|
@debug
|
||||||
Scenario: User can create multiple new todo items
|
Scenario: User can create multiple new todo items
|
||||||
Given I fill the "todo" field with "Buy carrots"
|
Given I fill the "todo" field with "Buy carrots"
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
@tag
|
@tag
|
||||||
Feature: Swiping
|
Feature: Swiping
|
||||||
|
|
||||||
@debug
|
|
||||||
Scenario: User can swipe cards left and right
|
Scenario: User can swipe cards left and right
|
||||||
Given I swipe right by 250 pixels on the "scrollable cards"`
|
Given I swipe right by 250 pixels on the "scrollable cards"`
|
||||||
Then Then I expect the text "Page 2" to be present
|
Then Then I expect the text "Page 2" to be present
|
||||||
|
|
|
@ -12,34 +12,30 @@ import 'steps/when_await_animation.dart';
|
||||||
import 'steps/when_step_has_timeout.dart';
|
import 'steps/when_step_has_timeout.dart';
|
||||||
import 'world/custom_world.dart';
|
import 'world/custom_world.dart';
|
||||||
|
|
||||||
FlutterTestConfiguration gherkinTestConfiguration =
|
FlutterTestConfiguration gherkinTestConfiguration = FlutterTestConfiguration(
|
||||||
FlutterTestConfiguration.DEFAULT(
|
tagExpression: '@debug',
|
||||||
[
|
stepDefinitions: [
|
||||||
thenIExpectTheTodos,
|
thenIExpectTheTodos,
|
||||||
whenAnAnimationIsAwaited,
|
whenAnAnimationIsAwaited,
|
||||||
whenStepHasTimeout,
|
whenStepHasTimeout,
|
||||||
givenTheData
|
givenTheData
|
||||||
],
|
],
|
||||||
)
|
hooks: [
|
||||||
// ..tagExpression = '@debug'
|
ResetAppHook(),
|
||||||
..hooks = [
|
],
|
||||||
ResetAppHook(),
|
reporters: [
|
||||||
]
|
StdoutReporter(MessageLevel.error)
|
||||||
..reporters = [
|
..setWriteLineFn(print)
|
||||||
StdoutReporter(MessageLevel.error)
|
..setWriteFn(print),
|
||||||
..setWriteLineFn(print)
|
ProgressReporter()
|
||||||
..setWriteFn(print),
|
..setWriteLineFn(print)
|
||||||
ProgressReporter()
|
..setWriteFn(print),
|
||||||
..setWriteLineFn(print)
|
TestRunSummaryReporter()
|
||||||
..setWriteFn(print),
|
..setWriteLineFn(print)
|
||||||
TestRunSummaryReporter()
|
..setWriteFn(print),
|
||||||
..setWriteLineFn(print)
|
],
|
||||||
..setWriteFn(print),
|
createWorld: (config) => Future.value(CustomWorld()),
|
||||||
JsonReporter(
|
);
|
||||||
writeReport: (_, __) => Future<void>.value(),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
..createWorld = (config) => Future.value(CustomWorld());
|
|
||||||
|
|
||||||
Future<void> Function(World) appInitializationFn = (World world) async {
|
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
|
||||||
|
|
|
@ -21,209 +21,152 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
|
|
||||||
void testFeature0() {
|
void testFeature0() {
|
||||||
runFeature(
|
runFeature(
|
||||||
'Checking data:',
|
'Swiping:',
|
||||||
<String>['@tag'],
|
<String>['@tag'],
|
||||||
() {
|
() {
|
||||||
runScenario(
|
runScenario(
|
||||||
'User can have data',
|
name: 'User can swipe cards left and right',
|
||||||
<String>['@tag', '@tag1'],
|
path:
|
||||||
(TestDependencies dependencies) async {
|
'C:\Development\github\flutter_gherkin\example_with_integration_test\.\integration_test\features\swiping.feature',
|
||||||
await runStep(
|
tags: <String>['@tag'],
|
||||||
'Given I have item with data',
|
steps: [
|
||||||
<String>[
|
(TestDependencies dependencies, bool hasToSkip) async {
|
||||||
"""{
|
return await runStep(
|
||||||
"glossary": {
|
'Given I swipe right by 250 pixels on the "scrollable cards"`',
|
||||||
"title": "example glossary",
|
<String>[],
|
||||||
"GlossDiv": {
|
null,
|
||||||
"title": "S",
|
dependencies,
|
||||||
"GlossList": {
|
hasToSkip,
|
||||||
"GlossEntry": {
|
);
|
||||||
"ID": "SGML",
|
},
|
||||||
"SortAs": "SGML",
|
(TestDependencies dependencies, bool hasToSkip) async {
|
||||||
"GlossTerm": "Standard Generalized Markup Language",
|
return await runStep(
|
||||||
"Acronym": "SGML",
|
'Then Then I expect the text "Page 2" to be present',
|
||||||
"Abbrev": "ISO 8879:1986",
|
<String>[],
|
||||||
"GlossDef": {
|
null,
|
||||||
"para": "A meta-markup language, used to create markup languages such as DocBook.",
|
dependencies,
|
||||||
"GlossSeeAlso": [
|
hasToSkip,
|
||||||
"GML",
|
);
|
||||||
"XML"
|
},
|
||||||
]
|
(TestDependencies dependencies, bool hasToSkip) async {
|
||||||
},
|
return await runStep(
|
||||||
"GlossSee": "markup"
|
'Given I swipe left by 250 pixels on the "scrollable cards"`',
|
||||||
}
|
<String>[],
|
||||||
}
|
null,
|
||||||
}
|
dependencies,
|
||||||
}
|
hasToSkip,
|
||||||
}"""
|
);
|
||||||
],
|
},
|
||||||
null,
|
(TestDependencies dependencies, bool hasToSkip) async {
|
||||||
dependencies,
|
return await runStep(
|
||||||
);
|
'Then Then I expect the text "Page 1" to be present',
|
||||||
},
|
<String>[],
|
||||||
|
null,
|
||||||
|
dependencies,
|
||||||
|
hasToSkip,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
],
|
||||||
onBefore: () async => onBeforeRunFeature(
|
onBefore: () async => onBeforeRunFeature(
|
||||||
'Checking data',
|
'Swiping',
|
||||||
<String>['@tag'],
|
<String>['@tag'],
|
||||||
),
|
),
|
||||||
onAfter: () async => onAfterRunFeature(
|
onAfter: () async => onAfterRunFeature('Swiping',
|
||||||
'Checking data',
|
'C:\Development\github\flutter_gherkin\example_with_integration_test\.\integration_test\features\swiping.feature'),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testFeature1() {
|
void testFeature1() {
|
||||||
runFeature(
|
|
||||||
'Swiping:',
|
|
||||||
<String>['@tag'],
|
|
||||||
() {
|
|
||||||
runScenario(
|
|
||||||
'User can swipe cards left and right',
|
|
||||||
<String>['@tag', '@debug'],
|
|
||||||
(TestDependencies dependencies) async {
|
|
||||||
await runStep(
|
|
||||||
'Given I swipe right by 250 pixels on the "scrollable cards"`',
|
|
||||||
<String>[],
|
|
||||||
null,
|
|
||||||
dependencies,
|
|
||||||
);
|
|
||||||
|
|
||||||
await runStep(
|
|
||||||
'Then Then I expect the text "Page 2" to be present',
|
|
||||||
<String>[],
|
|
||||||
null,
|
|
||||||
dependencies,
|
|
||||||
);
|
|
||||||
|
|
||||||
await runStep(
|
|
||||||
'Given I swipe left by 250 pixels on the "scrollable cards"`',
|
|
||||||
<String>[],
|
|
||||||
null,
|
|
||||||
dependencies,
|
|
||||||
);
|
|
||||||
|
|
||||||
await runStep(
|
|
||||||
'Then Then I expect the text "Page 1" to be present',
|
|
||||||
<String>[],
|
|
||||||
null,
|
|
||||||
dependencies,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onBefore: () async => onBeforeRunFeature(
|
|
||||||
'Swiping',
|
|
||||||
<String>['@tag'],
|
|
||||||
),
|
|
||||||
onAfter: () async => onAfterRunFeature(
|
|
||||||
'Swiping',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testFeature2() {
|
|
||||||
runFeature(
|
runFeature(
|
||||||
'Creating todos:',
|
'Creating todos:',
|
||||||
<String>['@tag'],
|
<String>['@tag'],
|
||||||
() {
|
() {
|
||||||
runScenario(
|
runScenario(
|
||||||
'User can create a new todo item',
|
name: 'User can create multiple new todo items',
|
||||||
<String>['@tag', '@tag1', '@tag_two'],
|
path:
|
||||||
(TestDependencies dependencies) async {
|
'C:\Development\github\flutter_gherkin\example_with_integration_test\.\integration_test\features\create.feature',
|
||||||
await runStep(
|
tags: <String>['@tag', '@debug'],
|
||||||
'Given I fill the "todo" field with "Buy carrots"',
|
steps: [
|
||||||
<String>[],
|
(TestDependencies dependencies, bool hasToSkip) async {
|
||||||
null,
|
return await runStep(
|
||||||
dependencies,
|
'Given I fill the "todo" field with "Buy carrots"',
|
||||||
);
|
<String>[],
|
||||||
|
null,
|
||||||
await runStep(
|
dependencies,
|
||||||
'When I tap the \'add\' button',
|
hasToSkip,
|
||||||
<String>[],
|
);
|
||||||
null,
|
},
|
||||||
dependencies,
|
(TestDependencies dependencies, bool hasToSkip) async {
|
||||||
);
|
return await runStep(
|
||||||
|
'When I tap the "add" button',
|
||||||
await runStep(
|
<String>[],
|
||||||
'Then I expect the todo list',
|
null,
|
||||||
<String>[],
|
dependencies,
|
||||||
GherkinTable.fromJson('[{"Todo":"Buy carrots"}]'),
|
hasToSkip,
|
||||||
dependencies,
|
);
|
||||||
);
|
},
|
||||||
},
|
(TestDependencies dependencies, bool hasToSkip) async {
|
||||||
onBefore: () async => onBeforeRunFeature(
|
return await runStep(
|
||||||
'Creating todos',
|
'And I fill the "todo" field with "Buy apples"',
|
||||||
<String>['@tag'],
|
<String>[],
|
||||||
),
|
null,
|
||||||
onAfter: null,
|
dependencies,
|
||||||
);
|
hasToSkip,
|
||||||
|
);
|
||||||
runScenario(
|
},
|
||||||
'User can create multiple new todo items',
|
(TestDependencies dependencies, bool hasToSkip) async {
|
||||||
<String>['@tag', '@debug'],
|
return await runStep(
|
||||||
(TestDependencies dependencies) async {
|
'When I tap the "add" button',
|
||||||
await runStep(
|
<String>[],
|
||||||
'Given I fill the "todo" field with "Buy carrots"',
|
null,
|
||||||
<String>[],
|
dependencies,
|
||||||
null,
|
hasToSkip,
|
||||||
dependencies,
|
);
|
||||||
);
|
},
|
||||||
|
(TestDependencies dependencies, bool hasToSkip) async {
|
||||||
await runStep(
|
return await runStep(
|
||||||
'When I tap the "add" button',
|
'And I fill the "todo" field with "Buy blueberries"',
|
||||||
<String>[],
|
<String>[],
|
||||||
null,
|
null,
|
||||||
dependencies,
|
dependencies,
|
||||||
);
|
hasToSkip,
|
||||||
|
);
|
||||||
await runStep(
|
},
|
||||||
'And I fill the "todo" field with "Buy apples"',
|
(TestDependencies dependencies, bool hasToSkip) async {
|
||||||
<String>[],
|
return await runStep(
|
||||||
null,
|
'When I tap the "add" button',
|
||||||
dependencies,
|
<String>[],
|
||||||
);
|
null,
|
||||||
|
dependencies,
|
||||||
await runStep(
|
hasToSkip,
|
||||||
'When I tap the "add" button',
|
);
|
||||||
<String>[],
|
},
|
||||||
null,
|
(TestDependencies dependencies, bool hasToSkip) async {
|
||||||
dependencies,
|
return await runStep(
|
||||||
);
|
'Then I expect the todo list',
|
||||||
|
<String>[],
|
||||||
await runStep(
|
GherkinTable.fromJson(
|
||||||
'And I fill the "todo" field with "Buy blueberries"',
|
'[{"Todo":"Buy blueberries"},{"Todo":"Buy apples"},{"Todo":"Buy carrots"}]'),
|
||||||
<String>[],
|
dependencies,
|
||||||
null,
|
hasToSkip,
|
||||||
dependencies,
|
);
|
||||||
);
|
},
|
||||||
|
(TestDependencies dependencies, bool hasToSkip) async {
|
||||||
await runStep(
|
return await runStep(
|
||||||
'When I tap the "add" button',
|
'Given I wait 5 seconds for the animation to complete',
|
||||||
<String>[],
|
<String>[],
|
||||||
null,
|
null,
|
||||||
dependencies,
|
dependencies,
|
||||||
);
|
hasToSkip,
|
||||||
|
);
|
||||||
await runStep(
|
},
|
||||||
'Then I expect the todo list',
|
(TestDependencies dependencies, bool hasToSkip) async {
|
||||||
<String>[],
|
return await runStep(
|
||||||
GherkinTable.fromJson(
|
'Given I have item with data',
|
||||||
'[{"Todo":"Buy blueberries"},{"Todo":"Buy apples"},{"Todo":"Buy carrots"}]'),
|
<String>[
|
||||||
dependencies,
|
"""{
|
||||||
);
|
|
||||||
|
|
||||||
await runStep(
|
|
||||||
'Given I wait 5 seconds for the animation to complete',
|
|
||||||
<String>[],
|
|
||||||
null,
|
|
||||||
dependencies,
|
|
||||||
);
|
|
||||||
|
|
||||||
await runStep(
|
|
||||||
'Given I have item with data',
|
|
||||||
<String>[
|
|
||||||
"""{
|
|
||||||
"glossary": {
|
"glossary": {
|
||||||
"title": "example glossary",
|
"title": "example glossary",
|
||||||
"GlossDiv": {
|
"GlossDiv": {
|
||||||
|
@ -248,15 +191,77 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}"""
|
}"""
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
dependencies,
|
dependencies,
|
||||||
);
|
hasToSkip,
|
||||||
},
|
);
|
||||||
onBefore: null,
|
}
|
||||||
onAfter: () async => onAfterRunFeature(
|
],
|
||||||
|
onBefore: () async => onBeforeRunFeature(
|
||||||
'Creating todos',
|
'Creating todos',
|
||||||
|
<String>['@tag'],
|
||||||
),
|
),
|
||||||
|
onAfter: () async => onAfterRunFeature('Creating todos',
|
||||||
|
'C:\Development\github\flutter_gherkin\example_with_integration_test\.\integration_test\features\create.feature'),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testFeature2() {
|
||||||
|
runFeature(
|
||||||
|
'Checking data:',
|
||||||
|
<String>['@tag'],
|
||||||
|
() {
|
||||||
|
runScenario(
|
||||||
|
name: 'User can have data',
|
||||||
|
path:
|
||||||
|
'C:\Development\github\flutter_gherkin\example_with_integration_test\.\integration_test\features\check.feature',
|
||||||
|
tags: <String>['@tag', '@tag1'],
|
||||||
|
steps: [
|
||||||
|
(TestDependencies dependencies, bool hasToSkip) async {
|
||||||
|
return await runStep(
|
||||||
|
'Given I have item with data',
|
||||||
|
<String>[
|
||||||
|
"""{
|
||||||
|
"glossary": {
|
||||||
|
"title": "example glossary",
|
||||||
|
"GlossDiv": {
|
||||||
|
"title": "S",
|
||||||
|
"GlossList": {
|
||||||
|
"GlossEntry": {
|
||||||
|
"ID": "SGML",
|
||||||
|
"SortAs": "SGML",
|
||||||
|
"GlossTerm": "Standard Generalized Markup Language",
|
||||||
|
"Acronym": "SGML",
|
||||||
|
"Abbrev": "ISO 8879:1986",
|
||||||
|
"GlossDef": {
|
||||||
|
"para": "A meta-markup language, used to create markup languages such as DocBook.",
|
||||||
|
"GlossSeeAlso": [
|
||||||
|
"GML",
|
||||||
|
"XML"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"GlossSee": "markup"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
],
|
||||||
|
null,
|
||||||
|
dependencies,
|
||||||
|
hasToSkip,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
],
|
||||||
|
onBefore: () async => onBeforeRunFeature(
|
||||||
|
'Checking data',
|
||||||
|
<String>['@tag'],
|
||||||
|
),
|
||||||
|
onAfter: () async => onAfterRunFeature('Checking data',
|
||||||
|
'C:\Development\github\flutter_gherkin\example_with_integration_test\.\integration_test\features\check.feature'),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:example_with_integration_test/models/todo_model.dart';
|
import 'package:example_with_integration_test/models/todo_model.dart';
|
||||||
import 'package:example_with_integration_test/widgets/view_utils_mixin.dart';
|
import 'package:example_with_integration_test/widgets/view_utils_mixin.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
|
|
||||||
class AddTodoComponent extends StatefulWidget {
|
class AddTodoComponent extends StatefulWidget {
|
||||||
|
|
|
@ -3,7 +3,6 @@ import 'package:example_with_integration_test/models/todo_model.dart';
|
||||||
import 'package:example_with_integration_test/models/todo_status_enum.dart';
|
import 'package:example_with_integration_test/models/todo_status_enum.dart';
|
||||||
import 'package:example_with_integration_test/widgets/components/add_todo_component.dart';
|
import 'package:example_with_integration_test/widgets/components/add_todo_component.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
|
|
||||||
import '../view_utils_mixin.dart';
|
import '../view_utils_mixin.dart';
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ packages:
|
||||||
name: archive
|
name: archive
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.11"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -35,7 +35,7 @@ packages:
|
||||||
name: async
|
name: async
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.8.1"
|
version: "2.8.2"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -105,7 +105,7 @@ packages:
|
||||||
name: characters
|
name: characters
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.2.0"
|
||||||
charcode:
|
charcode:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -147,7 +147,7 @@ packages:
|
||||||
name: collection
|
name: collection
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.15.0"
|
version: "1.16.0"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -175,7 +175,7 @@ packages:
|
||||||
name: fake_async
|
name: fake_async
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.3.0"
|
||||||
ffi:
|
ffi:
|
||||||
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.9"
|
version: "3.0.0"
|
||||||
flutter_simple_dependency_injection:
|
flutter_simple_dependency_injection:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -249,7 +249,7 @@ packages:
|
||||||
name: gherkin
|
name: gherkin
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.8"
|
version: "3.0.0+1"
|
||||||
glob:
|
glob:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -296,7 +296,7 @@ packages:
|
||||||
name: js
|
name: js
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.3"
|
version: "0.6.4"
|
||||||
json_annotation:
|
json_annotation:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -324,7 +324,14 @@ packages:
|
||||||
name: matcher
|
name: matcher
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.10"
|
version: "0.12.11"
|
||||||
|
material_color_utilities:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: material_color_utilities
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.4"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -352,7 +359,7 @@ packages:
|
||||||
name: path
|
name: path
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.0"
|
version: "1.8.1"
|
||||||
path_provider_linux:
|
path_provider_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -380,7 +387,7 @@ packages:
|
||||||
name: platform
|
name: platform
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.1.0"
|
||||||
plugin_platform_interface:
|
plugin_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -401,7 +408,7 @@ packages:
|
||||||
name: process
|
name: process
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.3"
|
version: "4.2.4"
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -504,7 +511,7 @@ packages:
|
||||||
name: source_span
|
name: source_span
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.1"
|
version: "1.8.2"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -553,7 +560,7 @@ packages:
|
||||||
name: test_api
|
name: test_api
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.2"
|
version: "0.4.9"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -574,21 +581,21 @@ packages:
|
||||||
name: uuid
|
name: uuid
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.5"
|
version: "3.0.6"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_math
|
name: vector_math
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.2"
|
||||||
vm_service:
|
vm_service:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.1.1"
|
version: "8.2.2"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -632,5 +639,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "3.1.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.14.0 <3.0.0"
|
dart: ">=2.17.0 <3.0.0"
|
||||||
flutter: ">=2.5.0"
|
flutter: ">=2.5.0"
|
||||||
|
|
|
@ -6,8 +6,8 @@ publish_to: 'none'
|
||||||
version: 1.0.0+1
|
version: 1.0.0+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.14.0 <3.0.0'
|
sdk: '>=2.17.0 <3.0.0'
|
||||||
flutter: ">=2.5.0"
|
flutter: ">=2.2.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
|
|
|
@ -29,6 +29,7 @@ export 'src/flutter/steps/text_exists_within_step.dart';
|
||||||
export 'src/flutter/steps/wait_until_key_exists_step.dart';
|
export 'src/flutter/steps/wait_until_key_exists_step.dart';
|
||||||
export 'src/flutter/steps/when_tap_the_back_button_step.dart';
|
export 'src/flutter/steps/when_tap_the_back_button_step.dart';
|
||||||
export 'src/flutter/steps/wait_until_type_exists_step.dart';
|
export 'src/flutter/steps/wait_until_type_exists_step.dart';
|
||||||
|
export 'src/flutter/steps/wait_until_key_exists_step.dart';
|
||||||
|
|
||||||
// Hooks
|
// Hooks
|
||||||
export 'src/flutter/hooks/attach_screenshot_on_failed_step_hook.dart';
|
export 'src/flutter/hooks/attach_screenshot_on_failed_step_hook.dart';
|
||||||
|
|
|
@ -1,16 +1,22 @@
|
||||||
import 'dart:async';
|
import 'dart:io' if (dart.library.html) 'dart:html';
|
||||||
import 'dart:ui' as ui show ImageByteFormat;
|
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'app_driver_adapter.dart';
|
import 'app_driver_adapter.dart';
|
||||||
|
|
||||||
class WidgetTesterAppDriverAdapter
|
class WidgetTesterAppDriverAdapter
|
||||||
extends AppDriverAdapter<WidgetTester, Finder, Widget> {
|
extends AppDriverAdapter<WidgetTester, Finder, Widget> {
|
||||||
WidgetTesterAppDriverAdapter(WidgetTester rawAdapter) : super(rawAdapter);
|
IntegrationTestWidgetsFlutterBinding binding;
|
||||||
|
bool waitImplicitlyAfterAction;
|
||||||
|
|
||||||
|
WidgetTesterAppDriverAdapter({
|
||||||
|
required WidgetTester rawAdapter,
|
||||||
|
required this.binding,
|
||||||
|
required this.waitImplicitlyAfterAction,
|
||||||
|
}) : super(rawAdapter);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<int> waitForAppToSettle({
|
Future<int> waitForAppToSettle({
|
||||||
|
@ -30,6 +36,21 @@ class WidgetTesterAppDriverAdapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _implicitWait({
|
||||||
|
Duration? duration = const Duration(milliseconds: 100),
|
||||||
|
Duration? timeout = const Duration(seconds: 30),
|
||||||
|
}) async {
|
||||||
|
if (waitImplicitlyAfterAction) {
|
||||||
|
try {
|
||||||
|
await nativeDriver.pumpAndSettle(
|
||||||
|
duration ?? const Duration(milliseconds: 100),
|
||||||
|
EnginePhase.sendSemanticsUpdate,
|
||||||
|
timeout ?? const Duration(seconds: 30),
|
||||||
|
);
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<T> widget<T extends Widget>(
|
Future<T> widget<T extends Widget>(
|
||||||
Finder finder, [
|
Finder finder, [
|
||||||
|
@ -47,20 +68,15 @@ class WidgetTesterAppDriverAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<int>> screenshot() {
|
Future<List<int>> screenshot() async {
|
||||||
var renderObject = nativeDriver.binding.renderViewElement?.renderObject;
|
if (!kIsWeb && Platform.isAndroid) {
|
||||||
|
await binding.convertFlutterSurfaceToImage();
|
||||||
while (renderObject != null && !renderObject.isRepaintBoundary) {
|
await binding.pump();
|
||||||
renderObject = renderObject.parent as RenderObject;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(renderObject != null && !renderObject.debugNeedsPaint);
|
return binding.takeScreenshot(
|
||||||
final layer = renderObject!.debugLayer as OffsetLayer;
|
'screenshot_${DateTime.now().millisecondsSinceEpoch}',
|
||||||
|
);
|
||||||
return layer
|
|
||||||
.toImage(renderObject.semanticBounds)
|
|
||||||
.then((value) => value.toByteData(format: ui.ImageByteFormat.png))
|
|
||||||
.then((value) => value?.buffer.asUint8List() ?? List<int>.empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -84,7 +100,7 @@ class WidgetTesterAppDriverAdapter
|
||||||
Finder finder, {
|
Finder finder, {
|
||||||
Duration? timeout = const Duration(seconds: 30),
|
Duration? timeout = const Duration(seconds: 30),
|
||||||
}) async {
|
}) async {
|
||||||
await waitForAppToSettle(timeout: timeout);
|
await _implicitWait(timeout: timeout);
|
||||||
|
|
||||||
final instance = await widget(finder);
|
final instance = await widget(finder);
|
||||||
if (instance is Text) {
|
if (instance is Text) {
|
||||||
|
@ -109,7 +125,7 @@ class WidgetTesterAppDriverAdapter
|
||||||
finder,
|
finder,
|
||||||
text,
|
text,
|
||||||
);
|
);
|
||||||
await waitForAppToSettle(
|
await _implicitWait(
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -120,7 +136,7 @@ class WidgetTesterAppDriverAdapter
|
||||||
Duration? timeout = const Duration(seconds: 30),
|
Duration? timeout = const Duration(seconds: 30),
|
||||||
}) async {
|
}) async {
|
||||||
await nativeDriver.tap(finder);
|
await nativeDriver.tap(finder);
|
||||||
await waitForAppToSettle(
|
await _implicitWait(
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -138,7 +154,7 @@ class WidgetTesterAppDriverAdapter
|
||||||
duration: pressDuration,
|
duration: pressDuration,
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
);
|
);
|
||||||
await waitForAppToSettle(timeout: timeout);
|
await _implicitWait(timeout: timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -233,6 +249,6 @@ class WidgetTesterAppDriverAdapter
|
||||||
@override
|
@override
|
||||||
Future<void> pageBack() async {
|
Future<void> pageBack() async {
|
||||||
await nativeDriver.pageBack();
|
await nativeDriver.pageBack();
|
||||||
await waitForAppToSettle();
|
await _implicitWait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@ import 'package:source_gen/source_gen.dart';
|
||||||
class NoOpReporter extends MessageReporter {
|
class NoOpReporter extends MessageReporter {
|
||||||
@override
|
@override
|
||||||
Future<void> message(String message, MessageLevel level) async {
|
Future<void> message(String message, MessageLevel level) async {
|
||||||
if(level == MessageLevel.info || level == MessageLevel.debug) {
|
if (level == MessageLevel.info || level == MessageLevel.debug) {
|
||||||
print(message);
|
print(message);
|
||||||
}else if(level == MessageLevel.warning) {
|
} else if (level == MessageLevel.warning) {
|
||||||
print('\x1B[33m$message\x1B[0m');
|
print('\x1B[33m$message\x1B[0m');
|
||||||
}else if(level == MessageLevel.error) {
|
} else if (level == MessageLevel.error) {
|
||||||
print('\x1B[31m$message\x1B[0m');
|
print('\x1B[31m$message\x1B[0m');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ void executeTestSuite(
|
||||||
.getField('index')!
|
.getField('index')!
|
||||||
.toIntValue()!;
|
.toIntValue()!;
|
||||||
final executionOrder = ExecutionOrder.values[idx];
|
final executionOrder = ExecutionOrder.values[idx];
|
||||||
final featureFiles = annotation
|
final featureFiles = annotation
|
||||||
.read('featurePaths')
|
.read('featurePaths')
|
||||||
.listValue
|
.listValue
|
||||||
.map((path) => Glob(path.toStringValue()!))
|
.map((path) => Glob(path.toStringValue()!))
|
||||||
|
@ -139,9 +139,10 @@ class FeatureFileTestGeneratorVisitor extends FeatureFileVisitor {
|
||||||
''';
|
''';
|
||||||
static const String SCENARIO_TEMPLATE = '''
|
static const String SCENARIO_TEMPLATE = '''
|
||||||
runScenario(
|
runScenario(
|
||||||
'{{scenario_name}}',
|
name: '{{scenario_name}}',
|
||||||
{{tags}},
|
path: '{{path}}',
|
||||||
[
|
tags:{{tags}},
|
||||||
|
steps: [
|
||||||
{{steps}}
|
{{steps}}
|
||||||
],
|
],
|
||||||
{{onBefore}}
|
{{onBefore}}
|
||||||
|
|
|
@ -1,28 +1,63 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:flutter_gherkin/flutter_gherkin_with_driver.dart';
|
import 'package:flutter_gherkin/flutter_gherkin_with_driver.dart';
|
||||||
import 'package:flutter_gherkin/src/flutter/configuration/build_mode.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/world/flutter_driver_world.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/world/flutter_world.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/hooks/app_runner_hook.dart';
|
import 'package:flutter_gherkin/src/flutter/hooks/app_runner_hook.dart';
|
||||||
import 'package:flutter_driver/flutter_driver.dart';
|
import 'package:flutter_driver/flutter_driver.dart';
|
||||||
import 'package:gherkin/gherkin.dart';
|
import 'package:gherkin/gherkin.dart';
|
||||||
|
|
||||||
import 'flutter_test_configuration.dart';
|
|
||||||
|
|
||||||
class FlutterDriverTestConfiguration extends FlutterTestConfiguration {
|
class FlutterDriverTestConfiguration extends FlutterTestConfiguration {
|
||||||
String? _observatoryDebuggerUri;
|
String? _observatoryDebuggerUri;
|
||||||
|
|
||||||
|
FlutterDriverTestConfiguration({
|
||||||
|
String? featurePath = 'features/*.*.feature',
|
||||||
|
Iterable<Pattern>? features,
|
||||||
|
super.featureDefaultLanguage = 'en',
|
||||||
|
super.order = ExecutionOrder.random,
|
||||||
|
super.defaultTimeout = const Duration(seconds: 10),
|
||||||
|
super.featureFileMatcher = const IoFeatureFileAccessor(),
|
||||||
|
super.featureFileReader = const IoFeatureFileAccessor(),
|
||||||
|
super.stopAfterTestFailed = false,
|
||||||
|
super.tagExpression,
|
||||||
|
super.hooks,
|
||||||
|
super.reporters = const [],
|
||||||
|
super.createWorld,
|
||||||
|
super.waitImplicitlyAfterAction = true,
|
||||||
|
super.customStepParameterDefinitions,
|
||||||
|
super.stepDefinitions,
|
||||||
|
this.targetAppPath = 'test_driver/app.dart',
|
||||||
|
this.targetAppWorkingDirectory,
|
||||||
|
this.buildFlavor,
|
||||||
|
this.targetDeviceId,
|
||||||
|
this.runningAppProtocolEndpointUri,
|
||||||
|
this.onBeforeFlutterDriverConnect,
|
||||||
|
this.onAfterFlutterDriverConnect,
|
||||||
|
this.restartAppBetweenScenarios = true,
|
||||||
|
this.logFlutterProcessOutput = false,
|
||||||
|
this.keepAppRunningAfterTests = false,
|
||||||
|
this.verboseFlutterProcessLogs = false,
|
||||||
|
this.build = true,
|
||||||
|
this.buildMode = BuildMode.Debug,
|
||||||
|
this.flutterBuildTimeout = const Duration(seconds: 90),
|
||||||
|
this.flutterDriverReconnectionDelay = const Duration(seconds: 2),
|
||||||
|
this.flutterDriverMaxConnectionAttempts = 3,
|
||||||
|
}) :
|
||||||
|
// assert(featurePath != null && features != null),
|
||||||
|
super(
|
||||||
|
features: features != null ? features : [RegExp(featurePath!)],
|
||||||
|
);
|
||||||
|
|
||||||
/// Provide a configuration object with default settings such as the reports and feature file location
|
/// Provide a configuration object with default settings such as the reports and feature file location
|
||||||
/// Additional setting on the configuration object can be set on the returned instance.
|
/// Additional setting on the configuration object can be set on the returned instance.
|
||||||
static FlutterDriverTestConfiguration DEFAULT(
|
static FlutterDriverTestConfiguration DEFAULT(
|
||||||
Iterable<StepDefinitionGeneric<World>> steps, {
|
Iterable<StepDefinitionGeneric<World>> steps, {
|
||||||
String featurePath = 'features/*.*.feature',
|
String featurePath = 'features/*.*.feature',
|
||||||
String targetAppPath = 'test_driver/app.dart',
|
String targetAppPath = 'test_driver/app.dart',
|
||||||
|
String? targetAppWorkingDirectory,
|
||||||
|
bool restartAppBetweenScenarios = true,
|
||||||
}) {
|
}) {
|
||||||
return FlutterDriverTestConfiguration()
|
return FlutterDriverTestConfiguration(
|
||||||
..features = [RegExp(featurePath)]
|
features: [RegExp(featurePath)],
|
||||||
..reporters = [
|
reporters: [
|
||||||
StdoutReporter(MessageLevel.error),
|
StdoutReporter(MessageLevel.error),
|
||||||
ProgressReporter(),
|
ProgressReporter(),
|
||||||
TestRunSummaryReporter(),
|
TestRunSummaryReporter(),
|
||||||
|
@ -32,81 +67,84 @@ class FlutterDriverTestConfiguration extends FlutterTestConfiguration {
|
||||||
logInfoMessages: false,
|
logInfoMessages: false,
|
||||||
logWarningMessages: false,
|
logWarningMessages: false,
|
||||||
),
|
),
|
||||||
]
|
],
|
||||||
..targetAppPath = targetAppPath
|
targetAppPath: targetAppPath,
|
||||||
..stepDefinitions = steps
|
targetAppWorkingDirectory: targetAppWorkingDirectory,
|
||||||
..restartAppBetweenScenarios = true;
|
stepDefinitions: steps,
|
||||||
|
restartAppBetweenScenarios: restartAppBetweenScenarios,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// restarts the application under test between each scenario.
|
/// restarts the application under test between each scenario.
|
||||||
/// Defaults to true to avoid the application being in an invalid state
|
/// Defaults to true to avoid the application being in an invalid state
|
||||||
/// before each test
|
/// before each test
|
||||||
bool restartAppBetweenScenarios = true;
|
final bool restartAppBetweenScenarios;
|
||||||
|
|
||||||
/// The target app to run the tests against
|
/// The target app to run the tests against
|
||||||
/// Defaults to "test_driver/app.dart"
|
/// Defaults to "test_driver/app.dart"
|
||||||
String targetAppPath = 'test_driver/app.dart';
|
final String targetAppPath;
|
||||||
|
|
||||||
/// Option to define the working directory for the process that runs the app under test (optional)
|
/// Option to define the working directory for the process that runs the app under test (optional)
|
||||||
/// Handy if your app is separated from your tests as flutter needs to be able to find a pubspec file
|
/// Handy if your app is separated from your tests as flutter needs to be able to find a pubspec file
|
||||||
String? targetAppWorkingDirectory;
|
final String? targetAppWorkingDirectory;
|
||||||
|
|
||||||
/// The build flavor to run the tests against (optional)
|
/// The build flavor to run the tests against (optional)
|
||||||
/// Defaults to null
|
/// Defaults to null
|
||||||
String? buildFlavor;
|
final String? buildFlavor;
|
||||||
|
|
||||||
/// The default build mode used for running tests is --debug.
|
/// The default build mode used for running tests is --debug.
|
||||||
/// We are exposing the option to run the tests also in --profile mode
|
/// We are exposing the option to run the tests also in --profile mode
|
||||||
BuildMode buildMode = BuildMode.Debug;
|
final BuildMode buildMode;
|
||||||
|
|
||||||
/// If the application should be built prior to running the tests
|
/// If the application should be built prior to running the tests
|
||||||
/// Defaults to true
|
/// Defaults to true
|
||||||
bool build = true;
|
final bool build;
|
||||||
|
|
||||||
/// The target device id to run the tests against when multiple devices detected
|
/// The target device id to run the tests against when multiple devices detected
|
||||||
/// Defaults to null
|
/// Defaults to null
|
||||||
String? targetDeviceId;
|
final String? targetDeviceId;
|
||||||
|
|
||||||
/// Will keep the Flutter application running when done testing
|
/// Will keep the Flutter application running when done testing
|
||||||
/// Defaults to false
|
/// Defaults to false
|
||||||
bool keepAppRunningAfterTests = false;
|
final bool keepAppRunningAfterTests;
|
||||||
|
|
||||||
/// Logs Flutter process output to stdout
|
/// Logs Flutter process output to stdout
|
||||||
/// The Flutter process is use to start and driver the app under test.
|
/// The Flutter process is use to start and driver the app under test.
|
||||||
/// The output may contain build and run information
|
/// The output may contain build and run information
|
||||||
/// Defaults to false
|
/// Defaults to false
|
||||||
bool logFlutterProcessOutput = false;
|
final bool logFlutterProcessOutput;
|
||||||
|
|
||||||
/// Sets the --verbose flag on the flutter process
|
/// Sets the --verbose flag on the flutter process
|
||||||
/// Defaults to false
|
/// Defaults to false
|
||||||
bool verboseFlutterProcessLogs = false;
|
final bool verboseFlutterProcessLogs;
|
||||||
|
|
||||||
/// Duration to wait for Flutter to build and start the app on the target device
|
/// Duration to wait for Flutter to build and start the app on the target device
|
||||||
/// Slower machine may take longer to build and run a large app
|
/// Slower machine may take longer to build and run a large app
|
||||||
/// Defaults to 90 seconds
|
/// Defaults to 90 seconds
|
||||||
Duration flutterBuildTimeout = const Duration(seconds: 90);
|
final Duration flutterBuildTimeout;
|
||||||
|
|
||||||
/// Duration to wait before reconnecting the Flutter driver to the app.
|
/// Duration to wait before reconnecting the Flutter driver to the app.
|
||||||
/// On slower machines the app might not be in a state where the driver can successfully connect immediately
|
/// On slower machines the app might not be in a state where the driver can successfully connect immediately
|
||||||
/// Defaults to 2 seconds
|
/// Defaults to 2 seconds
|
||||||
Duration flutterDriverReconnectionDelay = const Duration(seconds: 2);
|
final Duration flutterDriverReconnectionDelay;
|
||||||
|
|
||||||
/// The maximum times the flutter driver can try and connect to the running app
|
/// The maximum times the flutter driver can try and connect to the running app
|
||||||
/// Defaults to 3
|
/// Defaults to 3
|
||||||
int flutterDriverMaxConnectionAttempts = 3;
|
final int flutterDriverMaxConnectionAttempts;
|
||||||
|
|
||||||
/// An observatory url that the test runner can connect to instead of creating a new running instance of the target application
|
/// An observatory url that the test runner can connect to instead of creating a new running instance of the target application
|
||||||
/// Url takes the form of `http://127.0.0.1:51540/EM72VtRsUV0=/` and usually printed to stdout in the form `Connecting to service protocol: http://127.0.0.1:51540/EM72VtRsUV0=/`
|
/// Url takes the form of `http://127.0.0.1:51540/EM72VtRsUV0=/` and usually printed to stdout in the form `Connecting to service protocol: http://127.0.0.1:51540/EM72VtRsUV0=/`
|
||||||
/// You will have to add the `--verbose` flag to the command to start your flutter app to see this output and ensure `enableFlutterDriverExtension()` is called by the running app
|
/// You will have to add the `--verbose` flag to the command to start your flutter app to see this output and ensure `enableFlutterDriverExtension()` is called by the running app
|
||||||
String? runningAppProtocolEndpointUri;
|
final String? runningAppProtocolEndpointUri;
|
||||||
|
|
||||||
/// Called before any attempt to connect Flutter driver to the running application, Depending on your configuration this
|
/// Called before any attempt to connect Flutter driver to the running application, Depending on your configuration this
|
||||||
/// method will be called before each scenario is run.
|
/// method will be called before each scenario is run.
|
||||||
Future<void> Function()? onBeforeFlutterDriverConnect;
|
final Future<void> Function()? onBeforeFlutterDriverConnect;
|
||||||
|
|
||||||
/// Called after the successful connection of Flutter driver to the running application. Depending on your configuration this
|
/// Called after the successful connection of Flutter driver to the running application. Depending on your configuration this
|
||||||
/// method will be called on each new connection usually before each scenario is run.
|
/// method will be called on each new connection usually before each scenario is run.
|
||||||
Future<void> Function(FlutterDriver driver)? onAfterFlutterDriverConnect;
|
final Future<void> Function(FlutterDriver driver)?
|
||||||
|
onAfterFlutterDriverConnect;
|
||||||
|
|
||||||
void setObservatoryDebuggerUri(String uri) => _observatoryDebuggerUri = uri;
|
void setObservatoryDebuggerUri(String uri) => _observatoryDebuggerUri = uri;
|
||||||
|
|
||||||
|
@ -157,20 +195,41 @@ class FlutterDriverTestConfiguration extends FlutterTestConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void prepare() {
|
TestConfiguration prepare() {
|
||||||
super.prepare();
|
super.prepare();
|
||||||
_ensureCorrectConfiguration();
|
_ensureCorrectConfiguration();
|
||||||
final providedCreateWorld = createWorld;
|
final providedCreateWorld = createWorld;
|
||||||
createWorld = (config) async {
|
|
||||||
FlutterWorld? world;
|
|
||||||
if (providedCreateWorld != null) {
|
|
||||||
world = await providedCreateWorld(config) as FlutterWorld;
|
|
||||||
}
|
|
||||||
|
|
||||||
return await createFlutterWorld(config, world);
|
return FlutterDriverTestConfiguration(
|
||||||
};
|
buildFlavor: this.buildFlavor,
|
||||||
|
customStepParameterDefinitions: this.customStepParameterDefinitions,
|
||||||
|
defaultTimeout: this.defaultTimeout,
|
||||||
|
featureDefaultLanguage: this.featureDefaultLanguage,
|
||||||
|
featureFileMatcher: this.featureFileMatcher,
|
||||||
|
featureFileReader: this.featureFileReader,
|
||||||
|
features: this.features,
|
||||||
|
onAfterFlutterDriverConnect: this.onAfterFlutterDriverConnect,
|
||||||
|
onBeforeFlutterDriverConnect: this.onBeforeFlutterDriverConnect,
|
||||||
|
order: this.order,
|
||||||
|
reporters: this.reporters,
|
||||||
|
restartAppBetweenScenarios: this.restartAppBetweenScenarios,
|
||||||
|
runningAppProtocolEndpointUri: this.runningAppProtocolEndpointUri,
|
||||||
|
stepDefinitions: this.stepDefinitions,
|
||||||
|
stopAfterTestFailed: this.stopAfterTestFailed,
|
||||||
|
tagExpression: this.tagExpression,
|
||||||
|
targetAppPath: this.targetAppPath,
|
||||||
|
targetAppWorkingDirectory: this.targetAppWorkingDirectory,
|
||||||
|
targetDeviceId: this.targetDeviceId,
|
||||||
|
createWorld: (config) async {
|
||||||
|
FlutterWorld? world;
|
||||||
|
if (providedCreateWorld != null) {
|
||||||
|
world = await providedCreateWorld(config) as FlutterWorld;
|
||||||
|
}
|
||||||
|
|
||||||
hooks = List.from(hooks ?? Iterable.empty())..add(FlutterAppRunnerHook());
|
return await createFlutterWorld(config, world);
|
||||||
|
},
|
||||||
|
hooks: List.from(hooks ?? Iterable.empty())..add(FlutterAppRunnerHook()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<FlutterDriver> _attemptDriverConnection(
|
Future<FlutterDriver> _attemptDriverConnection(
|
||||||
|
|
|
@ -1,34 +1,50 @@
|
||||||
import 'package:flutter_gherkin/flutter_gherkin_with_driver.dart';
|
import 'package:flutter_gherkin/flutter_gherkin_with_driver.dart';
|
||||||
import 'package:flutter_gherkin/src/flutter/parameters/existence_parameter.dart';
|
import 'package:flutter_gherkin/src/flutter/parameters/existence_parameter.dart';
|
||||||
import 'package:flutter_gherkin/src/flutter/parameters/swipe_direction_parameter.dart';
|
import 'package:flutter_gherkin/src/flutter/parameters/swipe_direction_parameter.dart';
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/given_i_open_the_drawer_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/restart_app_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/sibling_contains_text_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/swipe_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/tap_text_within_widget_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/tap_widget_of_type_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/tap_widget_of_type_within_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/tap_widget_with_text_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/text_exists_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/text_exists_within_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/then_expect_element_to_have_value_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/then_expect_widget_to_be_present_step.dart';
|
import 'package:flutter_gherkin/src/flutter/steps/then_expect_widget_to_be_present_step.dart';
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/wait_until_key_exists_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/wait_until_type_exists_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/when_fill_field_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/when_long_press_widget_step.dart';
|
import 'package:flutter_gherkin/src/flutter/steps/when_long_press_widget_step.dart';
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/when_pause_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/when_tap_widget_step.dart';
|
|
||||||
import 'package:flutter_gherkin/src/flutter/steps/when_tap_the_back_button_step.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:gherkin/gherkin.dart';
|
import 'package:gherkin/gherkin.dart';
|
||||||
|
|
||||||
class FlutterTestConfiguration extends TestConfiguration {
|
class FlutterTestConfiguration extends TestConfiguration {
|
||||||
|
static final Iterable<CustomParameter<dynamic>> _wellKnownParameters = [
|
||||||
|
ExistenceParameter(),
|
||||||
|
SwipeDirectionParameter(),
|
||||||
|
];
|
||||||
|
static final _wellKnownStepDefinitions = [
|
||||||
|
ThenExpectElementToHaveValue(),
|
||||||
|
WhenTapBackButtonWidget(),
|
||||||
|
WhenTapWidget(),
|
||||||
|
WhenTapWidgetWithoutScroll(),
|
||||||
|
WhenLongPressWidget(),
|
||||||
|
WhenLongPressWidgetWithoutScroll(),
|
||||||
|
WhenLongPressWidgetForDuration(),
|
||||||
|
GivenOpenDrawer(),
|
||||||
|
WhenPauseStep(),
|
||||||
|
WhenFillFieldStep(),
|
||||||
|
ThenExpectWidgetToBePresent(),
|
||||||
|
RestartAppStep(),
|
||||||
|
SiblingContainsTextStep(),
|
||||||
|
SwipeOnKeyStep(),
|
||||||
|
SwipeOnTextStep(),
|
||||||
|
TapTextWithinWidgetStep(),
|
||||||
|
TapWidgetOfTypeStep(),
|
||||||
|
TapWidgetOfTypeWithinStep(),
|
||||||
|
TapWidgetWithTextStep(),
|
||||||
|
TextExistsStep(),
|
||||||
|
TextExistsWithinStep(),
|
||||||
|
WaitUntilKeyExistsStep(),
|
||||||
|
WaitUntilTypeExistsStep(),
|
||||||
|
];
|
||||||
|
|
||||||
/// Enable semantics in a test by creating a [SemanticsHandle].
|
/// Enable semantics in a test by creating a [SemanticsHandle].
|
||||||
/// See: [testWidgets] and [WidgetController.ensureSemantics].
|
/// See: [testWidgets] and [WidgetController.ensureSemantics].
|
||||||
bool semanticsEnabled = true;
|
final bool semanticsEnabled;
|
||||||
|
|
||||||
|
/// Set to `True` to wait implicit for pumpAndSettle() / waitForAppToSettle() functions after performing actions
|
||||||
|
/// Defaults to false
|
||||||
|
final bool waitImplicitlyAfterAction;
|
||||||
|
|
||||||
/// Provide a configuration object with default settings such as the reports and feature file location
|
/// Provide a configuration object with default settings such as the reports and feature file location
|
||||||
/// Additional setting on the configuration object can be set on the returned instance.
|
/// Additional setting on the configuration object can be set on the returned instance.
|
||||||
static FlutterTestConfiguration DEFAULT(
|
static FlutterTestConfiguration DEFAULT(
|
||||||
|
@ -36,49 +52,38 @@ class FlutterTestConfiguration extends TestConfiguration {
|
||||||
String featurePath = 'integration_test/features/*.*.feature',
|
String featurePath = 'integration_test/features/*.*.feature',
|
||||||
String targetAppPath = 'test_driver/integration_test_driver.dart',
|
String targetAppPath = 'test_driver/integration_test_driver.dart',
|
||||||
}) {
|
}) {
|
||||||
return FlutterTestConfiguration()
|
return FlutterTestConfiguration(
|
||||||
..reporters = [
|
reporters: [
|
||||||
StdoutReporter(MessageLevel.error),
|
StdoutReporter(MessageLevel.error),
|
||||||
ProgressReporter(),
|
ProgressReporter(),
|
||||||
TestRunSummaryReporter(),
|
TestRunSummaryReporter(),
|
||||||
// JsonReporter(path: './report.json'),
|
// JsonReporter(path: './report.json'),
|
||||||
]
|
],
|
||||||
..stepDefinitions = steps;
|
stepDefinitions: steps,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
FlutterTestConfiguration({
|
||||||
void prepare() {
|
super.features = const <Pattern>[],
|
||||||
customStepParameterDefinitions =
|
super.featureDefaultLanguage = 'en',
|
||||||
List.from(customStepParameterDefinitions ?? Iterable.empty())
|
super.order = ExecutionOrder.random,
|
||||||
..addAll([
|
super.defaultTimeout = const Duration(seconds: 10),
|
||||||
ExistenceParameter(),
|
super.featureFileMatcher = const IoFeatureFileAccessor(),
|
||||||
SwipeDirectionParameter(),
|
super.featureFileReader = const IoFeatureFileAccessor(),
|
||||||
]);
|
super.stopAfterTestFailed = false,
|
||||||
stepDefinitions = List.from(stepDefinitions ?? Iterable.empty())
|
super.tagExpression,
|
||||||
..addAll([
|
super.hooks,
|
||||||
ThenExpectElementToHaveValue(),
|
super.reporters = const [],
|
||||||
WhenTapBackButtonWidget(),
|
super.createWorld,
|
||||||
WhenTapWidget(),
|
this.semanticsEnabled = true,
|
||||||
WhenTapWidgetWithoutScroll(),
|
this.waitImplicitlyAfterAction = false,
|
||||||
WhenLongPressWidget(),
|
Iterable<CustomParameter<dynamic>>? customStepParameterDefinitions,
|
||||||
WhenLongPressWidgetWithoutScroll(),
|
Iterable<StepDefinitionGeneric<World>>? stepDefinitions,
|
||||||
WhenLongPressWidgetForDuration(),
|
}) : super(
|
||||||
GivenOpenDrawer(),
|
customStepParameterDefinitions:
|
||||||
WhenPauseStep(),
|
List.from(customStepParameterDefinitions ?? Iterable.empty())
|
||||||
WhenFillFieldStep(),
|
..addAll(_wellKnownParameters),
|
||||||
ThenExpectWidgetToBePresent(),
|
stepDefinitions: List.from(stepDefinitions ?? Iterable.empty())
|
||||||
RestartAppStep(),
|
..addAll(_wellKnownStepDefinitions),
|
||||||
SiblingContainsTextStep(),
|
);
|
||||||
SwipeOnKeyStep(),
|
|
||||||
SwipeOnTextStep(),
|
|
||||||
TapTextWithinWidgetStep(),
|
|
||||||
TapWidgetOfTypeStep(),
|
|
||||||
TapWidgetOfTypeWithinStep(),
|
|
||||||
TapWidgetWithTextStep(),
|
|
||||||
TextExistsStep(),
|
|
||||||
TextExistsWithinStep(),
|
|
||||||
WaitUntilKeyExistsStep(),
|
|
||||||
WaitUntilTypeExistsStep(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import 'dart:io';
|
import 'dart:io' if (dart.library.html) 'dart:html';
|
||||||
import 'package:flutter_gherkin/src/flutter/configuration/flutter_driver_test_configuration.dart';
|
import 'package:flutter_gherkin/src/flutter/configuration/flutter_driver_test_configuration.dart';
|
||||||
import 'package:flutter_gherkin/src/flutter/runners/flutter_run_process_handler.dart';
|
import 'package:flutter_gherkin/src/flutter/runners/flutter_run_process_handler.dart';
|
||||||
import 'package:flutter_gherkin/src/flutter/world/flutter_driver_world.dart';
|
import 'package:flutter_gherkin/src/flutter/world/flutter_driver_world.dart';
|
||||||
|
@ -38,9 +38,9 @@ class FlutterAppRunnerHook extends Hook {
|
||||||
Future<void> onAfterScenario(
|
Future<void> onAfterScenario(
|
||||||
TestConfiguration config,
|
TestConfiguration config,
|
||||||
String scenario,
|
String scenario,
|
||||||
Iterable<Tag> tags,
|
Iterable<Tag> tags, {
|
||||||
{bool? passed,}
|
bool? passed,
|
||||||
) async {
|
}) async {
|
||||||
final flutterConfig = _castConfig(config);
|
final flutterConfig = _castConfig(config);
|
||||||
haveRunFirstScenario = true;
|
haveRunFirstScenario = true;
|
||||||
if (_flutterRunProcessHandler != null &&
|
if (_flutterRunProcessHandler != null &&
|
||||||
|
|
|
@ -13,11 +13,14 @@ enum _FlutterDriverMessageLogLevel { info, warning, error }
|
||||||
/// This can cause problems with CI servers for example as they will mark a process as failed if it logs to the
|
/// This can cause problems with CI servers for example as they will mark a process as failed if it logs to the
|
||||||
/// stderr stream. So Flutter driver will log a normal info message to the stderr and thus make
|
/// stderr stream. So Flutter driver will log a normal info message to the stderr and thus make
|
||||||
/// the process fail from the perspective of a CI server.
|
/// the process fail from the perspective of a CI server.
|
||||||
class FlutterDriverReporter extends Reporter {
|
class FlutterDriverReporter extends Reporter
|
||||||
|
implements DisposableReporter, TestReporter {
|
||||||
final bool logErrorMessages;
|
final bool logErrorMessages;
|
||||||
final bool logWarningMessages;
|
final bool logWarningMessages;
|
||||||
final bool logInfoMessages;
|
final bool logInfoMessages;
|
||||||
|
|
||||||
|
DriverLogCallback? defaultCallback;
|
||||||
|
|
||||||
FlutterDriverReporter({
|
FlutterDriverReporter({
|
||||||
this.logErrorMessages = true,
|
this.logErrorMessages = true,
|
||||||
this.logWarningMessages = true,
|
this.logWarningMessages = true,
|
||||||
|
@ -25,13 +28,18 @@ class FlutterDriverReporter extends Reporter {
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> onTestRunStarted() async {
|
ReportActionHandler<TestMessage> get test => ReportActionHandler(
|
||||||
driverLog = _driverLogMessageHandler;
|
onStarted: ([_]) async {
|
||||||
}
|
defaultCallback = driverLog;
|
||||||
|
driverLog = _driverLogMessageHandler;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
// driverLog = null;
|
if (defaultCallback != null) {
|
||||||
|
driverLog = defaultCallback!;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _driverLogMessageHandler(String source, String message) {
|
void _driverLogMessageHandler(String source, String message) {
|
||||||
|
|
|
@ -49,8 +49,7 @@ abstract class GherkinIntegrationTestRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> run() async {
|
Future<void> run() async {
|
||||||
_binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized()
|
_binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
as IntegrationTestWidgetsFlutterBinding;
|
|
||||||
|
|
||||||
_binding!.framePolicy =
|
_binding!.framePolicy =
|
||||||
framePolicy ?? LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive;
|
framePolicy ?? LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive;
|
||||||
|
@ -77,10 +76,8 @@ abstract class GherkinIntegrationTestRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTestResultData(IntegrationTestWidgetsFlutterBinding binding) {
|
void setTestResultData(IntegrationTestWidgetsFlutterBinding binding) {
|
||||||
if (reporter is SerializableReporter) {
|
final json = (reporter).serialize();
|
||||||
final json = (reporter as SerializableReporter).serialize();
|
binding.reportData = {'gherkin_reports': json};
|
||||||
binding.reportData = {'gherkin_reports': json};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
|
@ -115,10 +112,7 @@ abstract class GherkinIntegrationTestRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Future<void> onAfterRunFeature(
|
Future<void> onAfterRunFeature(String name, String path) async {
|
||||||
String name,
|
|
||||||
String path
|
|
||||||
) async {
|
|
||||||
final debugInformation = RunnableDebugInformation(path, 0, name);
|
final debugInformation = RunnableDebugInformation(path, 0, name);
|
||||||
await reporter.test.onFinished.maybeCall(
|
await reporter.test.onFinished.maybeCall(
|
||||||
TestMessage(
|
TestMessage(
|
||||||
|
@ -130,11 +124,16 @@ abstract class GherkinIntegrationTestRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void runScenario(
|
void runScenario({
|
||||||
String name,
|
required String name,
|
||||||
Iterable<String>? tags,
|
required Iterable<String>? tags,
|
||||||
List<Future<StepResult> Function(TestDependencies dependencies, bool skip,)>
|
required List<
|
||||||
steps, String path, {
|
Future<StepResult> Function(
|
||||||
|
TestDependencies dependencies,
|
||||||
|
bool skip,
|
||||||
|
)>
|
||||||
|
steps,
|
||||||
|
required String path,
|
||||||
Future<void> Function()? onBefore,
|
Future<void> Function()? onBefore,
|
||||||
Future<void> Function()? onAfter,
|
Future<void> Function()? onAfter,
|
||||||
}) {
|
}) {
|
||||||
|
@ -257,7 +256,15 @@ abstract class GherkinIntegrationTestRunner {
|
||||||
world = world ?? FlutterWidgetTesterWorld();
|
world = world ?? FlutterWidgetTesterWorld();
|
||||||
world.setAttachmentManager(attachmentManager);
|
world.setAttachmentManager(attachmentManager);
|
||||||
|
|
||||||
(world as FlutterWorld).setAppAdapter(WidgetTesterAppDriverAdapter(tester));
|
(world as FlutterWorld).setAppAdapter(
|
||||||
|
WidgetTesterAppDriverAdapter(
|
||||||
|
rawAdapter: tester,
|
||||||
|
binding: _binding!,
|
||||||
|
waitImplicitlyAfterAction: configuration is FlutterTestConfiguration
|
||||||
|
? (configuration).waitImplicitlyAfterAction
|
||||||
|
: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
return TestDependencies(
|
return TestDependencies(
|
||||||
world,
|
world,
|
||||||
|
@ -266,8 +273,13 @@ abstract class GherkinIntegrationTestRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Future<StepResult> runStep(String step, Iterable<String> multiLineStrings,
|
Future<StepResult> runStep(
|
||||||
dynamic table, TestDependencies dependencies, bool hasToSkip,) async {
|
String step,
|
||||||
|
Iterable<String> multiLineStrings,
|
||||||
|
dynamic table,
|
||||||
|
TestDependencies dependencies,
|
||||||
|
bool hasToSkip,
|
||||||
|
) async {
|
||||||
final executable = _executableSteps!.firstWhereOrNull(
|
final executable = _executableSteps!.firstWhereOrNull(
|
||||||
(s) => s.expression.isMatch(step),
|
(s) => s.expression.isMatch(step),
|
||||||
);
|
);
|
||||||
|
@ -294,8 +306,8 @@ abstract class GherkinIntegrationTestRunner {
|
||||||
StepResult? result;
|
StepResult? result;
|
||||||
|
|
||||||
if (hasToSkip) {
|
if (hasToSkip) {
|
||||||
result = new StepResult(
|
result = new StepResult(0, StepExecutionResult.skipped,
|
||||||
0, StepExecutionResult.skipped, resultReason: "Previous step(s) failed.");
|
resultReason: "Previous step(s) failed.");
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < this.configuration.stepMaxRetries + 1; i++) {
|
for (int i = 0; i < this.configuration.stepMaxRetries + 1; i++) {
|
||||||
result = await executable.step.run(
|
result = await executable.step.run(
|
||||||
|
@ -426,7 +438,9 @@ abstract class GherkinIntegrationTestRunner {
|
||||||
name: step,
|
name: step,
|
||||||
context: RunnableDebugInformation('', 0, step),
|
context: RunnableDebugInformation('', 0, step),
|
||||||
result: result,
|
result: result,
|
||||||
attachments: dependencies.attachmentManager.getAttachmentsForContext(step).toList(),
|
attachments: dependencies.attachmentManager
|
||||||
|
.getAttachmentsForContext(step)
|
||||||
|
.toList(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import 'package:flutter_gherkin/flutter_gherkin.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/world/flutter_world.dart';
|
|
||||||
import 'package:gherkin/gherkin.dart';
|
import 'package:gherkin/gherkin.dart';
|
||||||
|
|
||||||
/// Discovers a widget by its text within the same parent.
|
/// Discovers a widget by its text within the same parent.
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
||||||
import 'package:flutter_gherkin/src/flutter/world/flutter_world.dart';
|
|
||||||
import 'package:gherkin/gherkin.dart';
|
import 'package:gherkin/gherkin.dart';
|
||||||
|
|
||||||
import '../parameters/swipe_direction_parameter.dart';
|
import '../parameters/swipe_direction_parameter.dart';
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:flutter_gherkin/flutter_gherkin.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 'package:gherkin/gherkin.dart';
|
||||||
|
|
||||||
/// Taps a widget that contains the text within another widget.
|
/// Taps a widget that contains the text within another widget.
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:flutter_gherkin/flutter_gherkin.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 'package:gherkin/gherkin.dart';
|
||||||
|
|
||||||
/// Taps a widget of type.
|
/// Taps a widget of type.
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:flutter_gherkin/flutter_gherkin.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 'package:gherkin/gherkin.dart';
|
||||||
|
|
||||||
/// Taps a widget of type within another widget.
|
/// Taps a widget of type within another widget.
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:flutter_gherkin/flutter_gherkin.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 'package:gherkin/gherkin.dart';
|
||||||
|
|
||||||
/// Taps a widget that contains text.
|
/// Taps a widget that contains text.
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:flutter_gherkin/flutter_gherkin.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 'package:gherkin/gherkin.dart';
|
||||||
|
|
||||||
import '../parameters/existence_parameter.dart';
|
import '../parameters/existence_parameter.dart';
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:flutter_gherkin/flutter_gherkin.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 'package:gherkin/gherkin.dart';
|
||||||
|
|
||||||
import '../parameters/existence_parameter.dart';
|
import '../parameters/existence_parameter.dart';
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:flutter_gherkin/flutter_gherkin.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 'package:gherkin/gherkin.dart';
|
||||||
|
|
||||||
import '../parameters/existence_parameter.dart';
|
import '../parameters/existence_parameter.dart';
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:flutter_gherkin/flutter_gherkin.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 'package:gherkin/gherkin.dart';
|
||||||
|
|
||||||
import '../parameters/existence_parameter.dart';
|
import '../parameters/existence_parameter.dart';
|
||||||
|
|
37
pubspec.lock
37
pubspec.lock
|
@ -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: "30.0.0"
|
version: "40.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.7.0"
|
version: "4.1.0"
|
||||||
archive:
|
archive:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -28,7 +28,7 @@ packages:
|
||||||
name: args
|
name: args
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.3.1"
|
||||||
async:
|
async:
|
||||||
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.1"
|
version: "2.3.0"
|
||||||
build_config:
|
build_config:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
@ -78,13 +78,6 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.1"
|
||||||
cli_util:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: cli_util
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.3.5"
|
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -105,7 +98,7 @@ packages:
|
||||||
name: convert
|
name: convert
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.1"
|
version: "3.0.2"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -119,7 +112,7 @@ packages:
|
||||||
name: dart_style
|
name: dart_style
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.3"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -160,14 +153,14 @@ packages:
|
||||||
name: gherkin
|
name: gherkin
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.0+1"
|
||||||
glob:
|
glob:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: glob
|
name: glob
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.1.0"
|
||||||
integration_test:
|
integration_test:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -179,7 +172,7 @@ packages:
|
||||||
name: json_annotation
|
name: json_annotation
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.3.0"
|
version: "4.5.0"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -214,7 +207,7 @@ packages:
|
||||||
name: package_config
|
name: package_config
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.1.0"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -249,14 +242,14 @@ packages:
|
||||||
name: pub_semver
|
name: pub_semver
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.1"
|
||||||
pubspec_parse:
|
pubspec_parse:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pubspec_parse
|
name: pubspec_parse
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.2.0"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -268,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.1"
|
version: "1.2.2"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -366,7 +359,7 @@ packages:
|
||||||
name: yaml
|
name: yaml
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "3.1.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.17.0-0 <3.0.0"
|
dart: ">=2.17.0 <3.0.0"
|
||||||
flutter: ">=2.2.0"
|
flutter: ">=2.2.0"
|
||||||
|
|
10
pubspec.yaml
10
pubspec.yaml
|
@ -1,10 +1,10 @@
|
||||||
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.9
|
version: 3.0.0
|
||||||
homepage: https://github.com/jonsamwell/flutter_gherkin
|
homepage: https://github.com/jonsamwell/flutter_gherkin
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.12.3 <3.0.0'
|
sdk: '>=2.17.0 <3.0.0'
|
||||||
flutter: ">=2.2.0"
|
flutter: ">=2.2.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -16,15 +16,15 @@ dependencies:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_driver:
|
flutter_driver:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
analyzer: ">=1.7.1 <3.0.0"
|
analyzer: '>=2.1.0 < 5.0.0'
|
||||||
collection: ^1.15.0
|
collection: ^1.15.0
|
||||||
gherkin: ^3.0.0
|
gherkin: ^3.0.0+1
|
||||||
source_gen: ^1.1.1
|
source_gen: ^1.1.1
|
||||||
build: ^2.1.1
|
build: ^2.1.1
|
||||||
glob: ^2.0.2
|
glob: ^2.0.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
meta: ^1.7.0
|
meta: '>=1.7.0 < 2.0.0'
|
||||||
pedantic: ^1.11.1
|
pedantic: ^1.11.1
|
||||||
build_config: ^1.0.0
|
build_config: ^1.0.0
|
||||||
|
|
||||||
|
|
|
@ -6,43 +6,37 @@ import 'mocks/step_definition_mock.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('config', () {
|
group('config', () {
|
||||||
group('prepare', () {
|
test('flutter app runner hook added', () {
|
||||||
test('flutter app runner hook added', () {
|
final config = FlutterDriverTestConfiguration();
|
||||||
final config = FlutterDriverTestConfiguration();
|
final newConfig = config.prepare();
|
||||||
expect(config.hooks, isNull);
|
|
||||||
config.prepare();
|
|
||||||
expect(config.hooks, isNotNull);
|
|
||||||
expect(config.hooks!.length, 1);
|
|
||||||
expect(config.hooks!.elementAt(0), (x) => x is FlutterAppRunnerHook);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('common steps definition added', () {
|
expect(newConfig.hooks, isNotNull);
|
||||||
final config = FlutterDriverTestConfiguration();
|
expect(newConfig.hooks!.length, 1);
|
||||||
expect(config.stepDefinitions, isNull);
|
expect(newConfig.hooks!.elementAt(0), (x) => x is FlutterAppRunnerHook);
|
||||||
|
});
|
||||||
|
|
||||||
config.prepare();
|
test('common steps definition added', () {
|
||||||
expect(config.stepDefinitions, isNotNull);
|
final config = FlutterDriverTestConfiguration();
|
||||||
expect(config.stepDefinitions!.length, 23);
|
expect(config.stepDefinitions, isNotNull);
|
||||||
expect(config.customStepParameterDefinitions, isNotNull);
|
expect(config.stepDefinitions!.length, 23);
|
||||||
expect(config.customStepParameterDefinitions!.length, 2);
|
expect(config.customStepParameterDefinitions, isNotNull);
|
||||||
});
|
expect(config.customStepParameterDefinitions!.length, 2);
|
||||||
|
});
|
||||||
|
|
||||||
test('common step definition added to existing steps', () {
|
test('common step definition added to existing steps', () {
|
||||||
final config = FlutterTestConfiguration()
|
final config = FlutterTestConfiguration(
|
||||||
..stepDefinitions = [MockStepDefinition()]
|
stepDefinitions: [MockStepDefinition()],
|
||||||
..customStepParameterDefinitions = [MockParameter()];
|
customStepParameterDefinitions: [MockParameter()],
|
||||||
expect(config.stepDefinitions!.length, 1);
|
);
|
||||||
|
|
||||||
config.prepare();
|
expect(config.stepDefinitions, isNotNull);
|
||||||
expect(config.stepDefinitions, isNotNull);
|
expect(config.stepDefinitions!.length, 24);
|
||||||
expect(config.stepDefinitions!.length, 24);
|
expect(
|
||||||
expect(config.stepDefinitions!.elementAt(0),
|
config.stepDefinitions!.elementAt(0), (x) => x is MockStepDefinition);
|
||||||
(x) => x is MockStepDefinition);
|
expect(config.customStepParameterDefinitions, isNotNull);
|
||||||
expect(config.customStepParameterDefinitions, isNotNull);
|
expect(config.customStepParameterDefinitions!.length, 3);
|
||||||
expect(config.customStepParameterDefinitions!.length, 3);
|
expect(config.customStepParameterDefinitions!.elementAt(0),
|
||||||
expect(config.customStepParameterDefinitions!.elementAt(0),
|
(x) => x is MockParameter);
|
||||||
(x) => x is MockParameter);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue