detox 20.14.4-prerelease.0 → 20.14.4-smoke.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. package/Detox-android/com/wix/detox/{20.14.4-prerelease.0/detox-20.14.4-prerelease.0-javadoc.jar → 20.14.4-smoke.0/detox-20.14.4-smoke.0-javadoc.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0-javadoc.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0-javadoc.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0-javadoc.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0-javadoc.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.14.4-prerelease.0/detox-20.14.4-prerelease.0-sources.jar → 20.14.4-smoke.0/detox-20.14.4-smoke.0-sources.jar} +0 -0
  7. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0-sources.jar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0-sources.jar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0-sources.jar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0-sources.jar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0.aar +0 -0
  12. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0.aar.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0.aar.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0.aar.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0.aar.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/{20.14.4-prerelease.0/detox-20.14.4-prerelease.0.pom → 20.14.4-smoke.0/detox-20.14.4-smoke.0.pom} +1 -1
  17. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0.pom.md5 +1 -0
  18. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0.pom.sha1 +1 -0
  19. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0.pom.sha256 +1 -0
  20. package/Detox-android/com/wix/detox/20.14.4-smoke.0/detox-20.14.4-smoke.0.pom.sha512 +1 -0
  21. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  22. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  23. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  24. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  25. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  26. package/Detox-ios-src.tbz +0 -0
  27. package/Detox-ios.tbz +0 -0
  28. package/android/detox/proguard-rules-app.pro +1 -2
  29. package/android/detox/src/full/java/com/wix/detox/Detox.java +70 -8
  30. package/android/detox/src/full/java/com/wix/detox/DetoxMain.kt +44 -69
  31. package/android/detox/src/full/java/com/wix/detox/LaunchIntentsFactory.kt +1 -1
  32. package/android/detox/src/full/java/com/wix/detox/NotificationDataParser.kt +1 -1
  33. package/android/detox/src/full/java/com/wix/detox/adapters/server/DetoxActionHandlers.kt +4 -0
  34. package/android/detox/src/full/java/com/wix/detox/adapters/server/DetoxActionsDispatcher.kt +6 -16
  35. package/android/detox/src/full/java/com/wix/detox/adapters/server/DetoxServerAdapter.kt +2 -0
  36. package/android/detox/src/full/java/com/wix/detox/adapters/server/DetoxServerInfo.kt +2 -4
  37. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeExtension.kt +32 -25
  38. package/android/detox/src/main/java/com/wix/detox/espresso/UiControllerSpy.kt +3 -0
  39. package/android/detox/src/testFull/java/com/wix/detox/espresso/matcher/RegexMatcherTest.kt +3 -0
  40. package/package.json +2 -2
  41. package/src/android/espressoapi/Detox.js +11 -0
  42. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0-javadoc.jar.md5 +0 -1
  43. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0-javadoc.jar.sha1 +0 -1
  44. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0-javadoc.jar.sha256 +0 -1
  45. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0-javadoc.jar.sha512 +0 -1
  46. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0-sources.jar.md5 +0 -1
  47. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0-sources.jar.sha1 +0 -1
  48. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0-sources.jar.sha256 +0 -1
  49. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0-sources.jar.sha512 +0 -1
  50. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0.aar +0 -0
  51. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0.aar.md5 +0 -1
  52. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0.aar.sha1 +0 -1
  53. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0.aar.sha256 +0 -1
  54. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0.aar.sha512 +0 -1
  55. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0.pom.md5 +0 -1
  56. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0.pom.sha1 +0 -1
  57. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0.pom.sha256 +0 -1
  58. package/Detox-android/com/wix/detox/20.14.4-prerelease.0/detox-20.14.4-prerelease.0.pom.sha512 +0 -1
  59. package/android/detox/src/full/java/com/wix/detox/ActivityLaunchHelper.kt +0 -78
  60. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactMarkersLogger.kt +0 -44
  61. package/android/detox/src/testFull/java/com/wix/detox/ActivityLaunchHelperTest.kt +0 -111
@@ -0,0 +1 @@
1
+ 3d0b64bdd6e7a436ee911d1418503a6d
@@ -0,0 +1 @@
1
+ 6635f90d741216b5aa76b5032514ba9784e4c671
@@ -0,0 +1 @@
1
+ b4b6831643b10e07a874aa90546f704478697908361c10679b4fb03f070ea287
@@ -0,0 +1 @@
1
+ 335d6a60ba8ac361a6404f631e0a2b1ba07a1e823dfe606fc35d28100516bd2a0eb727097d9c648b801192d6f5a0fcc61c6435a8e459ba0c7d83de435af4b255
@@ -0,0 +1 @@
1
+ f5c0348c6cf33679d63e5f79a4cb7be9
@@ -0,0 +1 @@
1
+ 4289a96b2a89d2d1ac3299142c65d7cbe7f7126d
@@ -0,0 +1 @@
1
+ e8f3230b45eb8950baa3400408ef9e21a5d0d61275fb63bffdfa11f97298a68f
@@ -0,0 +1 @@
1
+ f3420efb7574cee763513971f8a6753d72ad2aa47a479a825f321ae8c3bf98680b42bf5d9c1c37edcf6aa8528581a65ac8ee2ea0ef0f04682a5c693d2397eb62
@@ -0,0 +1 @@
1
+ 070f7c4048400fe1d6b1599414f5c7f1
@@ -0,0 +1 @@
1
+ 52ebf8f7cd97ab4d28216ce8504635be1f74b57c
@@ -0,0 +1 @@
1
+ 42299d1835b5db9fe3b7523d2d656a8834fff583ae82521ff69b9e050814ce3a
@@ -0,0 +1 @@
1
+ aeecbc2448822395dc7d9674c0a30f5cffd9cacd8361bd55a1a4f0bb8cafe82cb812fbe1da890395cfcc65439dcb4666e119a356a054c582cb7dfe225fb9d858
@@ -3,7 +3,7 @@
3
3
  <modelVersion>4.0.0</modelVersion>
