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.
|
||||
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
|
||||
.dart_tool/
|
||||
|
||||
.packages
|
||||
.pub/
|
||||
|
||||
build/
|
||||
ios/.generated/
|
||||
ios/Flutter/Generated.xcconfig
|
||||
ios/Runner/GeneratedPluginRegistrant.*
|
||||
|
||||
node_modules
|
||||
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
|
||||
|
||||
- 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"
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
compileSdkVersion 31
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '1.3.50'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,4 +3,5 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
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
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.6.1"
|
||||
version: "2.8.2"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -22,20 +43,34 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
build:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.2.0"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -49,7 +84,14 @@ packages:
|
|||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -57,20 +99,27 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.3.0"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.0"
|
||||
version: "6.1.2"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
|
@ -87,7 +136,7 @@ packages:
|
|||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "2.0.0"
|
||||
version: "3.0.0"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
|
@ -104,59 +153,101 @@ packages:
|
|||
name: gherkin
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0"
|
||||
version: "1.8.1"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.1.0"
|
||||
process:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: process
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.1"
|
||||
version: "1.8.2"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -198,7 +289,7 @@ packages:
|
|||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
version: "0.4.9"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -206,20 +297,34 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uuid
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.6"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.1.2"
|
||||
vm_service:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -227,6 +332,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: yaml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
sdks:
|
||||
dart: ">=2.12.3 <3.0.0"
|
||||
dart: ">=2.17.0 <3.0.0"
|
||||
flutter: ">=2.2.0"
|
||||
|
|
|
@ -6,7 +6,8 @@ publish_to: 'none'
|
|||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: '>=2.12.0 <3.0.0'
|
||||
sdk: '>=2.17.0 <3.0.0'
|
||||
flutter: ">=2.2.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
|
|
@ -3,22 +3,26 @@ import 'package:flutter_gherkin/flutter_gherkin_with_driver.dart';
|
|||
import 'package:gherkin/gherkin.dart';
|
||||
|
||||
Future<void> main() {
|
||||
final config = FlutterDriverTestConfiguration.DEFAULT(
|
||||
Iterable.empty(),
|
||||
featurePath: 'features/**.feature',
|
||||
final config = FlutterDriverTestConfiguration(
|
||||
features: [RegExp('features/**.feature')],
|
||||
targetAppPath: 'test_driver/app.dart',
|
||||
)
|
||||
..restartAppBetweenScenarios = true
|
||||
..targetAppWorkingDirectory = '../'
|
||||
..targetAppPath = 'test_driver/app.dart';
|
||||
// ..buildFlavor = "staging" // uncomment when using build flavor and check android/ios flavor setup see android file android\app\build.gradle
|
||||
// ..targetDeviceId = "all" // uncomment to run tests on all connected devices or set specific device target id
|
||||
// ..tagExpression = '@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
|
||||
// ..verboseFlutterProcessLogs = true // uncomment to see the verbose output from the Flutter process
|
||||
// ..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
|
||||
targetAppWorkingDirectory: '../',
|
||||
buildFlavor:
|
||||
"staging", // uncomment when using build flavor and check android/ios flavor setup see android file android\app\build.gradle
|
||||
targetDeviceId:
|
||||
"all", // uncomment to run tests on all connected devices or set specific device target id
|
||||
tagExpression:
|
||||
'@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
|
||||
verboseFlutterProcessLogs:
|
||||
true, // uncomment to see the verbose output from the Flutter process
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
|
|||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
compileSdkVersion 31
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
|
@ -39,8 +39,8 @@ android {
|
|||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId "com.example.example_with_integration_test"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 29
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 31
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
}
|
||||
|
|
|
@ -6,11 +6,12 @@
|
|||
additional functionality it is fine to subclass or reimplement
|
||||
FlutterApplication and put your custom class here. -->
|
||||
<application
|
||||
android:name="io.flutter.app.FlutterApplication"
|
||||
android:name="${applicationName}"
|
||||
android:label="example_with_integration_test"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '1.3.50'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,4 +3,5 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
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
|
||||
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
|
||||
Scenario: User can create multiple new todo items
|
||||
Given I fill the "todo" field with "Buy carrots"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
@tag
|
||||
Feature: Swiping
|
||||
|
||||
@debug
|
||||
Scenario: User can swipe cards left and right
|
||||
Given I swipe right by 250 pixels on the "scrollable cards"`
|
||||
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 'world/custom_world.dart';
|
||||
|
||||
FlutterTestConfiguration gherkinTestConfiguration =
|
||||
FlutterTestConfiguration.DEFAULT(
|
||||
[
|
||||
FlutterTestConfiguration gherkinTestConfiguration = FlutterTestConfiguration(
|
||||
tagExpression: '@debug',
|
||||
stepDefinitions: [
|
||||
thenIExpectTheTodos,
|
||||
whenAnAnimationIsAwaited,
|
||||
whenStepHasTimeout,
|
||||
givenTheData
|
||||
],
|
||||
)
|
||||
// ..tagExpression = '@debug'
|
||||
..hooks = [
|
||||
ResetAppHook(),
|
||||
]
|
||||
..reporters = [
|
||||
StdoutReporter(MessageLevel.error)
|
||||
..setWriteLineFn(print)
|
||||
..setWriteFn(print),
|
||||
ProgressReporter()
|
||||
..setWriteLineFn(print)
|
||||
..setWriteFn(print),
|
||||
TestRunSummaryReporter()
|
||||
..setWriteLineFn(print)
|
||||
..setWriteFn(print),
|
||||
JsonReporter(
|
||||
writeReport: (_, __) => Future<void>.value(),
|
||||
),
|
||||
]
|
||||
..createWorld = (config) => Future.value(CustomWorld());
|
||||
hooks: [
|
||||
ResetAppHook(),
|
||||
],
|
||||
reporters: [
|
||||
StdoutReporter(MessageLevel.error)
|
||||
..setWriteLineFn(print)
|
||||
..setWriteFn(print),
|
||||
ProgressReporter()
|
||||
..setWriteLineFn(print)
|
||||
..setWriteFn(print),
|
||||
TestRunSummaryReporter()
|
||||
..setWriteLineFn(print)
|
||||
..setWriteFn(print),
|
||||
],
|
||||
createWorld: (config) => Future.value(CustomWorld()),
|
||||
);
|
||||
|
||||
Future<void> Function(World) appInitializationFn = (World world) async {
|
||||
// ensure a new injector instance is created each time
|
||||
|
|
|
@ -21,209 +21,152 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
|||
|
||||
void testFeature0() {
|
||||
runFeature(
|
||||
'Checking data:',
|
||||
'Swiping:',
|
||||
<String>['@tag'],
|
||||
() {
|
||||
runScenario(
|
||||
'User can have data',
|
||||
<String>['@tag', '@tag1'],
|
||||
(TestDependencies dependencies) async {
|
||||
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,
|
||||
);
|
||||
},
|
||||
name: 'User can swipe cards left and right',
|
||||
path:
|
||||
'C:\Development\github\flutter_gherkin\example_with_integration_test\.\integration_test\features\swiping.feature',
|
||||
tags: <String>['@tag'],
|
||||
steps: [
|
||||
(TestDependencies dependencies, bool hasToSkip) async {
|
||||
return await runStep(
|
||||
'Given I swipe right by 250 pixels on the "scrollable cards"`',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
hasToSkip,
|
||||
);
|
||||
},
|
||||
(TestDependencies dependencies, bool hasToSkip) async {
|
||||
return await runStep(
|
||||
'Then Then I expect the text "Page 2" to be present',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
hasToSkip,
|
||||
);
|
||||
},
|
||||
(TestDependencies dependencies, bool hasToSkip) async {
|
||||
return await runStep(
|
||||
'Given I swipe left by 250 pixels on the "scrollable cards"`',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
hasToSkip,
|
||||
);
|
||||
},
|
||||
(TestDependencies dependencies, bool hasToSkip) async {
|
||||
return await runStep(
|
||||
'Then Then I expect the text "Page 1" to be present',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
hasToSkip,
|
||||
);
|
||||
}
|
||||
],
|
||||
onBefore: () async => onBeforeRunFeature(
|
||||
'Checking data',
|
||||
'Swiping',
|
||||
<String>['@tag'],
|
||||
),
|
||||
onAfter: () async => onAfterRunFeature(
|
||||
'Checking data',
|
||||
),
|
||||
onAfter: () async => onAfterRunFeature('Swiping',
|
||||
'C:\Development\github\flutter_gherkin\example_with_integration_test\.\integration_test\features\swiping.feature'),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
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(
|
||||
'Creating todos:',
|
||||
<String>['@tag'],
|
||||
() {
|
||||
runScenario(
|
||||
'User can create a new todo item',
|
||||
<String>['@tag', '@tag1', '@tag_two'],
|
||||
(TestDependencies dependencies) async {
|
||||
await runStep(
|
||||
'Given I fill the "todo" field with "Buy carrots"',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
);
|
||||
|
||||
await runStep(
|
||||
'When I tap the \'add\' button',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
);
|
||||
|
||||
await runStep(
|
||||
'Then I expect the todo list',
|
||||
<String>[],
|
||||
GherkinTable.fromJson('[{"Todo":"Buy carrots"}]'),
|
||||
dependencies,
|
||||
);
|
||||
},
|
||||
onBefore: () async => onBeforeRunFeature(
|
||||
'Creating todos',
|
||||
<String>['@tag'],
|
||||
),
|
||||
onAfter: null,
|
||||
);
|
||||
|
||||
runScenario(
|
||||
'User can create multiple new todo items',
|
||||
<String>['@tag', '@debug'],
|
||||
(TestDependencies dependencies) async {
|
||||
await runStep(
|
||||
'Given I fill the "todo" field with "Buy carrots"',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
);
|
||||
|
||||
await runStep(
|
||||
'When I tap the "add" button',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
);
|
||||
|
||||
await runStep(
|
||||
'And I fill the "todo" field with "Buy apples"',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
);
|
||||
|
||||
await runStep(
|
||||
'When I tap the "add" button',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
);
|
||||
|
||||
await runStep(
|
||||
'And I fill the "todo" field with "Buy blueberries"',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
);
|
||||
|
||||
await runStep(
|
||||
'When I tap the "add" button',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
);
|
||||
|
||||
await runStep(
|
||||
'Then I expect the todo list',
|
||||
<String>[],
|
||||
GherkinTable.fromJson(
|
||||
'[{"Todo":"Buy blueberries"},{"Todo":"Buy apples"},{"Todo":"Buy carrots"}]'),
|
||||
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>[
|
||||
"""{
|
||||
name: 'User can create multiple new todo items',
|
||||
path:
|
||||
'C:\Development\github\flutter_gherkin\example_with_integration_test\.\integration_test\features\create.feature',
|
||||
tags: <String>['@tag', '@debug'],
|
||||
steps: [
|
||||
(TestDependencies dependencies, bool hasToSkip) async {
|
||||
return await runStep(
|
||||
'Given I fill the "todo" field with "Buy carrots"',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
hasToSkip,
|
||||
);
|
||||
},
|
||||
(TestDependencies dependencies, bool hasToSkip) async {
|
||||
return await runStep(
|
||||
'When I tap the "add" button',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
hasToSkip,
|
||||
);
|
||||
},
|
||||
(TestDependencies dependencies, bool hasToSkip) async {
|
||||
return await runStep(
|
||||
'And I fill the "todo" field with "Buy apples"',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
hasToSkip,
|
||||
);
|
||||
},
|
||||
(TestDependencies dependencies, bool hasToSkip) async {
|
||||
return await runStep(
|
||||
'When I tap the "add" button',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
hasToSkip,
|
||||
);
|
||||
},
|
||||
(TestDependencies dependencies, bool hasToSkip) async {
|
||||
return await runStep(
|
||||
'And I fill the "todo" field with "Buy blueberries"',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
hasToSkip,
|
||||
);
|
||||
},
|
||||
(TestDependencies dependencies, bool hasToSkip) async {
|
||||
return await runStep(
|
||||
'When I tap the "add" button',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
hasToSkip,
|
||||
);
|
||||
},
|
||||
(TestDependencies dependencies, bool hasToSkip) async {
|
||||
return await runStep(
|
||||
'Then I expect the todo list',
|
||||
<String>[],
|
||||
GherkinTable.fromJson(
|
||||
'[{"Todo":"Buy blueberries"},{"Todo":"Buy apples"},{"Todo":"Buy carrots"}]'),
|
||||
dependencies,
|
||||
hasToSkip,
|
||||
);
|
||||
},
|
||||
(TestDependencies dependencies, bool hasToSkip) async {
|
||||
return await runStep(
|
||||
'Given I wait 5 seconds for the animation to complete',
|
||||
<String>[],
|
||||
null,
|
||||
dependencies,
|
||||
hasToSkip,
|
||||
);
|
||||
},
|
||||
(TestDependencies dependencies, bool hasToSkip) async {
|
||||
return await runStep(
|
||||
'Given I have item with data',
|
||||
<String>[
|
||||
"""{
|
||||
"glossary": {
|
||||
"title": "example glossary",
|
||||
"GlossDiv": {
|
||||
|
@ -248,15 +191,77 @@ class _CustomGherkinIntegrationTestRunner extends GherkinIntegrationTestRunner {
|
|||
}
|
||||
}
|
||||
}"""
|
||||
],
|
||||
null,
|
||||
dependencies,
|
||||
);
|
||||
},
|
||||
onBefore: null,
|
||||
onAfter: () async => onAfterRunFeature(
|
||||
],
|
||||
null,
|
||||
dependencies,
|
||||
hasToSkip,
|
||||
);
|
||||
}
|
||||
],
|
||||
onBefore: () async => onBeforeRunFeature(
|
||||
'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/widgets/view_utils_mixin.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
|
||||
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/widgets/components/add_todo_component.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import '../view_utils_mixin.dart';
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ packages:
|
|||
name: archive
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
version: "3.1.11"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -35,7 +35,7 @@ packages:
|
|||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.8.1"
|
||||
version: "2.8.2"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -105,7 +105,7 @@ packages:
|
|||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.2.0"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -147,7 +147,7 @@ packages:
|
|||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
version: "1.16.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -175,7 +175,7 @@ packages:
|
|||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.3.0"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -213,7 +213,7 @@ packages:
|
|||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "3.0.0-rc.9"
|
||||
version: "3.0.0"
|
||||
flutter_simple_dependency_injection:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -249,7 +249,7 @@ packages:
|
|||
name: gherkin
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.8"
|
||||
version: "3.0.0+1"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -296,7 +296,7 @@ packages:
|
|||
name: js
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.3"
|
||||
version: "0.6.4"
|
||||
json_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -324,7 +324,14 @@ packages:
|
|||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -352,7 +359,7 @@ packages:
|
|||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0"
|
||||
version: "1.8.1"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -380,7 +387,7 @@ packages:
|
|||
name: platform
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.1.0"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -401,7 +408,7 @@ packages:
|
|||
name: process
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.2.3"
|
||||
version: "4.2.4"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -504,7 +511,7 @@ packages:
|
|||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.1"
|
||||
version: "1.8.2"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -553,7 +560,7 @@ packages:
|
|||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.2"
|
||||
version: "0.4.9"
|
||||
timing:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -574,21 +581,21 @@ packages:
|
|||
name: uuid
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.5"
|
||||
version: "3.0.6"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.1.2"
|
||||
vm_service:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "7.1.1"
|
||||
version: "8.2.2"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -632,5 +639,5 @@ packages:
|
|||
source: hosted
|
||||
version: "3.1.0"
|
||||
sdks:
|
||||
dart: ">=2.14.0 <3.0.0"
|
||||
dart: ">=2.17.0 <3.0.0"
|
||||
flutter: ">=2.5.0"
|
||||
|
|
|
@ -6,8 +6,8 @@ publish_to: 'none'
|
|||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: '>=2.14.0 <3.0.0'
|
||||
flutter: ">=2.5.0"
|
||||
sdk: '>=2.17.0 <3.0.0'
|
||||
flutter: ">=2.2.0"
|
||||
|
||||
dependencies:
|
||||
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/when_tap_the_back_button_step.dart';
|
||||
export 'src/flutter/steps/wait_until_type_exists_step.dart';
|
||||
export 'src/flutter/steps/wait_until_key_exists_step.dart';
|
||||
|
||||
// Hooks
|
||||
export 'src/flutter/hooks/attach_screenshot_on_failed_step_hook.dart';
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
import 'dart:async';
|
||||
import 'dart:ui' as ui show ImageByteFormat;
|
||||
import 'dart:io' if (dart.library.html) 'dart:html';
|
||||
|
||||
import 'package:flutter/foundation.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:integration_test/integration_test.dart';
|
||||
|
||||
import 'app_driver_adapter.dart';
|
||||
|
||||
class WidgetTesterAppDriverAdapter
|
||||
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
|
||||
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
|
||||
Future<T> widget<T extends Widget>(
|
||||
Finder finder, [
|
||||
|
@ -47,20 +68,15 @@ class WidgetTesterAppDriverAdapter
|
|||
}
|
||||
|
||||
@override
|
||||
Future<List<int>> screenshot() {
|
||||
var renderObject = nativeDriver.binding.renderViewElement?.renderObject;
|
||||
|
||||
while (renderObject != null && !renderObject.isRepaintBoundary) {
|
||||
renderObject = renderObject.parent as RenderObject;
|
||||
Future<List<int>> screenshot() async {
|
||||
if (!kIsWeb && Platform.isAndroid) {
|
||||
await binding.convertFlutterSurfaceToImage();
|
||||
await binding.pump();
|
||||
}
|
||||
|
||||
assert(renderObject != null && !renderObject.debugNeedsPaint);
|
||||
final layer = renderObject!.debugLayer as OffsetLayer;
|
||||
|
||||
return layer
|
||||
.toImage(renderObject.semanticBounds)
|
||||
.then((value) => value.toByteData(format: ui.ImageByteFormat.png))
|
||||
.then((value) => value?.buffer.asUint8List() ?? List<int>.empty());
|
||||
return binding.takeScreenshot(
|
||||
'screenshot_${DateTime.now().millisecondsSinceEpoch}',
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -84,7 +100,7 @@ class WidgetTesterAppDriverAdapter
|
|||
Finder finder, {
|
||||
Duration? timeout = const Duration(seconds: 30),
|
||||
}) async {
|
||||
await waitForAppToSettle(timeout: timeout);
|
||||
await _implicitWait(timeout: timeout);
|
||||
|
||||
final instance = await widget(finder);
|
||||
if (instance is Text) {
|
||||
|
@ -109,7 +125,7 @@ class WidgetTesterAppDriverAdapter
|
|||
finder,
|
||||
text,
|
||||
);
|
||||
await waitForAppToSettle(
|
||||
await _implicitWait(
|
||||
timeout: timeout,
|
||||
);
|
||||
}
|
||||
|
@ -120,7 +136,7 @@ class WidgetTesterAppDriverAdapter
|
|||
Duration? timeout = const Duration(seconds: 30),
|
||||
}) async {
|
||||
await nativeDriver.tap(finder);
|
||||
await waitForAppToSettle(
|
||||
await _implicitWait(
|
||||
timeout: timeout,
|
||||
);
|
||||
}
|
||||
|
@ -138,7 +154,7 @@ class WidgetTesterAppDriverAdapter
|
|||
duration: pressDuration,
|
||||
timeout: timeout,
|
||||
);
|
||||
await waitForAppToSettle(timeout: timeout);
|
||||
await _implicitWait(timeout: timeout);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -233,6 +249,6 @@ class WidgetTesterAppDriverAdapter
|
|||
@override
|
||||
Future<void> pageBack() async {
|
||||
await nativeDriver.pageBack();
|
||||
await waitForAppToSettle();
|
||||
await _implicitWait();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,11 +11,11 @@ import 'package:source_gen/source_gen.dart';
|
|||
class NoOpReporter extends MessageReporter {
|
||||
@override
|
||||
Future<void> message(String message, MessageLevel level) async {
|
||||
if(level == MessageLevel.info || level == MessageLevel.debug) {
|
||||
if (level == MessageLevel.info || level == MessageLevel.debug) {
|
||||
print(message);
|
||||
}else if(level == MessageLevel.warning) {
|
||||
} else if (level == MessageLevel.warning) {
|
||||
print('\x1B[33m$message\x1B[0m');
|
||||
}else if(level == MessageLevel.error) {
|
||||
} else if (level == MessageLevel.error) {
|
||||
print('\x1B[31m$message\x1B[0m');
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ void executeTestSuite(
|
|||
.getField('index')!
|
||||
.toIntValue()!;
|
||||
final executionOrder = ExecutionOrder.values[idx];
|
||||
final featureFiles = annotation
|
||||
final featureFiles = annotation
|
||||
.read('featurePaths')
|
||||
.listValue
|
||||
.map((path) => Glob(path.toStringValue()!))
|
||||
|
@ -139,9 +139,10 @@ class FeatureFileTestGeneratorVisitor extends FeatureFileVisitor {
|
|||
''';
|
||||
static const String SCENARIO_TEMPLATE = '''
|
||||
runScenario(
|
||||
'{{scenario_name}}',
|
||||
{{tags}},
|
||||
[
|
||||
name: '{{scenario_name}}',
|
||||
path: '{{path}}',
|
||||
tags:{{tags}},
|
||||
steps: [
|
||||
{{steps}}
|
||||
],
|
||||
{{onBefore}}
|
||||
|
|
|
@ -1,28 +1,63 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
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_driver/flutter_driver.dart';
|
||||
import 'package:gherkin/gherkin.dart';
|
||||
|
||||
import 'flutter_test_configuration.dart';
|
||||
|
||||
class FlutterDriverTestConfiguration extends FlutterTestConfiguration {
|
||||
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
|
||||
/// Additional setting on the configuration object can be set on the returned instance.
|
||||
static FlutterDriverTestConfiguration DEFAULT(
|
||||
Iterable<StepDefinitionGeneric<World>> steps, {
|
||||
String featurePath = 'features/*.*.feature',
|
||||
String targetAppPath = 'test_driver/app.dart',
|
||||
String? targetAppWorkingDirectory,
|
||||
bool restartAppBetweenScenarios = true,
|
||||
}) {
|
||||
return FlutterDriverTestConfiguration()
|
||||
..features = [RegExp(featurePath)]
|
||||
..reporters = [
|
||||
return FlutterDriverTestConfiguration(
|
||||
features: [RegExp(featurePath)],
|
||||
reporters: [
|
||||
StdoutReporter(MessageLevel.error),
|
||||
ProgressReporter(),
|
||||
TestRunSummaryReporter(),
|
||||
|
@ -32,81 +67,84 @@ class FlutterDriverTestConfiguration extends FlutterTestConfiguration {
|
|||
logInfoMessages: false,
|
||||
logWarningMessages: false,
|
||||
),
|
||||
]
|
||||
..targetAppPath = targetAppPath
|
||||
..stepDefinitions = steps
|
||||
..restartAppBetweenScenarios = true;
|
||||
],
|
||||
targetAppPath: targetAppPath,
|
||||
targetAppWorkingDirectory: targetAppWorkingDirectory,
|
||||
stepDefinitions: steps,
|
||||
restartAppBetweenScenarios: restartAppBetweenScenarios,
|
||||
);
|
||||
}
|
||||
|
||||
/// restarts the application under test between each scenario.
|
||||
/// Defaults to true to avoid the application being in an invalid state
|
||||
/// before each test
|
||||
bool restartAppBetweenScenarios = true;
|
||||
final bool restartAppBetweenScenarios;
|
||||
|
||||
/// The target app to run the tests against
|
||||
/// 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)
|
||||
/// 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)
|
||||
/// Defaults to null
|
||||
String? buildFlavor;
|
||||
final String? buildFlavor;
|
||||
|
||||
/// The default build mode used for running tests is --debug.
|
||||
/// 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
|
||||
/// Defaults to true
|
||||
bool build = true;
|
||||
final bool build;
|
||||
|
||||
/// The target device id to run the tests against when multiple devices detected
|
||||
/// Defaults to null
|
||||
String? targetDeviceId;
|
||||
final String? targetDeviceId;
|
||||
|
||||
/// Will keep the Flutter application running when done testing
|
||||
/// Defaults to false
|
||||
bool keepAppRunningAfterTests = false;
|
||||
final bool keepAppRunningAfterTests;
|
||||
|
||||
/// Logs Flutter process output to stdout
|
||||
/// The Flutter process is use to start and driver the app under test.
|
||||
/// The output may contain build and run information
|
||||
/// Defaults to false
|
||||
bool logFlutterProcessOutput = false;
|
||||
final bool logFlutterProcessOutput;
|
||||
|
||||
/// Sets the --verbose flag on the flutter process
|
||||
/// Defaults to false
|
||||
bool verboseFlutterProcessLogs = false;
|
||||
final bool verboseFlutterProcessLogs;
|
||||
|
||||
/// 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
|
||||
/// Defaults to 90 seconds
|
||||
Duration flutterBuildTimeout = const Duration(seconds: 90);
|
||||
final Duration flutterBuildTimeout;
|
||||
|
||||
/// 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
|
||||
/// 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
|
||||
/// 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
|
||||
/// 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
|
||||
String? runningAppProtocolEndpointUri;
|
||||
final String? runningAppProtocolEndpointUri;
|
||||
|
||||
/// 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.
|
||||
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
|
||||
/// 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;
|
||||
|
||||
|
@ -157,20 +195,41 @@ class FlutterDriverTestConfiguration extends FlutterTestConfiguration {
|
|||
}
|
||||
|
||||
@override
|
||||
void prepare() {
|
||||
TestConfiguration prepare() {
|
||||
super.prepare();
|
||||
_ensureCorrectConfiguration();
|
||||
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(
|
||||
|
|
|
@ -1,34 +1,50 @@
|
|||
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/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/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_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:gherkin/gherkin.dart';
|
||||
|
||||
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].
|
||||
/// 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
|
||||
/// Additional setting on the configuration object can be set on the returned instance.
|
||||
static FlutterTestConfiguration DEFAULT(
|
||||
|
@ -36,49 +52,38 @@ class FlutterTestConfiguration extends TestConfiguration {
|
|||
String featurePath = 'integration_test/features/*.*.feature',
|
||||
String targetAppPath = 'test_driver/integration_test_driver.dart',
|
||||
}) {
|
||||
return FlutterTestConfiguration()
|
||||
..reporters = [
|
||||
return FlutterTestConfiguration(
|
||||
reporters: [
|
||||
StdoutReporter(MessageLevel.error),
|
||||
ProgressReporter(),
|
||||
TestRunSummaryReporter(),
|
||||
// JsonReporter(path: './report.json'),
|
||||
]
|
||||
..stepDefinitions = steps;
|
||||
],
|
||||
stepDefinitions: steps,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void prepare() {
|
||||
customStepParameterDefinitions =
|
||||
List.from(customStepParameterDefinitions ?? Iterable.empty())
|
||||
..addAll([
|
||||
ExistenceParameter(),
|
||||
SwipeDirectionParameter(),
|
||||
]);
|
||||
stepDefinitions = List.from(stepDefinitions ?? Iterable.empty())
|
||||
..addAll([
|
||||
ThenExpectElementToHaveValue(),
|
||||
WhenTapBackButtonWidget(),
|
||||
WhenTapWidget(),
|
||||
WhenTapWidgetWithoutScroll(),
|
||||
WhenLongPressWidget(),
|
||||
WhenLongPressWidgetWithoutScroll(),
|
||||
WhenLongPressWidgetForDuration(),
|
||||
GivenOpenDrawer(),
|
||||
WhenPauseStep(),
|
||||
WhenFillFieldStep(),
|
||||
ThenExpectWidgetToBePresent(),
|
||||
RestartAppStep(),
|
||||
SiblingContainsTextStep(),
|
||||
SwipeOnKeyStep(),
|
||||
SwipeOnTextStep(),
|
||||
TapTextWithinWidgetStep(),
|
||||
TapWidgetOfTypeStep(),
|
||||
TapWidgetOfTypeWithinStep(),
|
||||
TapWidgetWithTextStep(),
|
||||
TextExistsStep(),
|
||||
TextExistsWithinStep(),
|
||||
WaitUntilKeyExistsStep(),
|
||||
WaitUntilTypeExistsStep(),
|
||||
]);
|
||||
}
|
||||
FlutterTestConfiguration({
|
||||
super.features = const <Pattern>[],
|
||||
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,
|
||||
this.semanticsEnabled = true,
|
||||
this.waitImplicitlyAfterAction = false,
|
||||
Iterable<CustomParameter<dynamic>>? customStepParameterDefinitions,
|
||||
Iterable<StepDefinitionGeneric<World>>? stepDefinitions,
|
||||
}) : super(
|
||||
customStepParameterDefinitions:
|
||||
List.from(customStepParameterDefinitions ?? Iterable.empty())
|
||||
..addAll(_wellKnownParameters),
|
||||
stepDefinitions: List.from(stepDefinitions ?? Iterable.empty())
|
||||
..addAll(_wellKnownStepDefinitions),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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/runners/flutter_run_process_handler.dart';
|
||||
import 'package:flutter_gherkin/src/flutter/world/flutter_driver_world.dart';
|
||||
|
@ -38,9 +38,9 @@ class FlutterAppRunnerHook extends Hook {
|
|||
Future<void> onAfterScenario(
|
||||
TestConfiguration config,
|
||||
String scenario,
|
||||
Iterable<Tag> tags,
|
||||
{bool? passed,}
|
||||
) async {
|
||||
Iterable<Tag> tags, {
|
||||
bool? passed,
|
||||
}) async {
|
||||
final flutterConfig = _castConfig(config);
|
||||
haveRunFirstScenario = true;
|
||||
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
|
||||
/// 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.
|
||||
class FlutterDriverReporter extends Reporter {
|
||||
class FlutterDriverReporter extends Reporter
|
||||
implements DisposableReporter, TestReporter {
|
||||
final bool logErrorMessages;
|
||||
final bool logWarningMessages;
|
||||
final bool logInfoMessages;
|
||||
|
||||
DriverLogCallback? defaultCallback;
|
||||
|
||||
FlutterDriverReporter({
|
||||
this.logErrorMessages = true,
|
||||
this.logWarningMessages = true,
|
||||
|
@ -25,13 +28,18 @@ class FlutterDriverReporter extends Reporter {
|
|||
});
|
||||
|
||||
@override
|
||||
Future<void> onTestRunStarted() async {
|
||||
driverLog = _driverLogMessageHandler;
|
||||
}
|
||||
ReportActionHandler<TestMessage> get test => ReportActionHandler(
|
||||
onStarted: ([_]) async {
|
||||
defaultCallback = driverLog;
|
||||
driverLog = _driverLogMessageHandler;
|
||||
},
|
||||
);
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
// driverLog = null;
|
||||
if (defaultCallback != null) {
|
||||
driverLog = defaultCallback!;
|
||||
}
|
||||
}
|
||||
|
||||
void _driverLogMessageHandler(String source, String message) {
|
||||
|
|
|
@ -49,8 +49,7 @@ abstract class GherkinIntegrationTestRunner {
|
|||
}
|
||||
|
||||
Future<void> run() async {
|
||||
_binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized()
|
||||
as IntegrationTestWidgetsFlutterBinding;
|
||||
_binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
_binding!.framePolicy =
|
||||
framePolicy ?? LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive;
|
||||
|
@ -77,10 +76,8 @@ abstract class GherkinIntegrationTestRunner {
|
|||
}
|
||||
|
||||
void setTestResultData(IntegrationTestWidgetsFlutterBinding binding) {
|
||||
if (reporter is SerializableReporter) {
|
||||
final json = (reporter as SerializableReporter).serialize();
|
||||
binding.reportData = {'gherkin_reports': json};
|
||||
}
|
||||
final json = (reporter).serialize();
|
||||
binding.reportData = {'gherkin_reports': json};
|
||||
}
|
||||
|
||||
@protected
|
||||
|
@ -115,10 +112,7 @@ abstract class GherkinIntegrationTestRunner {
|
|||
}
|
||||
|
||||
@protected
|
||||
Future<void> onAfterRunFeature(
|
||||
String name,
|
||||
String path
|
||||
) async {
|
||||
Future<void> onAfterRunFeature(String name, String path) async {
|
||||
final debugInformation = RunnableDebugInformation(path, 0, name);
|
||||
await reporter.test.onFinished.maybeCall(
|
||||
TestMessage(
|
||||
|
@ -130,11 +124,16 @@ abstract class GherkinIntegrationTestRunner {
|
|||
}
|
||||
|
||||
@protected
|
||||
void runScenario(
|
||||
String name,
|
||||
Iterable<String>? tags,
|
||||
List<Future<StepResult> Function(TestDependencies dependencies, bool skip,)>
|
||||
steps, String path, {
|
||||
void runScenario({
|
||||
required String name,
|
||||
required Iterable<String>? tags,
|
||||
required List<
|
||||
Future<StepResult> Function(
|
||||
TestDependencies dependencies,
|
||||
bool skip,
|
||||
)>
|
||||
steps,
|
||||
required String path,
|
||||
Future<void> Function()? onBefore,
|
||||
Future<void> Function()? onAfter,
|
||||
}) {
|
||||
|
@ -257,7 +256,15 @@ abstract class GherkinIntegrationTestRunner {
|
|||
world = world ?? FlutterWidgetTesterWorld();
|
||||
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(
|
||||
world,
|
||||
|
@ -266,8 +273,13 @@ abstract class GherkinIntegrationTestRunner {
|
|||
}
|
||||
|
||||
@protected
|
||||
Future<StepResult> runStep(String step, Iterable<String> multiLineStrings,
|
||||
dynamic table, TestDependencies dependencies, bool hasToSkip,) async {
|
||||
Future<StepResult> runStep(
|
||||
String step,
|
||||
Iterable<String> multiLineStrings,
|
||||
dynamic table,
|
||||
TestDependencies dependencies,
|
||||
bool hasToSkip,
|
||||
) async {
|
||||
final executable = _executableSteps!.firstWhereOrNull(
|
||||
(s) => s.expression.isMatch(step),
|
||||
);
|
||||
|
@ -294,8 +306,8 @@ abstract class GherkinIntegrationTestRunner {
|
|||
StepResult? result;
|
||||
|
||||
if (hasToSkip) {
|
||||
result = new StepResult(
|
||||
0, StepExecutionResult.skipped, resultReason: "Previous step(s) failed.");
|
||||
result = new StepResult(0, StepExecutionResult.skipped,
|
||||
resultReason: "Previous step(s) failed.");
|
||||
} else {
|
||||
for (int i = 0; i < this.configuration.stepMaxRetries + 1; i++) {
|
||||
result = await executable.step.run(
|
||||
|
@ -426,7 +438,9 @@ abstract class GherkinIntegrationTestRunner {
|
|||
name: step,
|
||||
context: RunnableDebugInformation('', 0, step),
|
||||
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/src/flutter/adapters/app_driver_adapter.dart';
|
||||
import 'package:flutter_gherkin/src/flutter/world/flutter_world.dart';
|
||||
import 'package:gherkin/gherkin.dart';
|
||||
|
||||
/// 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/src/flutter/world/flutter_world.dart';
|
||||
import 'package:gherkin/gherkin.dart';
|
||||
|
||||
import '../parameters/swipe_direction_parameter.dart';
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
||||
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
|
||||
import 'package:gherkin/gherkin.dart';
|
||||
|
||||
/// Taps a widget that contains the text within another widget.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
||||
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
|
||||
import 'package:gherkin/gherkin.dart';
|
||||
|
||||
/// Taps a widget of type.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
||||
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
|
||||
import 'package:gherkin/gherkin.dart';
|
||||
|
||||
/// Taps a widget of type within another widget.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
||||
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
|
||||
import 'package:gherkin/gherkin.dart';
|
||||
|
||||
/// Taps a widget that contains text.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
||||
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
|
||||
import 'package:gherkin/gherkin.dart';
|
||||
|
||||
import '../parameters/existence_parameter.dart';
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
||||
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
|
||||
import 'package:gherkin/gherkin.dart';
|
||||
|
||||
import '../parameters/existence_parameter.dart';
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
||||
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
|
||||
import 'package:gherkin/gherkin.dart';
|
||||
|
||||
import '../parameters/existence_parameter.dart';
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter_gherkin/flutter_gherkin.dart';
|
||||
import 'package:flutter_gherkin/src/flutter/adapters/app_driver_adapter.dart';
|
||||
import 'package:gherkin/gherkin.dart';
|
||||
|
||||
import '../parameters/existence_parameter.dart';
|
||||
|
|
37
pubspec.lock
37
pubspec.lock
|
@ -7,14 +7,14 @@ packages:
|
|||
name: _fe_analyzer_shared
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "30.0.0"
|
||||
version: "40.0.0"
|
||||
analyzer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: analyzer
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.7.0"
|
||||
version: "4.1.0"
|
||||
archive:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -28,7 +28,7 @@ packages:
|
|||
name: args
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.3.1"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -49,7 +49,7 @@ packages:
|
|||
name: build
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.3.0"
|
||||
build_config:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
@ -78,13 +78,6 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
cli_util:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cli_util
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.5"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -105,7 +98,7 @@ packages:
|
|||
name: convert
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "3.0.2"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -119,7 +112,7 @@ packages:
|
|||
name: dart_style
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.2.3"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -160,14 +153,14 @@ packages:
|
|||
name: gherkin
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.0.0+1"
|
||||
glob:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: glob
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
version: "2.1.0"
|
||||
integration_test:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
|
@ -179,7 +172,7 @@ packages:
|
|||
name: json_annotation
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.3.0"
|
||||
version: "4.5.0"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -214,7 +207,7 @@ packages:
|
|||
name: package_config
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
version: "2.1.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -249,14 +242,14 @@ packages:
|
|||
name: pub_semver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.1.1"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pubspec_parse
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.2.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
@ -268,7 +261,7 @@ packages:
|
|||
name: source_gen
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
version: "1.2.2"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -366,7 +359,7 @@ packages:
|
|||
name: yaml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.1.1"
|
||||
sdks:
|
||||
dart: ">=2.17.0-0 <3.0.0"
|
||||
dart: ">=2.17.0 <3.0.0"
|
||||
flutter: ">=2.2.0"
|
||||
|
|
10
pubspec.yaml
10
pubspec.yaml
|
@ -1,10 +1,10 @@
|
|||
name: flutter_gherkin
|
||||
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
|
||||
|
||||
environment:
|
||||
sdk: '>=2.12.3 <3.0.0'
|
||||
sdk: '>=2.17.0 <3.0.0'
|
||||
flutter: ">=2.2.0"
|
||||
|
||||
dependencies:
|
||||
|
@ -16,15 +16,15 @@ dependencies:
|
|||
sdk: flutter
|
||||
flutter_driver:
|
||||
sdk: flutter
|
||||
analyzer: ">=1.7.1 <3.0.0"
|
||||
analyzer: '>=2.1.0 < 5.0.0'
|
||||
collection: ^1.15.0
|
||||
gherkin: ^3.0.0
|
||||
gherkin: ^3.0.0+1
|
||||
source_gen: ^1.1.1
|
||||
build: ^2.1.1
|
||||
glob: ^2.0.2
|
||||
|
||||
dev_dependencies:
|
||||
meta: ^1.7.0
|
||||
meta: '>=1.7.0 < 2.0.0'
|
||||
pedantic: ^1.11.1
|
||||
build_config: ^1.0.0
|
||||
|
||||
|
|
|
@ -6,43 +6,37 @@ import 'mocks/step_definition_mock.dart';
|
|||
|
||||
void main() {
|
||||
group('config', () {
|
||||
group('prepare', () {
|
||||
test('flutter app runner hook added', () {
|
||||
final config = FlutterDriverTestConfiguration();
|
||||
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('flutter app runner hook added', () {
|
||||
final config = FlutterDriverTestConfiguration();
|
||||
final newConfig = config.prepare();
|
||||
|
||||
test('common steps definition added', () {
|
||||
final config = FlutterDriverTestConfiguration();
|
||||
expect(config.stepDefinitions, isNull);
|
||||
expect(newConfig.hooks, isNotNull);
|
||||
expect(newConfig.hooks!.length, 1);
|
||||
expect(newConfig.hooks!.elementAt(0), (x) => x is FlutterAppRunnerHook);
|
||||
});
|
||||
|
||||
config.prepare();
|
||||
expect(config.stepDefinitions, isNotNull);
|
||||
expect(config.stepDefinitions!.length, 23);
|
||||
expect(config.customStepParameterDefinitions, isNotNull);
|
||||
expect(config.customStepParameterDefinitions!.length, 2);
|
||||
});
|
||||
test('common steps definition added', () {
|
||||
final config = FlutterDriverTestConfiguration();
|
||||
expect(config.stepDefinitions, isNotNull);
|
||||
expect(config.stepDefinitions!.length, 23);
|
||||
expect(config.customStepParameterDefinitions, isNotNull);
|
||||
expect(config.customStepParameterDefinitions!.length, 2);
|
||||
});
|
||||
|
||||
test('common step definition added to existing steps', () {
|
||||
final config = FlutterTestConfiguration()
|
||||
..stepDefinitions = [MockStepDefinition()]
|
||||
..customStepParameterDefinitions = [MockParameter()];
|
||||
expect(config.stepDefinitions!.length, 1);
|
||||
test('common step definition added to existing steps', () {
|
||||
final config = FlutterTestConfiguration(
|
||||
stepDefinitions: [MockStepDefinition()],
|
||||
customStepParameterDefinitions: [MockParameter()],
|
||||
);
|
||||
|
||||
config.prepare();
|
||||
expect(config.stepDefinitions, isNotNull);
|
||||
expect(config.stepDefinitions!.length, 24);
|
||||
expect(config.stepDefinitions!.elementAt(0),
|
||||
(x) => x is MockStepDefinition);
|
||||
expect(config.customStepParameterDefinitions, isNotNull);
|
||||
expect(config.customStepParameterDefinitions!.length, 3);
|
||||
expect(config.customStepParameterDefinitions!.elementAt(0),
|
||||
(x) => x is MockParameter);
|
||||
});
|
||||
expect(config.stepDefinitions, isNotNull);
|
||||
expect(config.stepDefinitions!.length, 24);
|
||||
expect(
|
||||
config.stepDefinitions!.elementAt(0), (x) => x is MockStepDefinition);
|
||||
expect(config.customStepParameterDefinitions, isNotNull);
|
||||
expect(config.customStepParameterDefinitions!.length, 3);
|
||||
expect(config.customStepParameterDefinitions!.elementAt(0),
|
||||
(x) => x is MockParameter);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue