detox 20.13.5 → 20.14.0-prerelease.0
Sign up to get free protection for your applications and to get access to all the features.
- package/Detox-android/com/wix/detox/{20.13.5/detox-20.13.5-javadoc.jar → 20.14.0-prerelease.0/detox-20.14.0-prerelease.0-javadoc.jar} +0 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-javadoc.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-javadoc.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-javadoc.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-javadoc.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{20.13.5/detox-20.13.5-sources.jar → 20.14.0-prerelease.0/detox-20.14.0-prerelease.0-sources.jar} +0 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-sources.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-sources.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-sources.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-sources.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.aar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.aar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.aar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.aar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{20.13.5/detox-20.13.5.pom → 20.14.0-prerelease.0/detox-20.14.0-prerelease.0.pom} +1 -1
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.pom.md5 +1 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.pom.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.pom.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.pom.sha512 +1 -0
- package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
- package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
- package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
- package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
- package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
- package/Detox-ios-src.tbz +0 -0
- package/Detox-ios.tbz +0 -0
- package/android/detox/src/full/java/com/wix/detox/ActivityLaunchHelper.kt +76 -0
- package/android/detox/src/full/java/com/wix/detox/Detox.java +8 -64
- package/android/detox/src/full/java/com/wix/detox/DetoxMain.kt +53 -33
- package/android/detox/src/full/java/com/wix/detox/LaunchIntentsFactory.kt +1 -1
- package/android/detox/src/full/java/com/wix/detox/adapters/server/DetoxActionHandlers.kt +0 -4
- package/android/detox/src/full/java/com/wix/detox/adapters/server/DetoxActionsDispatcher.kt +7 -3
- package/android/detox/src/full/java/com/wix/detox/adapters/server/DetoxServerAdapter.kt +0 -2
- package/android/detox/src/full/java/com/wix/detox/adapters/server/DetoxServerInfo.kt +4 -2
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactMarkersLogger.kt +44 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeExtension.kt +28 -22
- package/android/detox/src/main/java/com/wix/detox/espresso/UiControllerSpy.kt +0 -3
- package/detox.d.ts +7 -0
- package/internals.d.ts +2 -1
- package/local-cli/testCommand/TestRunnerCommand.js +26 -3
- package/local-cli/utils/interruptListeners.js +15 -0
- package/package.json +3 -3
- package/runners/jest/testEnvironment/index.js +7 -1
- package/src/android/espressoapi/Detox.js +0 -11
- package/src/configuration/composeRunnerConfig.js +3 -1
- package/src/ipc/IPCClient.js +2 -2
- package/src/ipc/IPCServer.js +5 -3
- package/src/realms/DetoxContext.js +1 -1
- package/src/realms/DetoxPrimaryContext.js +2 -2
- package/src/realms/DetoxSecondaryContext.js +2 -2
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5-javadoc.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5-javadoc.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5-javadoc.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5-javadoc.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5.aar +0 -0
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5.aar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5.pom.md5 +0 -1
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.13.5/detox-20.13.5.pom.sha512 +0 -1
Binary file
|
package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-javadoc.jar.md5
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
5aec7a3796623aa58d8d12e2a79a73d4
|
package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-javadoc.jar.sha1
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3530c43ea00d627580747ee9f0d5863ca9813f37
|
@@ -0,0 +1 @@
|
|
1
|
+
8e1b2ec062f53625f04682a7680f945a735f5ce1398779fc75053e06552d1df5
|
@@ -0,0 +1 @@
|
|
1
|
+
609e6c6a9432b4e1ef6a4e0cce31001a69ea5fb95ea2396be34732e5e1cc80accb647c5c9003827cf69754918a3a814deb24d27f14047a3aa6297c92b764ef03
|
Binary file
|
package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-sources.jar.md5
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
a5d3efc29dc36129f22268aecde7ba01
|
package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-sources.jar.sha1
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
c2dffdb56581b4c26ed98b6775e222e1a4486c5e
|
@@ -0,0 +1 @@
|
|
1
|
+
c9a52d8a32ecbc37230bcdbb9a4aa67411ca950311e5de327ec44694d77c8872
|
@@ -0,0 +1 @@
|
|
1
|
+
402fd90cfcfc8ee4f7faa04e7915ab6f24580ef704dbe0b835bae434abe4bf749987cb7fcc52b6a1f7557275a3ca5e0205438aef2934966948dfdaa66335a162
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
e4d79ca2a269e97059c4321c69b89508
|
@@ -0,0 +1 @@
|
|
1
|
+
a5f8cbcf67d3d87d5036eb6f48372962c64dd12b
|
package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.aar.sha256
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
b2459b4c1286baf4f608be3ec55a46688c92ab1a95d840769a3519b4f75c2ea4
|
package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.aar.sha512
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
60375b1df9ce89baea8fb435985d83d2fde2a8013f3b12fb1d3e3391ef7ac14e98d10eff9b27fd44acc753c7764244fcb0d9934ce97c4beb534102247a9962f0
|
@@ -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.
|
6
|
+
<version>20.14.0-prerelease.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
|
+
1e365cca25c5a49f1bf610fd76df8ff0
|
@@ -0,0 +1 @@
|
|
1
|
+
6f1a93a3247a829d64f63a67830adc742dfef0b9
|
package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.pom.sha256
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
c2745e1391bb64bed726bf43a1f624f79d13f0a2c7e4ccd9838b64df40d1e3ee
|
package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.pom.sha512
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ca4428ae0cdffbf5bb7967d24f29486735a29ee89bad794bfa451f12467744f48bab8a7adac1fdb73426951aec461ccf3bae0396994c6e4711d1ff347e85369b
|
@@ -3,11 +3,11 @@
|
|
3
3
|
<groupId>com.wix</groupId>
|
4
4
|
<artifactId>detox</artifactId>
|
5
5
|
<versioning>
|
6
|
-
<latest>20.
|
7
|
-
<release>20.
|
6
|
+
<latest>20.14.0-prerelease.0</latest>
|
7
|
+
<release>20.14.0-prerelease.0</release>
|
8
8
|
<versions>
|
9
|
-
<version>20.
|
9
|
+
<version>20.14.0-prerelease.0</version>
|
10
10
|
</versions>
|
11
|
-
<lastUpdated>
|
11
|
+
<lastUpdated>20231206150336</lastUpdated>
|
12
12
|
</versioning>
|
13
13
|
</metadata>
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
374b144f9306034184388c9579fcda60
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
aeb72dae3a76fd71e383c8b1bbc7871bf39b5424
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
94e4275040ab622783723cea7783afc664a6b9759ea43e8d3c57b48e1eb34290
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
8ed181a738180833c36cf5066afb55082d4067c3924e5f240deef147ee818058a09ad14f3a2800cb46538e67872fd79b8437561b37eadd9e2f9f7d38b5454285
|
package/Detox-ios-src.tbz
CHANGED
Binary file
|
package/Detox-ios.tbz
CHANGED
Binary file
|
@@ -0,0 +1,76 @@
|
|
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(private val activityTestRule: ActivityTestRule<*>) {
|
10
|
+
|
11
|
+
private val launchArgs = LaunchArgs()
|
12
|
+
private val intentsFactory = LaunchIntentsFactory()
|
13
|
+
|
14
|
+
fun launchActivityUnderTest() {
|
15
|
+
val intent = extractInitialIntent()
|
16
|
+
activityTestRule.launchActivity(intent)
|
17
|
+
}
|
18
|
+
|
19
|
+
fun launchMainActivity() {
|
20
|
+
val activity = activityTestRule.activity
|
21
|
+
launchActivitySync(intentsFactory.activityLaunchIntent(activity))
|
22
|
+
}
|
23
|
+
|
24
|
+
fun startActivityFromUrl(url: String) {
|
25
|
+
launchActivitySync(intentsFactory.intentWithUrl(url, false))
|
26
|
+
}
|
27
|
+
|
28
|
+
fun startActivityFromNotification(dataFilePath: String) {
|
29
|
+
val notificationData = NotificationDataParser(dataFilePath!!).toBundle()
|
30
|
+
val intent = intentsFactory.intentWithNotificationData(appContext, notificationData, false)
|
31
|
+
launchActivitySync(intent)
|
32
|
+
}
|
33
|
+
|
34
|
+
private fun extractInitialIntent(): Intent =
|
35
|
+
if (launchArgs.hasUrlOverride()) {
|
36
|
+
intentsFactory.intentWithUrl(launchArgs.urlOverride, true)
|
37
|
+
} else if (launchArgs.hasNotificationPath()) {
|
38
|
+
val notificationData = NotificationDataParser(launchArgs.notificationPath).toBundle()
|
39
|
+
intentsFactory.intentWithNotificationData(appContext, notificationData, true)
|
40
|
+
} else {
|
41
|
+
intentsFactory.cleanIntent()
|
42
|
+
}.also {
|
43
|
+
it.putExtra(INTENT_LAUNCH_ARGS_KEY, launchArgs.asIntentBundle())
|
44
|
+
}
|
45
|
+
|
46
|
+
private fun launchActivitySync(intent: Intent) {
|
47
|
+
// Ideally, we would just call sActivityTestRule.launchActivity(intent) and get it over with.
|
48
|
+
// BUT!!! as it turns out, Espresso has an issue where doing this for an activity running in the background
|
49
|
+
// would have Espresso set up an ActivityMonitor which will spend its time waiting for the activity to load, *without
|
50
|
+
// ever being released*. It will finally fail after a 45 seconds timeout.
|
51
|
+
// Without going into full details, it seems that activity test rules were not meant to be used this way. However,
|
52
|
+
// the all-new ActivityScenario implementation introduced in androidx could probably support this (e.g. by using
|
53
|
+
// dedicated methods such as moveToState(), which give better control over the lifecycle).
|
54
|
+
// In any case, this is the core reason for this issue: https://github.com/wix/Detox/issues/1125
|
55
|
+
// What it forces us to do, then, is this -
|
56
|
+
// 1. Launch the activity by "ourselves" from the OS (i.e. using context.startActivity()).
|
57
|
+
// 2. Set up an activity monitor by ourselves -- such that it would block until the activity is ready.
|
58
|
+
// ^ Hence the code below.
|
59
|
+
val activity = activityTestRule.activity
|
60
|
+
val activityMonitor = ActivityMonitor(activity.javaClass.name, null, true)
|
61
|
+
activity.startActivity(intent)
|
62
|
+
|
63
|
+
InstrumentationRegistry.getInstrumentation().run {
|
64
|
+
addMonitor(activityMonitor)
|
65
|
+
waitForMonitorWithTimeout(activityMonitor, ACTIVITY_LAUNCH_TIMEOUT)
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
private val appContext: Context
|
70
|
+
get() = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext
|
71
|
+
|
72
|
+
companion object {
|
73
|
+
private const val INTENT_LAUNCH_ARGS_KEY = "launchArgs"
|
74
|
+
private const val ACTIVITY_LAUNCH_TIMEOUT = 10000L
|
75
|
+
}
|
76
|
+
}
|
@@ -1,18 +1,13 @@
|
|
1
1
|
package com.wix.detox;
|
2
2
|
|
3
|
-
import android.app.Activity;
|
4
|
-
import android.app.Instrumentation;
|
5
3
|
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;
|
11
4
|
|
12
5
|
import androidx.annotation.NonNull;
|
13
6
|
import androidx.test.platform.app.InstrumentationRegistry;
|
14
7
|
import androidx.test.rule.ActivityTestRule;
|
15
8
|
|
9
|
+
import com.wix.detox.config.DetoxConfig;
|
10
|
+
|
16
11
|
/**
|
17
12
|
* <p>Static class.</p>
|
18
13
|
*
|
@@ -67,12 +62,7 @@ import androidx.test.rule.ActivityTestRule;
|
|
67
62
|
* <p>If not set, then Detox tests are no ops. So it's safe to mix it with other tests.</p>
|
68
63
|
*/
|
69
64
|
public final class Detox {
|
70
|
-
private static
|
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;
|
65
|
+
private static ActivityLaunchHelper sActivityLaunchHelper;
|
76
66
|
|
77
67
|
private Detox() {
|
78
68
|
}
|
@@ -132,15 +122,10 @@ public final class Detox {
|
|
132
122
|
DetoxConfig.CONFIG = detoxConfig;
|
133
123
|
DetoxConfig.CONFIG.apply();
|
134
124
|
|
135
|
-
|
136
|
-
|
137
|
-
UiControllerSpy.attachThroughProxy();
|
138
|
-
|
139
|
-
Intent intent = extractInitialIntent();
|
140
|
-
sActivityTestRule.launchActivity(intent);
|
125
|
+
sActivityLaunchHelper = new ActivityLaunchHelper(activityTestRule);
|
141
126
|
|
142
127
|
try {
|
143
|
-
DetoxMain.run(context);
|
128
|
+
DetoxMain.run(context, sActivityLaunchHelper);
|
144
129
|
} catch (Exception e) {
|
145
130
|
Thread.currentThread().interrupt();
|
146
131
|
throw new RuntimeException("Detox got interrupted prematurely", e);
|
@@ -148,56 +133,15 @@ public final class Detox {
|
|
148
133
|
}
|
149
134
|
|
150
135
|
public static void launchMainActivity() {
|
151
|
-
|
152
|
-
launchActivitySync(sIntentsFactory.activityLaunchIntent(activity));
|
136
|
+
sActivityLaunchHelper.launchMainActivity();
|
153
137
|
}
|
154
138
|
|
155
139
|
public static void startActivityFromUrl(String url) {
|
156
|
-
|
140
|
+
sActivityLaunchHelper.startActivityFromUrl(url);
|
157
141
|
}
|
158
142
|
|
159
143
|
public static void startActivityFromNotification(String dataFilePath) {
|
160
|
-
|
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);
|
144
|
+
sActivityLaunchHelper.startActivityFromNotification(dataFilePath);
|
201
145
|
}
|
202
146
|
|
203
147
|
private static Context getAppContext() {
|
@@ -3,35 +3,50 @@ 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
|
6
|
+
import com.wix.detox.common.DetoxLog
|
7
|
+
import com.wix.detox.espresso.UiControllerSpy
|
7
8
|
import com.wix.detox.instruments.DetoxInstrumentsManager
|
8
9
|
import com.wix.detox.reactnative.ReactNativeExtension
|
9
10
|
import com.wix.invoke.MethodInvocation
|
11
|
+
import java.util.concurrent.CountDownLatch
|
10
12
|
|
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 loginMonitor = CountDownLatch(1)
|
17
|
+
|
16
18
|
@JvmStatic
|
17
|
-
fun run(rnHostHolder: Context) {
|
19
|
+
fun run(rnHostHolder: Context, activityLaunchHelper: ActivityLaunchHelper) {
|
18
20
|
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 externalAdapter = DetoxServerAdapter(actionsDispatcher, detoxServerInfo,
|
23
|
+
val externalAdapter = DetoxServerAdapter(actionsDispatcher, detoxServerInfo, TERMINATION_ACTION)
|
24
|
+
|
24
25
|
initActionHandlers(actionsDispatcher, externalAdapter, testEngineFacade, rnHostHolder)
|
25
|
-
actionsDispatcher.dispatchAction(INIT_ACTION, "", 0)
|
26
|
+
// actionsDispatcher.dispatchAction(INIT_ACTION, "", 0)
|
27
|
+
init(externalAdapter)
|
28
|
+
synchronized(this) {
|
29
|
+
awaitHandshake()
|
30
|
+
launchApp(rnHostHolder, activityLaunchHelper)
|
31
|
+
}
|
26
32
|
actionsDispatcher.join()
|
27
33
|
}
|
28
34
|
|
29
|
-
private fun
|
30
|
-
externalAdapter.connect()
|
31
|
-
|
35
|
+
private fun init(externalAdapter: DetoxServerAdapter) {
|
32
36
|
initCrashHandler(externalAdapter)
|
33
37
|
initANRListener(externalAdapter)
|
34
|
-
|
38
|
+
initEspresso()
|
39
|
+
initReactNative()
|
40
|
+
|
41
|
+
externalAdapter.connect()
|
42
|
+
}
|
43
|
+
|
44
|
+
private fun awaitHandshake() {
|
45
|
+
loginMonitor.await()
|
46
|
+
}
|
47
|
+
|
48
|
+
private fun onLoginSuccess() {
|
49
|
+
loginMonitor.countDown()
|
35
50
|
}
|
36
51
|
|
37
52
|
private fun doTeardown(serverAdapter: DetoxServerAdapter, actionsDispatcher: DetoxActionsDispatcher, testEngineFacade: TestEngineFacade) {
|
@@ -44,32 +59,27 @@ object DetoxMain {
|
|
44
59
|
private fun initActionHandlers(actionsDispatcher: DetoxActionsDispatcher, serverAdapter: DetoxServerAdapter, testEngineFacade: TestEngineFacade, rnHostHolder: Context) {
|
45
60
|
// Primary actions
|
46
61
|
with(actionsDispatcher) {
|
62
|
+
val readyHandler = ReadyActionHandler(serverAdapter, testEngineFacade)
|
47
63
|
val rnReloadHandler = ReactNativeReloadActionHandler(rnHostHolder, serverAdapter, testEngineFacade)
|
48
64
|
|
49
|
-
associateActionHandler(
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
}
|
55
|
-
associateActionHandler(
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
synchronized(this@DetoxMain) {
|
61
|
-
rnReloadHandler.handle(params, messageId)
|
62
|
-
}
|
63
|
-
})
|
65
|
+
associateActionHandler("isReady") { params, messageId ->
|
66
|
+
synchronized(this@DetoxMain) {
|
67
|
+
readyHandler.handle(params, messageId)
|
68
|
+
}
|
69
|
+
}
|
70
|
+
associateActionHandler("loginSuccess") { _, _ -> this@DetoxMain.onLoginSuccess() }
|
71
|
+
associateActionHandler("reactNativeReload") { params, messageId ->
|
72
|
+
synchronized(this@DetoxMain) {
|
73
|
+
rnReloadHandler.handle(params, messageId)
|
74
|
+
}
|
75
|
+
}
|
64
76
|
associateActionHandler("invoke", InvokeActionHandler(MethodInvocation(), serverAdapter))
|
65
77
|
associateActionHandler("cleanup", CleanupActionHandler(serverAdapter, testEngineFacade) {
|
66
78
|
dispatchAction(TERMINATION_ACTION, "", 0)
|
67
79
|
})
|
68
|
-
associateActionHandler(TERMINATION_ACTION,
|
69
|
-
|
70
|
-
|
71
|
-
}
|
72
|
-
})
|
80
|
+
associateActionHandler(TERMINATION_ACTION) { _, _ ->
|
81
|
+
this@DetoxMain.doTeardown(serverAdapter, actionsDispatcher, testEngineFacade)
|
82
|
+
}
|
73
83
|
|
74
84
|
if (DetoxInstrumentsManager.supports()) {
|
75
85
|
val instrumentsManager = DetoxInstrumentsManager(rnHostHolder)
|
@@ -98,7 +108,17 @@ object DetoxMain {
|
|
98
108
|
DetoxANRHandler(outboundServerAdapter).attach()
|
99
109
|
}
|
100
110
|
|
101
|
-
private fun
|
111
|
+
private fun initEspresso() {
|
112
|
+
UiControllerSpy.attachThroughProxy()
|
113
|
+
}
|
114
|
+
|
115
|
+
private fun initReactNative() {
|
116
|
+
ReactNativeExtension.initIfNeeded()
|
117
|
+
}
|
118
|
+
|
119
|
+
private fun launchApp(rnHostHolder: Context, activityLaunchHelper: ActivityLaunchHelper) {
|
120
|
+
Log.i(DetoxLog.LOG_TAG, "Launching the tested activity!")
|
121
|
+
activityLaunchHelper.launchActivityUnderTest()
|
102
122
|
ReactNativeExtension.waitForRNBootstrap(rnHostHolder)
|
103
123
|
}
|
104
124
|
}
|
@@ -16,6 +16,12 @@ class DetoxActionsDispatcher {
|
|
16
16
|
actionsExecutor.associateHandler(type, actionHandler)
|
17
17
|
}
|
18
18
|
|
19
|
+
fun associateActionHandler(type: String, handlerFunc: (params: String, messageId: Long) -> Unit) {
|
20
|
+
associateActionHandler(type, object: DetoxActionHandler {
|
21
|
+
override fun handle(params: String, messageId: Long) = handlerFunc(params, messageId)
|
22
|
+
})
|
23
|
+
}
|
24
|
+
|
19
25
|
fun dispatchAction(type: String, params: String, messageId: Long) {
|
20
26
|
(primaryExec.executeAction(type, params, messageId) ||
|
21
27
|
secondaryExec.executeAction(type, params, messageId))
|
@@ -74,7 +80,5 @@ private class ActionsExecutor(name: String) {
|
|
74
80
|
handler.looper.quit()
|
75
81
|
}
|
76
82
|
|
77
|
-
fun join()
|
78
|
-
thread.join()
|
79
|
-
}
|
83
|
+
fun join() = thread.join()
|
80
84
|
}
|
@@ -10,7 +10,6 @@ interface OutboundServerAdapter {
|
|
10
10
|
class DetoxServerAdapter(
|
11
11
|
private val actionsDispatcher: DetoxActionsDispatcher,
|
12
12
|
private val detoxServerInfo: DetoxServerInfo,
|
13
|
-
private val readyActionType: String,
|
14
13
|
private val terminationActionType: String)
|
15
14
|
: WebSocketClient.WSEventsHandler, OutboundServerAdapter {
|
16
15
|
|
@@ -27,7 +26,6 @@ class DetoxServerAdapter(
|
|
27
26
|
|
28
27
|
override fun onConnect() {
|
29
28
|
Log.i(DetoxLog.LOG_TAG, "Connected to server!")
|
30
|
-
actionsDispatcher.dispatchAction(readyActionType, "", -1000L)
|
31
29
|
}
|
32
30
|
|
33
31
|
override fun onClosed() {
|
@@ -1,7 +1,9 @@
|
|
1
1
|
package com.wix.detox.adapters.server
|
2
2
|
|
3
|
+
import android.util.Log
|
3
4
|
import androidx.test.platform.app.InstrumentationRegistry
|
4
5
|
import com.wix.detox.LaunchArgs
|
6
|
+
import com.wix.detox.common.DetoxLog
|
5
7
|
|
6
8
|
private const val DEFAULT_URL = "ws://localhost:8099"
|
7
9
|
|
@@ -9,7 +11,7 @@ class DetoxServerInfo internal constructor(launchArgs: LaunchArgs = LaunchArgs()
|
|
9
11
|
val serverUrl: String = launchArgs.detoxServerUrl ?: DEFAULT_URL
|
10
12
|
val sessionId: String = launchArgs.detoxSessionId ?: InstrumentationRegistry.getInstrumentation().targetContext.applicationInfo.packageName
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
+
init {
|
15
|
+
Log.i(DetoxLog.LOG_TAG, "Detox server connection details: url=$serverUrl, sessionId=$sessionId")
|
14
16
|
}
|
15
17
|
}
|
@@ -0,0 +1,44 @@
|
|
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
|
+
}
|
@@ -14,6 +14,32 @@ 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
|
+
hackRN50WaitForReady()
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
17
43
|
/**
|
18
44
|
* Reloads the React Native context and thus all javascript code.
|
19
45
|
*
|
@@ -40,26 +66,7 @@ object ReactNativeExtension {
|
|
40
66
|
val reactContext = awaitNewReactNativeContext(it, previousReactContext)
|
41
67
|
|
42
68
|
enableOrDisableSynchronization(reactContext, networkSyncEnabled)
|
43
|
-
|
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()
|
69
|
+
hackRN50WaitForReady()
|
63
70
|
}
|
64
71
|
}
|
65
72
|
|
@@ -145,7 +152,7 @@ object ReactNativeExtension {
|
|
145
152
|
}
|
146
153
|
}
|
147
154
|
|
148
|
-
private fun
|
155
|
+
private fun hackRN50WaitForReady() {
|
149
156
|
if (ReactNativeInfo.rnVersion().minor in 50..62) {
|
150
157
|
try {
|
151
158
|
//TODO- Temp hack to make Detox usable for RN>=50 till we find a better sync solution.
|
@@ -153,7 +160,6 @@ object ReactNativeExtension {
|
|
153
160
|
} catch (e: InterruptedException) {
|
154
161
|
e.printStackTrace()
|
155
162
|
}
|
156
|
-
|
157
163
|
}
|
158
164
|
}
|
159
165
|
|
@@ -11,11 +11,8 @@ class UiControllerSpy: MethodsSpy("uiController") {
|
|
11
11
|
fun eventInjectionsIterator(): Iterator<CallInfo?> = historyOf("injectMotionEvent").iterator()
|
12
12
|
|
13
13
|
companion object {
|
14
|
-
@JvmStatic
|
15
14
|
val instance = UiControllerSpy()
|
16
15
|
|
17
|
-
@JvmStatic
|
18
|
-
@JvmOverloads
|
19
16
|
fun attachThroughProxy(spy: UiControllerSpy = instance) {
|
20
17
|
val eventsInjectorReflected = EventsInjectorReflected(getUiController())
|
21
18
|
|
package/detox.d.ts
CHANGED
@@ -235,6 +235,13 @@ declare global {
|
|
235
235
|
* @see {DetoxInternals.DetoxTestFileReport#isPermanentFailure}
|
236
236
|
*/
|
237
237
|
bail?: boolean;
|
238
|
+
/**
|
239
|
+
* When true, tells `detox test` to spawn the test runner in a detached mode.
|
240
|
+
* This is useful in CI environments, where you want to intercept SIGINT and SIGTERM signals to gracefully shut down the test runner and the device.
|
241
|
+
* Instead of passing the kill signal to the child process (the test runner), Detox will send an emergency shutdown request to all the workers, and then it will wait for them to finish.
|
242
|
+
* @default false
|
243
|
+
*/
|
244
|
+
detached?: boolean;
|
238
245
|
/**
|
239
246
|
* Custom handler to process --inspect-brk CLI flag.
|
240
247
|
* Use it when you rely on another test runner than Jest to mutate the config.
|
package/internals.d.ts
CHANGED
@@ -116,8 +116,9 @@ declare global {
|
|
116
116
|
/**
|
117
117
|
* Workaround for Jest exiting abruptly in --bail mode.
|
118
118
|
* Makes sure that all workers and their test environments are properly torn down.
|
119
|
+
* @param [permanent] - forbids further retries
|
119
120
|
*/
|
120
|
-
unsafe_conductEarlyTeardown(): Promise<void>;
|
121
|
+
unsafe_conductEarlyTeardown(permanent?: boolean): Promise<void>;
|
121
122
|
/**
|
122
123
|
* Reports to Detox CLI about passed and failed test files.
|
123
124
|
* The failed test files might be re-run again if
|
@@ -12,6 +12,7 @@ const { escapeSpaces, useForwardSlashes } = require('../../src/utils/shellUtils'
|
|
12
12
|
const sleep = require('../../src/utils/sleep');
|
13
13
|
const AppStartCommand = require('../startCommand/AppStartCommand');
|
14
14
|
const { markErrorAsLogged } = require('../utils/cliErrorHandling');
|
15
|
+
const interruptListeners = require('../utils/interruptListeners');
|
15
16
|
|
16
17
|
const TestRunnerError = require('./TestRunnerError');
|
17
18
|
|
@@ -28,10 +29,12 @@ class TestRunnerCommand {
|
|
28
29
|
const appsConfig = opts.config.apps;
|
29
30
|
|
30
31
|
this._argv = runnerConfig.args;
|
32
|
+
this._detached = runnerConfig.detached;
|
31
33
|
this._retries = runnerConfig.retries;
|
32
34
|
this._envHint = this._buildEnvHint(opts.env);
|
33
35
|
this._startCommands = this._prepareStartCommands(appsConfig, cliConfig);
|
34
36
|
this._envFwd = {};
|
37
|
+
this._terminating = false;
|
35
38
|
|
36
39
|
if (runnerConfig.forwardEnv) {
|
37
40
|
this._envFwd = this._buildEnvOverride(cliConfig, deviceConfig);
|
@@ -59,16 +62,20 @@ class TestRunnerCommand {
|
|
59
62
|
} catch (e) {
|
60
63
|
launchError = e;
|
61
64
|
|
65
|
+
if (this._terminating) {
|
66
|
+
runsLeft = 0;
|
67
|
+
}
|
68
|
+
|
62
69
|
const failedTestFiles = detox.session.testResults.filter(r => !r.success);
|
63
70
|
|
64
71
|
const { bail } = detox.config.testRunner;
|
65
72
|
if (bail && failedTestFiles.some(r => r.isPermanentFailure)) {
|
66
|
-
|
73
|
+
runsLeft = 0;
|
67
74
|
}
|
68
75
|
|
69
76
|
const testFilesToRetry = failedTestFiles.filter(r => !r.isPermanentFailure).map(r => r.testFilePath);
|
70
|
-
if (
|
71
|
-
|
77
|
+
if (testFilesToRetry.length === 0) {
|
78
|
+
runsLeft = 0;
|
72
79
|
}
|
73
80
|
|
74
81
|
if (--runsLeft > 0) {
|
@@ -143,6 +150,15 @@ class TestRunnerCommand {
|
|
143
150
|
}, _.isUndefined);
|
144
151
|
}
|
145
152
|
|
153
|
+
_onTerminate = () => {
|
154
|
+
if (this._terminating) {
|
155
|
+
return;
|
156
|
+
}
|
157
|
+
|
158
|
+
this._terminating = true;
|
159
|
+
return detox.unsafe_conductEarlyTeardown(true);
|
160
|
+
};
|
161
|
+
|
146
162
|
async _spawnTestRunner() {
|
147
163
|
const fullCommand = this._buildSpawnArguments().map(escapeSpaces);
|
148
164
|
const fullCommandWithHint = printEnvironmentVariables(this._envHint) + fullCommand.join(' ');
|
@@ -153,6 +169,7 @@ class TestRunnerCommand {
|
|
153
169
|
cp.spawn(fullCommand[0], fullCommand.slice(1), {
|
154
170
|
shell: true,
|
155
171
|
stdio: 'inherit',
|
172
|
+
detached: this._detached,
|
156
173
|
env: _({})
|
157
174
|
.assign(process.env)
|
158
175
|
.assign(this._envFwd)
|
@@ -162,6 +179,8 @@ class TestRunnerCommand {
|
|
162
179
|
})
|
163
180
|
.on('error', /* istanbul ignore next */ (err) => reject(err))
|
164
181
|
.on('exit', (code, signal) => {
|
182
|
+
interruptListeners.unsubscribe(this._onTerminate);
|
183
|
+
|
165
184
|
if (code === 0) {
|
166
185
|
log.trace.end({ success: true });
|
167
186
|
resolve();
|
@@ -175,6 +194,10 @@ class TestRunnerCommand {
|
|
175
194
|
reject(markErrorAsLogged(error));
|
176
195
|
}
|
177
196
|
});
|
197
|
+
|
198
|
+
if (this._detached) {
|
199
|
+
interruptListeners.subscribe(this._onTerminate);
|
200
|
+
}
|
178
201
|
});
|
179
202
|
}
|
180
203
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
function subscribe(listener) {
|
2
|
+
process.on('SIGINT', listener);
|
3
|
+
process.on('SIGTERM', listener);
|
4
|
+
}
|
5
|
+
|
6
|
+
function unsubscribe(listener) {
|
7
|
+
process.removeListener('SIGINT', listener);
|
8
|
+
process.removeListener('SIGTERM', listener);
|
9
|
+
}
|
10
|
+
|
11
|
+
module.exports = {
|
12
|
+
subscribe,
|
13
|
+
unsubscribe,
|
14
|
+
};
|
15
|
+
|
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.
|
4
|
+
"version": "20.14.0-prerelease.0",
|
5
5
|
"bin": {
|
6
6
|
"detox": "local-cli/cli.js"
|
7
7
|
},
|
@@ -51,7 +51,7 @@
|
|
51
51
|
"eslint-plugin-node": "^11.1.0",
|
52
52
|
"eslint-plugin-unicorn": "^47.0.0",
|
53
53
|
"jest": "^28.1.3",
|
54
|
-
"jest-allure2-reporter": "2.0.0-alpha.
|
54
|
+
"jest-allure2-reporter": "2.0.0-alpha.11",
|
55
55
|
"mockdate": "^2.0.1",
|
56
56
|
"prettier": "^2.4.1",
|
57
57
|
"react-native": "0.71.10",
|
@@ -109,5 +109,5 @@
|
|
109
109
|
"browserslist": [
|
110
110
|
"node 14"
|
111
111
|
],
|
112
|
-
"gitHead": "
|
112
|
+
"gitHead": "4eb7e6729cf5bd3d30f720c40df316fdf38300df"
|
113
113
|
}
|
@@ -73,7 +73,9 @@ class DetoxCircusEnvironment extends NodeEnvironment {
|
|
73
73
|
// @ts-expect-error TS2425
|
74
74
|
async handleTestEvent(event, state) {
|
75
75
|
if (detox.session.unsafe_earlyTeardown) {
|
76
|
-
|
76
|
+
if (event.name === 'test_fn_start' || event.name === 'hook_start') {
|
77
|
+
throw new Error('Detox halted test execution due to an early teardown request');
|
78
|
+
}
|
77
79
|
}
|
78
80
|
|
79
81
|
this._timer.schedule(state.testTimeout != null ? state.testTimeout : this.setupTimeout);
|
@@ -107,6 +109,10 @@ class DetoxCircusEnvironment extends NodeEnvironment {
|
|
107
109
|
* @protected
|
108
110
|
*/
|
109
111
|
async initDetox() {
|
112
|
+
if (detox.session.unsafe_earlyTeardown) {
|
113
|
+
throw new Error('Detox halted test execution due to an early teardown request');
|
114
|
+
}
|
115
|
+
|
110
116
|
const opts = {
|
111
117
|
global: this.global,
|
112
118
|
workerId: `w${process.env.JEST_WORKER_ID}`,
|
@@ -58,17 +58,6 @@ 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
|
-
|
72
61
|
static getAppContext() {
|
73
62
|
return {
|
74
63
|
target: {
|
@@ -32,6 +32,7 @@ function composeRunnerConfig(opts) {
|
|
32
32
|
retries: 0,
|
33
33
|
inspectBrk: inspectBrkHookDefault,
|
34
34
|
forwardEnv: false,
|
35
|
+
detached: false,
|
35
36
|
bail: false,
|
36
37
|
jest: {
|
37
38
|
setupTimeout: 300000,
|
@@ -56,8 +57,9 @@ function composeRunnerConfig(opts) {
|
|
56
57
|
|
57
58
|
if (typeof merged.inspectBrk === 'function') {
|
58
59
|
if (cliConfig.inspectBrk) {
|
59
|
-
merged.
|
60
|
+
merged.detached = false;
|
60
61
|
merged.forwardEnv = true;
|
62
|
+
merged.retries = 0;
|
61
63
|
merged.inspectBrk(merged);
|
62
64
|
}
|
63
65
|
|
package/src/ipc/IPCClient.js
CHANGED
@@ -86,8 +86,8 @@ class IPCClient {
|
|
86
86
|
this._sessionState.patch(sessionState);
|
87
87
|
}
|
88
88
|
|
89
|
-
async conductEarlyTeardown() {
|
90
|
-
const sessionState = await this._emit('conductEarlyTeardown', {});
|
89
|
+
async conductEarlyTeardown({ permanent }) {
|
90
|
+
const sessionState = await this._emit('conductEarlyTeardown', { permanent });
|
91
91
|
this._sessionState.patch(sessionState);
|
92
92
|
}
|
93
93
|
|
package/src/ipc/IPCServer.js
CHANGED
@@ -73,6 +73,7 @@ class IPCServer {
|
|
73
73
|
this._ipc.server.emit(socket, 'registerContextDone', {
|
74
74
|
testResults: this._sessionState.testResults,
|
75
75
|
testSessionIndex: this._sessionState.testSessionIndex,
|
76
|
+
unsafe_earlyTeardown: this._sessionState.unsafe_earlyTeardown,
|
76
77
|
});
|
77
78
|
}
|
78
79
|
|
@@ -90,10 +91,11 @@ class IPCServer {
|
|
90
91
|
}
|
91
92
|
}
|
92
93
|
|
93
|
-
onConductEarlyTeardown(
|
94
|
-
// Note that we don't save `unsafe_earlyTeardown` in the primary session state
|
95
|
-
// because it's transient and needed only to make the workers quit early.
|
94
|
+
onConductEarlyTeardown({ permanent }, socket = null) {
|
96
95
|
const newState = { unsafe_earlyTeardown: true };
|
96
|
+
if (permanent) {
|
97
|
+
Object.assign(this._sessionState, newState);
|
98
|
+
}
|
97
99
|
|
98
100
|
if (socket) {
|
99
101
|
this._ipc.server.emit(socket, 'conductEarlyTeardownDone', newState);
|
@@ -102,7 +102,7 @@ class DetoxContext {
|
|
102
102
|
/** @abstract */
|
103
103
|
[symbols.reportTestResults](_testResults) {}
|
104
104
|
/** @abstract */
|
105
|
-
[symbols.conductEarlyTeardown]() {}
|
105
|
+
[symbols.conductEarlyTeardown](_permanent) {}
|
106
106
|
/**
|
107
107
|
* @abstract
|
108
108
|
* @param {Partial<DetoxInternals.DetoxInitOptions>} _opts
|
@@ -51,9 +51,9 @@ class DetoxPrimaryContext extends DetoxContext {
|
|
51
51
|
}
|
52
52
|
}
|
53
53
|
|
54
|
-
[symbols.conductEarlyTeardown] = async () => {
|
54
|
+
[symbols.conductEarlyTeardown] = async (permanent = false) => {
|
55
55
|
if (this[_ipcServer]) {
|
56
|
-
await this[_ipcServer].onConductEarlyTeardown();
|
56
|
+
await this[_ipcServer].onConductEarlyTeardown({ permanent });
|
57
57
|
}
|
58
58
|
};
|
59
59
|
|
@@ -33,9 +33,9 @@ class DetoxSecondaryContext extends DetoxContext {
|
|
33
33
|
}
|
34
34
|
}
|
35
35
|
|
36
|
-
[symbols.conductEarlyTeardown] = async () => {
|
36
|
+
[symbols.conductEarlyTeardown] = async (permanent = false) => {
|
37
37
|
if (this[_ipcClient]) {
|
38
|
-
await this[_ipcClient].conductEarlyTeardown();
|
38
|
+
await this[_ipcClient].conductEarlyTeardown({ permanent });
|
39
39
|
} else {
|
40
40
|
throw new DetoxInternalError('Detected an attempt to report early teardown using a non-initialized context.');
|
41
41
|
}
|
@@ -1 +0,0 @@
|
|
1
|
-
faf5dc28d8239cc6da3b2bf96b1b29a5
|
@@ -1 +0,0 @@
|
|
1
|
-
66259e139e74a9129e2f568fcdabaa5385713e68
|
@@ -1 +0,0 @@
|
|
1
|
-
9150be4e9ca3b67f6ff6f6df43fcb06cd8e072077992431f578e514bbe9f778f
|
@@ -1 +0,0 @@
|
|
1
|
-
337245632beaeaf3cf9dce4ec6f98a0dee7faaf09e95fc5538781452c532ebb002bc1907b2da230ec47044cf9f31c6dba55dbb00ab16dab8c3af7b643a376974
|
@@ -1 +0,0 @@
|
|
1
|
-
364d1f43c94bb6c771f7c29321e1bc4c
|
@@ -1 +0,0 @@
|
|
1
|
-
1021db825c7835306b90ae34b8d1c294f719990e
|
@@ -1 +0,0 @@
|
|
1
|
-
fb7098e8a4f09fd00b0ac9f123d104bb7298784d055fcbc1d385788c071f0983
|
@@ -1 +0,0 @@
|
|
1
|
-
19a6d854223aba1d9a037ed08f96ea5ac66d4fca81083b9e755bd0f60df0ef55e0cfee4849ed0ddb742c856b4083efeb772da1cd83771d3f56eba813b194d65f
|
Binary file
|
@@ -1 +0,0 @@
|
|
1
|
-
5037d89ac5d98e47d69d63b8731e7e3a
|
@@ -1 +0,0 @@
|
|
1
|
-
b4a0f9db575d92cb2da51c617e0ff531330cc2c6
|
@@ -1 +0,0 @@
|
|
1
|
-
1fa253115965db1c97bc6c8b0c1ab0dff9ac9f8714e063dc972332cc6798b63a
|
@@ -1 +0,0 @@
|
|
1
|
-
8174914ad6abe68c79f4812a32d292e80d922239045a30401bc39f43801f3cd2ea2807786248ffb58e84dfcdb8eddc00c7f606a874eb216def9350d325442af3
|
@@ -1 +0,0 @@
|
|
1
|
-
4ddd8a0d0201920d14cba4ec92fbbc30
|
@@ -1 +0,0 @@
|
|
1
|
-
3ba542128c404b075ca90ee6603104cc1311e0c9
|
@@ -1 +0,0 @@
|
|
1
|
-
c3c239c4180d3fdcc490b06a5848308470e6cf69e23c469716f41d53bf12c32e
|
@@ -1 +0,0 @@
|
|
1
|
-
2a99293177c0028c4839b99fbc16a7afaee90cefb1fc26eb32c3960a71c1cc541b92bc06d6efe38c23932abd14d9b301a72812ce86f700069124805d1e2421c2
|