diff --git a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolJUnitRunner.java b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolJUnitRunner.java index 03c969a7ef..6485ff84c8 100644 --- a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolJUnitRunner.java +++ b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolJUnitRunner.java @@ -10,14 +10,12 @@ import android.os.Bundle; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnitRunner; - import pl.leancode.patrol.contracts.Contracts; import pl.leancode.patrol.contracts.PatrolAppServiceClientException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.concurrent.ExecutionException; import static pl.leancode.patrol.contracts.Contracts.DartGroupEntry; import static pl.leancode.patrol.contracts.Contracts.RunDartTestResponse; @@ -30,6 +28,13 @@ public class PatrolJUnitRunner extends AndroidJUnitRunner { public PatrolAppServiceClient patrolAppServiceClient; + /** + *
+ * Available only after onCreate() has been run. + *
+ */ + protected boolean isInitialRun; + @Override protected boolean shouldWaitForActivitiesToComplete() { return false; @@ -40,10 +45,10 @@ public void onCreate(Bundle arguments) { super.onCreate(arguments); // This is only true when the ATO requests a list of tests from the app during the initial run. - boolean isInitialRun = Boolean.parseBoolean(arguments.getString("listTestsForOrchestrator")); + this.isInitialRun = Boolean.parseBoolean(arguments.getString("listTestsForOrchestrator")); Logger.INSTANCE.i("--------------------------------"); - Logger.INSTANCE.i("PatrolJUnitRunner.onCreate() " + (isInitialRun ? "(initial run)" : "")); + Logger.INSTANCE.i("PatrolJUnitRunner.onCreate() " + (this.isInitialRun ? "(initial run)" : "")); } /** @@ -69,6 +74,7 @@ public void setUp(Class> activityClass) { // Currently, the only synchronization point we're interested in is when the app under test returns the list of tests. Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); Intent intent = new Intent(Intent.ACTION_MAIN); + intent.putExtra("isInitialRun", isInitialRun); intent.setClassName(instrumentation.getTargetContext(), activityClass.getCanonicalName()); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); instrumentation.getTargetContext().startActivity(intent); diff --git a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolPlugin.kt b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolPlugin.kt index 9984204196..e66785585b 100644 --- a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolPlugin.kt +++ b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolPlugin.kt @@ -1,24 +1,52 @@ package pl.leancode.patrol import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.embedding.engine.plugins.activity.ActivityAware +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result -class PatrolPlugin : FlutterPlugin, MethodCallHandler { +class PatrolPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { private lateinit var channel: MethodChannel + private var isInitialRun: Boolean? = null + override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { channel = MethodChannel(flutterPluginBinding.binaryMessenger, "pl.leancode.patrol/main") channel.setMethodCallHandler(this) } override fun onMethodCall(call: MethodCall, result: Result) { - result.notImplemented() + when (call.method) { + "inInitialRun" -> result.success(isInitialRun) + else -> result.notImplemented() + } } override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { channel.setMethodCallHandler(null) } + + override fun onAttachedToActivity(binding: ActivityPluginBinding) { + val intent = binding.activity.intent + if (!intent.hasExtra("isInitialRun")) { + throw IllegalStateException("PatrolPlugin must be initialized with intent having isInitialRun boolean") + } + + isInitialRun = intent.getBooleanExtra("isInitialRun", false) + } + + override fun onDetachedFromActivityForConfigChanges() { + // Do nothing + } + + override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { + // Do nothing + } + + override fun onDetachedFromActivity() { + // Do nothing + } } diff --git a/packages/patrol/lib/src/common.dart b/packages/patrol/lib/src/common.dart index e6d02ff46e..21d100ce0f 100644 --- a/packages/patrol/lib/src/common.dart +++ b/packages/patrol/lib/src/common.dart @@ -141,6 +141,13 @@ void patrolTest( tags: tags, (widgetTester) async { if (!constants.hotRestartEnabled) { + if (await global_state.isInitialRun) { + // Fall through tests during the initial run that discovers tests. + // + // This is required to be able to find all setUpAll callbacks. + return; + } + // If Patrol's native automation feature is enabled, then this test will // be executed only if the native side requested it to be executed. // Otherwise, it returns early. @@ -153,6 +160,7 @@ void patrolTest( return; } } + if (!kIsWeb && io.Platform.isIOS) { widgetTester.binding.platformDispatcher.onSemanticsEnabledChanged = () { // This callback is empty on purpose. It's a workaround for tests diff --git a/packages/patrol/lib/src/global_state.dart b/packages/patrol/lib/src/global_state.dart index 5a8c01df23..81b922c538 100644 --- a/packages/patrol/lib/src/global_state.dart +++ b/packages/patrol/lib/src/global_state.dart @@ -1,4 +1,5 @@ // ignore: implementation_imports +import 'package:flutter/services.dart'; import 'package:test_api/src/backend/invoker.dart'; /// Maximum test case length for ATO, after transformations. @@ -42,3 +43,9 @@ String get currentTestIndividualName { bool get isCurrentTestPassing { return Invoker.current!.liveTest.state.result.isPassing; } + +const _channel = MethodChannel('pl.leancode.patrol/main'); + +Future