4
4
  <groupId>com.wix</groupId>
5
5
  <artifactId>detox</artifactId>
6
- <version>20.14.4-prerelease.0</version>
6
+ <version>20.14.4-smoke.0</version>
7
7
  <packaging>aar</packaging>
8
8
  <name>Detox</name>
9
9
  <description>Gray box end-to-end testing and automation library for mobile apps</description>
@@ -0,0 +1 @@
1
+ 0fc89c4edda6315cb57a7cf8e97f90dc
@@ -0,0 +1 @@
1
+ f3fe5b9e1063318f207d7c185d19ecbe21a84f6d
@@ -0,0 +1 @@
1
+ ba3399fb186167a3d399cb00c12f39db8597fc00c5ca269e6ae98fd8af8dd4eb
@@ -0,0 +1 @@
1
+ 34e9d1dc0267749af9e4cba6899b3c75e0275f16edca353e9d52fbc07a8f1582aeebead081595c7794fd8bbb37680870e7281a9f4d249be3de73dec508a41ce8
@@ -3,11 +3,11 @@
3
3
  <groupId>com.wix</groupId>
4
4
  <artifactId>detox</artifactId>
5
5
  <versioning>
6
- <latest>20.14.4-prerelease.0</latest>
7
- <release>20.14.4-prerelease.0</release>
6
+ <latest>20.14.4-smoke.0</latest>
7
+ <release>20.14.4-smoke.0</release>
8
8
  <versions>
9
- <version>20.14.4-prerelease.0</version>
9
+ <version>20.14.4-smoke.0</version>
10
10
  </versions>
11
- <lastUpdated>20231220153927</lastUpdated>
11
+ <lastUpdated>20231221025706</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- 5c1d4e12b1f2f774d7def161e3e3f9fd
1
+ 891c5308c9e49fc080cb14e82d7e6919
@@ -1 +1 @@
1
- 521a576afd0a6a16928fa14bc3617db7c115a3bb
1
+ 30bbc998cdcd5633acd13644f592f971a142dc3f
@@ -1 +1 @@
1
- d55edad08d5fd0a9b2a1b5be751106328267e2dd68874a1d6132dcdad7ec07ac
1
+ b12dc7fa9e99b2896286d020a9d7386a8321f19c8a1e6872dbf51d40ae4d45f7
@@ -1 +1 @@
1
- 161ddacaad8efff1a7023cc0bc8d6ba62333aed51b3a93994415fba1ead902d165e87c8b9d57f73c3b148c601c26a97b791b583a96001103a49e307954f0a4d5
1
+ 39aeb05537af1b3f2b2124fe5c0775c21f6a682770ee478874a0c845cea3ccf4a68bbab568d0249a1942d5be71edc0d05355484018cdb93da4fadc733a82de23
package/Detox-ios-src.tbz CHANGED
Binary file
package/Detox-ios.tbz CHANGED
Binary file
@@ -20,5 +20,4 @@
20
20
  -keep class kotlin.io.** { *; }
21
21
  -keep class okhttp3.** { *; }
22
22
 
23
- -keep class androidx.concurrent.futures.CallbackToFutureAdapter$* { *; }
24
- -keep class androidx.concurrent.futures.CallbackToFutureAdapter { *; }
23
+ -keep class androidx.concurrent.futures.** { *; }
@@ -1,13 +1,18 @@
1
1
  package com.wix.detox;
2
2
 
3
+ import android.app.Activity;
4
+ import android.app.Instrumentation;
3
5
  import android.content.Context;
6
+ import android.content.Intent;
7
+ import android.os.Bundle;
8
+
9
+ import com.wix.detox.config.DetoxConfig;
10
+ import com.wix.detox.espresso.UiControllerSpy;
4
11
 
5
12
  import androidx.annotation.NonNull;
6
13
  import androidx.test.platform.app.InstrumentationRegistry;
7
14
  import androidx.test.rule.ActivityTestRule;
8
15
 
9
- import com.wix.detox.config.DetoxConfig;
10
-
11
16
  /**
12
17
  * <p>Static class.</p>
13
18
  *
@@ -62,7 +67,12 @@ import com.wix.detox.config.DetoxConfig;
62
67
  * <p>If not set, then Detox tests are no ops. So it's safe to mix it with other tests.</p>
63
68
  */
64
69
  public final class Detox {
65
- private static ActivityLaunchHelper sActivityLaunchHelper;
70
+ private static final String INTENT_LAUNCH_ARGS_KEY = "launchArgs";
71
+ private static final long ACTIVITY_LAUNCH_TIMEOUT = 10000L;
72
+
73
+ private static final LaunchArgs sLaunchArgs = new LaunchArgs();
74
+ private static final LaunchIntentsFactory sIntentsFactory = new LaunchIntentsFactory();
75
+ private static ActivityTestRule sActivityTestRule;
66
76
 
67
77
  private Detox() {
68
78
  }
@@ -122,20 +132,72 @@ public final class Detox {
122
132
  DetoxConfig.CONFIG = detoxConfig;
123
133
  DetoxConfig.CONFIG.apply();
124
134
 
125
- sActivityLaunchHelper = new ActivityLaunchHelper(activityTestRule);
126
- DetoxMain.run(context, sActivityLaunchHelper);
135
+ sActivityTestRule = activityTestRule;
136
+
137
+ UiControllerSpy.attachThroughProxy();
138
+
139
+ Intent intent = extractInitialIntent();
140
+ sActivityTestRule.launchActivity(intent);
141
+
142
+ try {
143
+ DetoxMain.run(context);
144
+ } catch (Exception e) {
145
+ Thread.currentThread().interrupt();
146
+ throw new RuntimeException("Detox got interrupted prematurely", e);
147
+ }
127
148
  }
128
149
 
129
150
  public static void launchMainActivity() {
130
- sActivityLaunchHelper.launchMainActivity();
151
+ final Activity activity = sActivityTestRule.getActivity();
152
+ launchActivitySync(sIntentsFactory.activityLaunchIntent(activity));
131
153
  }
132
154
 
133
155
  public static void startActivityFromUrl(String url) {
134
- sActivityLaunchHelper.startActivityFromUrl(url);
156
+ launchActivitySync(sIntentsFactory.intentWithUrl(url, false));
135
157
  }
136
158
 
137
159
  public static void startActivityFromNotification(String dataFilePath) {
138
- sActivityLaunchHelper.startActivityFromNotification(dataFilePath);
160
+ Bundle notificationData = new NotificationDataParser(dataFilePath).toBundle();
161
+ Intent intent = sIntentsFactory.intentWithNotificationData(getAppContext(), notificationData, false);
162
+ launchActivitySync(intent);
163
+ }
164
+
165
+ private static Intent extractInitialIntent() {
166
+ Intent intent;
167
+
168
+ if (sLaunchArgs.hasUrlOverride()) {
169
+ intent = sIntentsFactory.intentWithUrl(sLaunchArgs.getUrlOverride(), true);
170
+ } else if (sLaunchArgs.hasNotificationPath()) {
171
+ Bundle notificationData = new NotificationDataParser(sLaunchArgs.getNotificationPath()).toBundle();
172
+ intent = sIntentsFactory.intentWithNotificationData(getAppContext(), notificationData, true);
173
+ } else {
174
+ intent = sIntentsFactory.cleanIntent();
175
+ }
176
+ intent.putExtra(INTENT_LAUNCH_ARGS_KEY, sLaunchArgs.asIntentBundle());
177
+ return intent;
178
+ }
179
+
180
+ private static void launchActivitySync(Intent intent) {
181
+ // Ideally, we would just call sActivityTestRule.launchActivity(intent) and get it over with.
182
+ // BUT!!! as it turns out, Espresso has an issue where doing this for an activity running in the background
183
+ // would have Espresso set up an ActivityMonitor which will spend its time waiting for the activity to load, *without
184
+ // ever being released*. It will finally fail after a 45 seconds timeout.
185
+ // Without going into full details, it seems that activity test rules were not meant to be used this way. However,
186
+ // the all-new ActivityScenario implementation introduced in androidx could probably support this (e.g. by using
187
+ // dedicated methods such as moveToState(), which give better control over the lifecycle).
188
+ // In any case, this is the core reason for this issue: https://github.com/wix/Detox/issues/1125
189
+ // What it forces us to do, then, is this -
190
+ // 1. Launch the activity by "ourselves" from the OS (i.e. using context.startActivity()).
191
+ // 2. Set up an activity monitor by ourselves -- such that it would block until the activity is ready.
192
+ // ^ Hence the code below.
193
+
194
+ final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
195
+ final Activity activity = sActivityTestRule.getActivity();
196
+ final Instrumentation.ActivityMonitor activityMonitor = new Instrumentation.ActivityMonitor(activity.getClass().getName(), null, true);
197
+
198
+ activity.startActivity(intent);
199
+ instrumentation.addMonitor(activityMonitor);
200
+ instrumentation.waitForMonitorWithTimeout(activityMonitor, ACTIVITY_LAUNCH_TIMEOUT);
139
201
  }
140
202
 
141
203
  private static Context getAppContext() {
@@ -3,62 +3,35 @@ package com.wix.detox
3
3
  import android.content.Context
4
4
  import android.util.Log
5
5
  import com.wix.detox.adapters.server.*
6
- import com.wix.detox.common.DetoxLog
7
- import com.wix.detox.espresso.UiControllerSpy
6
+ import com.wix.detox.common.DetoxLog.Companion.LOG_TAG
8
7
  import com.wix.detox.instruments.DetoxInstrumentsManager
9
8
  import com.wix.detox.reactnative.ReactNativeExtension
10
9
  import com.wix.invoke.MethodInvocation
11
- import java.util.concurrent.CountDownLatch
12
10
 
11
+ private const val INIT_ACTION = "_init"
12
+ private const val IS_READY_ACTION = "isReady"
13
13
  private const val TERMINATION_ACTION = "_terminate"
14
14
 
15
15
  object DetoxMain {
16
- private val handshakeLock = CountDownLatch(1)
17
-
18
16
  @JvmStatic
19
- fun run(rnHostHolder: Context, activityLaunchHelper: ActivityLaunchHelper) {
17
+ fun run(rnHostHolder: Context) {
20
18
  val detoxServerInfo = DetoxServerInfo()
19
+ Log.i(LOG_TAG, "Detox server connection details: $detoxServerInfo")
20
+
21
21
  val testEngineFacade = TestEngineFacade()
22
22
  val actionsDispatcher = DetoxActionsDispatcher()
23
- val serverAdapter = DetoxServerAdapter(actionsDispatcher, detoxServerInfo, TERMINATION_ACTION)
24
-
25
- initCrashHandler(serverAdapter)
26
- initANRListener(serverAdapter)
27
- initEspresso()
28
- initReactNative()
29
-
30
- setupActionHandlers(actionsDispatcher, serverAdapter, testEngineFacade, rnHostHolder)
31
- serverAdapter.connect()
32
-
33
- launchActivityOnCue(rnHostHolder, activityLaunchHelper)
23
+ val externalAdapter = DetoxServerAdapter(actionsDispatcher, detoxServerInfo, IS_READY_ACTION, TERMINATION_ACTION)
24
+ initActionHandlers(actionsDispatcher, externalAdapter, testEngineFacade, rnHostHolder)
25
+ actionsDispatcher.dispatchAction(INIT_ACTION, "", 0)
34
26
  actionsDispatcher.join()
35
27
  }
36
28
 
37
- /**
38
- * Launch the tested activity "on cue", namely, right after a connection is established and the handshake
39
- * completes successfully.
40
- *
41
- * This has to be synchronized so that an `isReady` isn't handled *before* the activity is launched (albeit not fully
42
- * initialized - all native modules and everything) and a react context is available.
43
- *
44
- * As a better alternative, it would make sense to execute this as a simple action from within the actions
45
- * dispatcher (i.e. handler of `loginSuccess`), in which case, no inter-thread locking would be required
46
- * thanks to the usage of Handlers. However, in this type of a solution, errors / crashes would be reported
47
- * not by instrumentation itself, but based on the `AppWillTerminateWithError` message; In it's own, it is a good
48
- * thing, but for a reason we're not sure of yet, it is ignored by the test runner at this point in the flow.
49
- */
50
- @Synchronized
51
- private fun launchActivityOnCue(rnHostHolder: Context, activityLaunchHelper: ActivityLaunchHelper) {
52
- awaitHandshake()
53
- launchActivity(rnHostHolder, activityLaunchHelper)
54
- }
55
-
56
- private fun awaitHandshake() {
57
- handshakeLock.await()
58
- }
29
+ private fun doInit(externalAdapter: DetoxServerAdapter, rnHostHolder: Context) {
30
+ externalAdapter.connect()
59
31
 
60
- private fun onLoginSuccess() {
61
- handshakeLock.countDown()
32
+ initCrashHandler(externalAdapter)
33
+ initANRListener(externalAdapter)
34
+ initReactNativeIfNeeded(rnHostHolder)
62
35
  }
63
36
 
64
37
  private fun doTeardown(serverAdapter: DetoxServerAdapter, actionsDispatcher: DetoxActionsDispatcher, testEngineFacade: TestEngineFacade) {
@@ -68,28 +41,35 @@ object DetoxMain {
68
41
  actionsDispatcher.teardown()
69
42
  }
70
43
 
71
- private fun setupActionHandlers(actionsDispatcher: DetoxActionsDispatcher, serverAdapter: DetoxServerAdapter, testEngineFacade: TestEngineFacade, rnHostHolder: Context) {
72
- class SynchronizedActionHandler(private val actionHandler: DetoxActionHandler): DetoxActionHandler {
73
- override fun handle(params: String, messageId: Long) {
74
- synchronized(this@DetoxMain) {
75
- actionHandler.handle(params, messageId)
76
- }
77
- }
78
- }
79
-
44
+ private fun initActionHandlers(actionsDispatcher: DetoxActionsDispatcher, serverAdapter: DetoxServerAdapter, testEngineFacade: TestEngineFacade, rnHostHolder: Context) {
80
45
  // Primary actions
81
46
  with(actionsDispatcher) {
82
- val readyHandler = SynchronizedActionHandler( ReadyActionHandler(serverAdapter, testEngineFacade) )
83
- val rnReloadHandler = SynchronizedActionHandler( ReactNativeReloadActionHandler(rnHostHolder, serverAdapter, testEngineFacade) )
47
+ val rnReloadHandler = ReactNativeReloadActionHandler(rnHostHolder, serverAdapter, testEngineFacade)
84
48
 
85
- associateActionHandler("loginSuccess", ::onLoginSuccess)
86
- associateActionHandler("isReady", readyHandler)
87
- associateActionHandler("reactNativeReload", rnReloadHandler)
49
+ associateActionHandler(INIT_ACTION, object : DetoxActionHandler {
50
+ override fun handle(params: String, messageId: Long) =
51
+ synchronized(this@DetoxMain) {
52
+ this@DetoxMain.doInit(serverAdapter, rnHostHolder)
53
+ }
54
+ })
55
+ associateActionHandler(IS_READY_ACTION, ReadyActionHandler(serverAdapter, testEngineFacade))
56
+
57
+ associateActionHandler("loginSuccess", ScarceActionHandler())
58
+ associateActionHandler("reactNativeReload", object: DetoxActionHandler {
59
+ override fun handle(params: String, messageId: Long) =
60
+ synchronized(this@DetoxMain) {
61
+ rnReloadHandler.handle(params, messageId)
62
+ }
63
+ })
88
64
  associateActionHandler("invoke", InvokeActionHandler(MethodInvocation(), serverAdapter))
89
65
  associateActionHandler("cleanup", CleanupActionHandler(serverAdapter, testEngineFacade) {
90
66
  dispatchAction(TERMINATION_ACTION, "", 0)
91
67
  })
92
- associateActionHandler(TERMINATION_ACTION) { -> doTeardown(serverAdapter, actionsDispatcher, testEngineFacade) }
68
+ associateActionHandler(TERMINATION_ACTION, object: DetoxActionHandler {
69
+ override fun handle(params: String, messageId: Long) {
70
+ this@DetoxMain.doTeardown(serverAdapter, actionsDispatcher, testEngineFacade)
71
+ }
72
+ })
93
73
 
94
74
  if (DetoxInstrumentsManager.supports()) {
95
75
  val instrumentsManager = DetoxInstrumentsManager(rnHostHolder)
@@ -100,8 +80,13 @@ object DetoxMain {
100
80
 
101
81
  // Secondary actions
102
82
  with(actionsDispatcher) {
103
- val queryStatusHandler = SynchronizedActionHandler( QueryStatusActionHandler(serverAdapter, testEngineFacade) )
104
- associateSecondaryActionHandler("currentStatus", queryStatusHandler)
83
+ val queryStatusHandler = QueryStatusActionHandler(serverAdapter, testEngineFacade)
84
+ associateActionHandler("currentStatus", object: DetoxActionHandler {
85
+ override fun handle(params: String, messageId: Long) =
86
+ synchronized(this@DetoxMain) {
87
+ queryStatusHandler.handle(params, messageId)
88
+ }
89
+ }, false)
105
90
  }
106
91
  }
107
92
 
@@ -113,17 +98,7 @@ object DetoxMain {
113
98
  DetoxANRHandler(outboundServerAdapter).attach()
114
99
  }
115
100
 
116
- private fun initEspresso() {
117
- UiControllerSpy.attachThroughProxy()
118
- }
119
-
120
- private fun initReactNative() {
121
- ReactNativeExtension.initIfNeeded()
122
- }
123
-
124
- private fun launchActivity(rnHostHolder: Context, activityLaunchHelper: ActivityLaunchHelper) {
125
- Log.i(DetoxLog.LOG_TAG, "Launching the tested activity!")
126
- activityLaunchHelper.launchActivityUnderTest()
101
+ private fun initReactNativeIfNeeded(rnHostHolder: Context) {
127
102
  ReactNativeExtension.waitForRNBootstrap(rnHostHolder)
128
103
  }
129
104
  }
@@ -6,7 +6,7 @@ import android.content.Intent
6
6
  import android.net.Uri
7
7
  import android.os.Bundle
8
8
 
9
- class LaunchIntentsFactory {
9
+ internal class LaunchIntentsFactory {
10
10
 
11
11
  /**
12
12
  * Constructs an intent tightly associated with a specific activity.
@@ -5,7 +5,7 @@ import com.wix.detox.common.JsonConverter
5
5
  import com.wix.detox.common.TextFileReader
6
6
  import org.json.JSONObject
7
7
 
8
- class NotificationDataParser(private val notificationPath: String) {
8
+ internal class NotificationDataParser(private val notificationPath: String) {
9
9
  fun toBundle(): Bundle {
10
10
  val rawData = readNotificationFromFile()
11
11
  val json = JSONObject(rawData)
@@ -152,3 +152,7 @@ class InstrumentsEventsActionsHandler(
152
152
  outboundServerAdapter.sendMessage("eventDone", emptyMap<String, Any>(), messageId)
153
153
  }
154
154
  }
155
+
156
+ class ScarceActionHandler: DetoxActionHandler {
157
+ override fun handle(params: String, messageId: Long) {}
158
+ }
@@ -11,18 +11,11 @@ class DetoxActionsDispatcher {
11
11
  private val primaryExec = ActionsExecutor("detox.primary")
12
12
  private val secondaryExec = ActionsExecutor("detox.secondary")
13
13
 
14
- fun associateActionHandler(type: String, actionHandler: DetoxActionHandler) =
15
- associateActionHandler(type, actionHandler, true)
16
-
17
- fun associateActionHandler(type: String, handlerFunc: () -> Unit) {
18
- associateActionHandler(type, object: DetoxActionHandler {
19
- override fun handle(params: String, messageId: Long) = handlerFunc()
20
- })
14
+ fun associateActionHandler(type: String, actionHandler: DetoxActionHandler, isPrimary: Boolean = true) {
15
+ val actionsExecutor = (if (isPrimary) primaryExec else secondaryExec)
16
+ actionsExecutor.associateHandler(type, actionHandler)
21
17
  }
22
18
 
23
- fun associateSecondaryActionHandler(type: String, actionHandler: DetoxActionHandler) =
24
- associateActionHandler(type, actionHandler, false)
25
-
26
19
  fun dispatchAction(type: String, params: String, messageId: Long) {
27
20
  (primaryExec.executeAction(type, params, messageId) ||
28
21
  secondaryExec.executeAction(type, params, messageId))
@@ -40,11 +33,6 @@ class DetoxActionsDispatcher {
40
33
  primaryExec.join()
41
34
  secondaryExec.join()
42
35
  }
43
-
44
- private fun associateActionHandler(type: String, actionHandler: DetoxActionHandler, isPrimary: Boolean = true) {
45
- val actionsExecutor = (if (isPrimary) primaryExec else secondaryExec)
46
- actionsExecutor.associateHandler(type, actionHandler)
47
- }
48
36
  }
49
37
 
50
38
  private class ActionsExecutor(name: String) {
@@ -86,5 +74,7 @@ private class ActionsExecutor(name: String) {
86
74
  handler.looper.quit()
87
75
  }
88
76
 
89
- fun join() = thread.join()
77
+ fun join() {
78
+ thread.join()
79
+ }
90
80
  }
@@ -10,6 +10,7 @@ interface OutboundServerAdapter {
10
10
  class DetoxServerAdapter(
11
11
  private val actionsDispatcher: DetoxActionsDispatcher,
12
12
  private val detoxServerInfo: DetoxServerInfo,
13
+ private val readyActionType: String,
13
14
  private val terminationActionType: String)
14
15
  : WebSocketClient.WSEventsHandler, OutboundServerAdapter {
15
16
 
@@ -26,6 +27,7 @@ class DetoxServerAdapter(
26
27
 
27
28
  override fun onConnect() {
28
29
  Log.i(DetoxLog.LOG_TAG, "Connected to server!")
30
+ actionsDispatcher.dispatchAction(readyActionType, "", -1000L)
29
31
  }
30
32
 
31
33
  override fun onClosed() {
@@ -1,9 +1,7 @@
1
1
  package com.wix.detox.adapters.server
2
2
 
3
- import android.util.Log
4
3
  import androidx.test.platform.app.InstrumentationRegistry
5
4
  import com.wix.detox.LaunchArgs
6
- import com.wix.detox.common.DetoxLog
7
5
 
8
6
  private const val DEFAULT_URL = "ws://localhost:8099"
9
7
 
@@ -11,7 +9,7 @@ class DetoxServerInfo internal constructor(launchArgs: LaunchArgs = LaunchArgs()
11
9
  val serverUrl: String = launchArgs.detoxServerUrl ?: DEFAULT_URL
12
10
  val sessionId: String = launchArgs.detoxSessionId ?: InstrumentationRegistry.getInstrumentation().targetContext.applicationInfo.packageName
13
11
 
14
- init {
15
- Log.i(DetoxLog.LOG_TAG, "Detox server connection details: url=$serverUrl, sessionId=$sessionId")
12
+ override fun toString(): String {
13
+ return "url=$serverUrl, sessionId=$sessionId"
16
14
  }
17
15
  }
@@ -14,31 +14,6 @@ private const val LOG_TAG = "DetoxRNExt"
14
14
  object ReactNativeExtension {
15
15
  private var rnIdlingResources: ReactNativeIdlingResources? = null
16
16
 
17
- fun initIfNeeded() {
18
- if (!ReactNativeInfo.isReactNativeApp()) {
19
- return
20
- }
21
-
22
- ReactMarkersLogger.attach()
23
- }
24
-
25
- /**
26
- * Wait for React-Native to finish loading (i.e. make RN context available).
27
- *
28
- * @param applicationContext The app context, implicitly assumed to be a [ReactApplication] instance.
29
- */
30
- fun waitForRNBootstrap(applicationContext: Context) {
31
- if (!ReactNativeInfo.isReactNativeApp()) {
32
- return
33
- }
34
-
35
- (applicationContext as ReactApplication).let {
36
- val reactContext = awaitNewReactNativeContext(it, null)
37
-
38
- enableOrDisableSynchronization(reactContext)
39
- }
40
- }
41
-
42
17
  /**
43
18
  * Reloads the React Native context and thus all javascript code.
44
19
  *
@@ -65,6 +40,26 @@ object ReactNativeExtension {
65
40
  val reactContext = awaitNewReactNativeContext(it, previousReactContext)
66
41
 
67
42
  enableOrDisableSynchronization(reactContext, networkSyncEnabled)
43
+ hackRN50OrHigherWaitForReady()
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Wait for React-Native to finish loading (i.e. make RN context available).
49
+ *
50
+ * @param applicationContext The app context, implicitly assumed to be a [ReactApplication] instance.
51
+ */
52
+ @JvmStatic
53
+ fun waitForRNBootstrap(applicationContext: Context) {
54
+ if (!ReactNativeInfo.isReactNativeApp()) {
55
+ return
56
+ }
57
+
58
+ (applicationContext as ReactApplication).let {
59
+ val reactContext = awaitNewReactNativeContext(it, null)
60
+
61
+ enableOrDisableSynchronization(reactContext)
62
+ hackRN50OrHigherWaitForReady()
68
63
  }
69
64
  }
70
65
 
@@ -150,6 +145,18 @@ object ReactNativeExtension {
150
145
  }
151
146
  }
152
147
 
148
+ private fun hackRN50OrHigherWaitForReady() {
149
+ if (ReactNativeInfo.rnVersion().minor in 50..62) {
150
+ try {
151
+ //TODO- Temp hack to make Detox usable for RN>=50 till we find a better sync solution.
152
+ Thread.sleep(1000)
153
+ } catch (e: InterruptedException) {
154
+ e.printStackTrace()
155
+ }
156
+
157
+ }
158
+ }
159
+
153
160
  private fun clearIdlingResources() {
154
161
  rnIdlingResources?.unregisterAll()
155
162
  rnIdlingResources = null
@@ -11,8 +11,11 @@ class UiControllerSpy: MethodsSpy("uiController") {
11
11
  fun eventInjectionsIterator(): Iterator<CallInfo?> = historyOf("injectMotionEvent").iterator()
12
12
 
13
13
  companion object {
14
+ @JvmStatic
14
15
  val instance = UiControllerSpy()
15
16
 
17
+ @JvmStatic
18
+ @JvmOverloads
16
19
  fun attachThroughProxy(spy: UiControllerSpy = instance) {
17
20
  val eventsInjectorReflected = EventsInjectorReflected(getUiController())
18
21
 
@@ -3,7 +3,10 @@ package com.wix.detox.espresso.matcher
3
3
  import org.junit.Test
4
4
  import kotlin.test.assertFalse
5
5
  import kotlin.test.assertTrue
6
+ import org.junit.runner.RunWith
7
+ import org.robolectric.RobolectricTestRunner
6
8
 
9
+ @RunWith(RobolectricTestRunner::class)
7
10
  class RegexMatcherTest {
8
11
  @Test
9
12
  fun `should work with string matching regex`() {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "detox",
3
3
  "description": "E2E tests and automation for mobile",
4
- "version": "20.14.4-prerelease.0",
4
+ "version": "20.14.4-smoke.0",
5
5
  "bin": {
6
6
  "detox": "local-cli/cli.js"
7
7
  },
@@ -109,5 +109,5 @@
109
109
  "browserslist": [
110
110
  "node 14"
111
111
  ],
112
- "gitHead": "5823eb3647890266afea3fd2282c216184929b46"
112
+ "gitHead": "cef00d5518934c10b512869ee716be753e20cad6"
113
113
  }
@@ -58,6 +58,17 @@ class Detox {
58
58
  };
59
59
  }
60
60
 
61
+ static extractInitialIntent() {
62
+ return {
63
+ target: {
64
+ type: "Class",
65
+ value: "com.wix.detox.Detox"
66
+ },
67
+ method: "extractInitialIntent",
68
+ args: []
69
+ };
70
+ }
71
+
61
72
  static getAppContext() {
62
73
  return {
63
74
  target: {
@@ -1 +0,0 @@
1
- d1fb1fd9948721e2962638d6a291aaf3dd76f664
@@ -1 +0,0 @@
1
- 27c5d79abbbfb83d77067e0961e13952e14efed610c9326d8344df6ad59c318c
@@ -1 +0,0 @@
1
- bd730da8c7bba1d17654de9d04520084ccd666cd0122751453dc4626658be02b0dba78217b5a85aa4f14a1e3e8e83a432bd6cb42abc8ca086837f49579c39112
@@ -1 +0,0 @@
1
- f78ab572fa5eb4d80e736a09ef248b3aefdc3e49
@@ -1 +0,0 @@
1
- 1fa998d82cc17386743596ef3ef401ee9f2297c40f6ad5f0e62bbde1b479ae6a
@@ -1 +0,0 @@
1
- 229659e5fa1a88fe9f5764fed0b45388d347848c4702c7d7530d5f9db662b39d04ecd7d38450947fc2c54c2761adf3e98ea8f683dec119771ded207b8928cebf
@@ -1 +0,0 @@
1
- c27920150917efb5b25878186e904fe0
@@ -1 +0,0 @@
1
- ad9e12738ca3c82606a58bacea6d50b51687aee9
@@ -1 +0,0 @@
1
- ab07c0011f9cee612e5b56ea42618978b75a5cfff9841766fc3f796e730c3571
@@ -1 +0,0 @@
1
- a26f964a1ef775262740a23fbbeca9e5754a5da7896bcab22a476f684d40168b67ad4a97087a1f6fe484343e70eb32063adfeac3a2879f887e8d7fc616e6eacc
@@ -1 +0,0 @@
1
- d2944af61d45243912e839416e58f2b8
@@ -1 +0,0 @@
1
- b65e1c75082be225692c4613416d5a34449b9975
@@ -1 +0,0 @@
1
- 3c7f5e26e9752fbb0bb622460ce95cb2dd619cf121a453e0062424e2b7d6c2bc
@@ -1 +0,0 @@
1
- d6444af9c9dda33104b686473cfa6978d1696bc13f6a7f1611ae15ffc920b52a068b15ab82f8222a499f8d59b4645d643487a4878979cd5f2f26ce1b2a0dff9d
@@ -1,78 +0,0 @@
1
- package com.wix.detox
2
-
3
- import android.app.Instrumentation.ActivityMonitor
4
- import android.content.Context
5
- import android.content.Intent
6
- import androidx.test.platform.app.InstrumentationRegistry
7
- import androidx.test.rule.ActivityTestRule
8
-
9
- class ActivityLaunchHelper
10
- @JvmOverloads constructor(
11
- private val activityTestRule: ActivityTestRule<*>,
12
- private val launchArgs: LaunchArgs = LaunchArgs(),
13
- private val intentsFactory: LaunchIntentsFactory = LaunchIntentsFactory(),
14
- private val notificationDataParserGen: (String) -> NotificationDataParser = { path -> NotificationDataParser(path) }
15
- ) {
16
- fun launchActivityUnderTest() {
17
- val intent = extractInitialIntent()
18
- activityTestRule.launchActivity(intent)
19
- }
20
-
21
- fun launchMainActivity() {
22
- val activity = activityTestRule.activity
23
- launchActivitySync(intentsFactory.activityLaunchIntent(activity))
24
- }
25
-
26
- fun startActivityFromUrl(url: String) {
27
- launchActivitySync(intentsFactory.intentWithUrl(url, false))
28
- }
29
-
30
- fun startActivityFromNotification(dataFilePath: String) {
31
- val notificationData = notificationDataParserGen(dataFilePath).toBundle()
32
- val intent = intentsFactory.intentWithNotificationData(appContext, notificationData, false)
33
- launchActivitySync(intent)
34
- }
35
-
36
- private fun extractInitialIntent(): Intent =
37
- (if (launchArgs.hasUrlOverride()) {
38
- intentsFactory.intentWithUrl(launchArgs.urlOverride, true)
39
- } else if (launchArgs.hasNotificationPath()) {
40
- val notificationData = notificationDataParserGen(launchArgs.notificationPath).toBundle()
41
- intentsFactory.intentWithNotificationData(appContext, notificationData, true)
42
- } else {
43
- intentsFactory.cleanIntent()
44
- }).also {
45
- it.putExtra(INTENT_LAUNCH_ARGS_KEY, launchArgs.asIntentBundle())
46
- }
47
-
48
- private fun launchActivitySync(intent: Intent) {
49
- // Ideally, we would just call sActivityTestRule.launchActivity(intent) and get it over with.
50
- // BUT!!! as it turns out, Espresso has an issue where doing this for an activity running in the background
51
- // would have Espresso set up an ActivityMonitor which will spend its time waiting for the activity to load, *without
52
- // ever being released*. It will finally fail after a 45 seconds timeout.
53
- // Without going into full details, it seems that activity test rules were not meant to be used this way. However,
54
- // the all-new ActivityScenario implementation introduced in androidx could probably support this (e.g. by using
55
- // dedicated methods such as moveToState(), which give better control over the lifecycle).
56
- // In any case, this is the core reason for this issue: https://github.com/wix/Detox/issues/1125
57
- // What it forces us to do, then, is this -
58
- // 1. Launch the activity by "ourselves" from the OS (i.e. using context.startActivity()).
59
- // 2. Set up an activity monitor by ourselves -- such that it would block until the activity is ready.
60
- // ^ Hence the code below.
61
- val activity = activityTestRule.activity
62
- val activityMonitor = ActivityMonitor(activity.javaClass.name, null, true)
63
- activity.startActivity(intent)
64
-
65
- InstrumentationRegistry.getInstrumentation().run {
66
- addMonitor(activityMonitor)
67
- waitForMonitorWithTimeout(activityMonitor, ACTIVITY_LAUNCH_TIMEOUT)
68
- }
69
- }
70
-
71
- private val appContext: Context
72
- get() = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext
73
-
74
- companion object {
75
- private const val INTENT_LAUNCH_ARGS_KEY = "launchArgs"
76
- private const val ACTIVITY_LAUNCH_TIMEOUT = 10000L
77
- }
78
- }
@@ -1,44 +0,0 @@
1
- package com.wix.detox.reactnative
2
-
3
- import android.util.Log
4
- import com.facebook.react.bridge.ReactMarker
5
- import com.facebook.react.bridge.ReactMarkerConstants
6
- import com.facebook.react.bridge.ReactMarkerConstants.*
7
-
8
- object ReactMarkersLogger : ReactMarker.MarkerListener {
9
-
10
- fun attach() {
11
- ReactMarker.addListener(this)
12
- }
13
-
14
- override fun logMarker(marker: ReactMarkerConstants, p1: String?, p2: Int) {
15
- when {
16
- marker == DOWNLOAD_START ||
17
- marker == DOWNLOAD_END ||
18
- marker == BUILD_REACT_INSTANCE_MANAGER_START ||
19
- marker == BUILD_REACT_INSTANCE_MANAGER_END ||
20
- marker == REACT_BRIDGE_LOADING_START ||
21
- marker == REACT_BRIDGE_LOADING_END ||
22
- marker == REACT_BRIDGELESS_LOADING_START ||
23
- marker == REACT_BRIDGELESS_LOADING_END ||
24
- marker == CREATE_MODULE_START ||
25
- marker == CREATE_MODULE_END ||
26
- marker == NATIVE_MODULE_SETUP_START ||
27
- marker == NATIVE_MODULE_SETUP_END ||
28
- marker == PRE_RUN_JS_BUNDLE_START ||
29
- marker == RUN_JS_BUNDLE_START ||
30
- marker == RUN_JS_BUNDLE_END ||
31
- marker == CONTENT_APPEARED ||
32
- marker == CREATE_CATALYST_INSTANCE_START ||
33
- marker == CREATE_CATALYST_INSTANCE_END ||
34
- marker == DESTROY_CATALYST_INSTANCE_START ||
35
- marker == DESTROY_CATALYST_INSTANCE_END ||
36
- marker == CREATE_REACT_CONTEXT_START ||
37
- marker == CREATE_REACT_CONTEXT_END ||
38
- marker == PROCESS_PACKAGES_START ||
39
- marker == PROCESS_PACKAGES_END ||
40
- false ->
41
- Log.d("Detox.RNMarker", "$marker ($p1)")
42
- }
43
- }
44
- }
@@ -1,111 +0,0 @@
1
- package com.wix.detox
2
-
3
- import android.app.Activity
4
- import android.content.Intent
5
- import android.os.Bundle
6
- import org.mockito.kotlin.*
7
- import androidx.test.rule.ActivityTestRule
8
- import org.junit.runner.RunWith
9
- import org.assertj.core.api.Assertions.assertThat
10
- import org.junit.Before
11
- import org.junit.Test
12
- import org.mockito.ArgumentMatchers.anyBoolean
13
- import org.mockito.ArgumentMatchers.anyString
14
- import org.robolectric.RobolectricTestRunner
15
-
16
- @RunWith(RobolectricTestRunner::class)
17
- class ActivityLaunchHelperTest {
18
-
19
- private val initialURL = "detox://unit-test"
20
- private val bundleExtraLaunchArgs = "launchArgs"
21
- private val notificationPath = "path/to/notification.data"
22
-
23
- private lateinit var intent: Intent
24
- private lateinit var launchArgsAsBundle: Bundle
25
- private lateinit var notificationDataAsBundle: Bundle
26
- private lateinit var testRule: ActivityTestRule<Activity>
27
- private lateinit var launchArgs: LaunchArgs
28
- private lateinit var intentsFactory: LaunchIntentsFactory
29
- private lateinit var notificationDataParser: NotificationDataParser
30
-
31
- private fun uut() = ActivityLaunchHelper(testRule, launchArgs, intentsFactory, { notificationDataParser })
32
-
33
- @Before
34
- fun setup() {
35
- intent = Intent()
36
- launchArgsAsBundle = mock()
37
- notificationDataAsBundle = mock()
38
-
39
- testRule = mock()
40
- launchArgs = mock() {
41
- on { asIntentBundle() }.thenReturn(launchArgsAsBundle)
42
- }
43
- intentsFactory = mock()
44
- notificationDataParser = mock() {
45
- on { toBundle() }.thenReturn(notificationDataAsBundle)
46
- }
47
- }
48
-
49
- @Test
50
- fun `default-activity -- should launch using test rule, with a clean intent`() {
51
- givenCleanLaunch()
52
- uut().launchActivityUnderTest()
53
- verify(testRule).launchActivity(eq(intent))
54
- }
55
-
56
- @Test
57
- fun `default-activity -- should apply launch args to intent`() {
58
- givenCleanLaunch()
59
- uut().launchActivityUnderTest()
60
- assertIntentHasLaunchArgs()
61
- }
62
-
63
- @Test
64
- fun `default activity, with a url -- should launch based on the url`() {
65
- givenLaunchWithInitialURL()
66
- uut().launchActivityUnderTest()
67
- verify(testRule).launchActivity(eq(intent))
68
- verify(intentsFactory).intentWithUrl(initialURL, true)
69
- }
70
-
71
- @Test
72
- fun `default activity, with a url -- should apply launch args to intent`() {
73
- givenLaunchWithInitialURL()
74
- uut().launchActivityUnderTest()
75
- assertIntentHasLaunchArgs()
76
- }
77
-
78
- @Test
79
- fun `default activity, with notification data -- should launch with the data as bundle`() {
80
- givenLaunchWithNotificationData()
81
- uut().launchActivityUnderTest()
82
- verify(testRule).launchActivity(eq(intent))
83
- verify(intentsFactory).intentWithNotificationData(any(), eq(notificationDataAsBundle), eq(true))
84
- }
85
-
86
- @Test
87
- fun `default activity, with notification data -- should apply launch args to intent`() {
88
- givenLaunchWithNotificationData()
89
- uut().launchActivityUnderTest()
90
- assertIntentHasLaunchArgs()
91
- }
92
-
93
- private fun givenCleanLaunch() {
94
- whenever(intentsFactory.cleanIntent()).thenReturn(intent)
95
- }
96
- private fun givenLaunchWithInitialURL() {
97
- whenever(launchArgs.hasUrlOverride()).thenReturn(true)
98
- whenever(launchArgs.urlOverride).thenReturn(initialURL)
99
- whenever(intentsFactory.intentWithUrl(anyString(), anyBoolean())).thenReturn(intent)
100
- }
101
- private fun givenLaunchWithNotificationData() {
102
- whenever(launchArgs.hasNotificationPath()).thenReturn(true)
103
- whenever(launchArgs.notificationPath).thenReturn(notificationPath)
104
- whenever(intentsFactory.intentWithNotificationData(any(), any(), anyBoolean()))
105
- .thenReturn(intent)
106
- }
107
- private fun assertIntentHasLaunchArgs() {
108
- assertThat(intent.hasExtra(bundleExtraLaunchArgs)).isTrue
109
- assertThat(intent.getBundleExtra(bundleExtraLaunchArgs)).isEqualTo(launchArgsAsBundle)
110
- }
111
- }