detox 19.9.3-prerelease.0 → 19.11.0
Sign up to get free protection for your applications and to get access to all the features.
- package/Detox-android/com/wix/detox/{19.9.3-prerelease.0/detox-19.9.3-prerelease.0-javadoc.jar → 19.11.0/detox-19.11.0-javadoc.jar} +0 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0-javadoc.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0-javadoc.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0-javadoc.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0-javadoc.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{19.9.3-prerelease.0/detox-19.9.3-prerelease.0-sources.jar → 19.11.0/detox-19.11.0-sources.jar} +0 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0-sources.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0-sources.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0-sources.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0-sources.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0.aar +0 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0.aar.md5 +1 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0.aar.sha1 +1 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0.aar.sha256 +1 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0.aar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{19.9.3-prerelease.0/detox-19.9.3-prerelease.0.pom → 19.11.0/detox-19.11.0.pom} +1 -1
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0.pom.md5 +1 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0.pom.sha1 +1 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.0.pom.sha256 +1 -0
- package/Detox-android/com/wix/detox/19.11.0/detox-19.11.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/DetoxCrashHandler.kt +1 -1
- package/android/detox/src/full/java/com/wix/detox/LaunchArgs.java +9 -0
- package/android/detox/src/full/java/com/wix/detox/TestEngineFacade.kt +1 -1
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeExtension.kt +15 -2
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeIdlingResources.kt +43 -38
- package/package.json +2 -2
- package/runners/jest-circus/listeners/DetoxCoreListener.js +24 -15
- package/src/DetoxExportWrapper.js +1 -1
- package/src/android/core/NativeElement.js +56 -20
- package/src/android/core/NativeExpect.js +28 -9
- package/src/android/interactions/native.js +24 -18
- package/src/artifacts/timeline/TimelineArtifactPlugin.js +6 -9
- package/src/artifacts/timeline/TimelineContextTypes.js +7 -0
- package/src/client/Client.js +18 -1
- package/src/devices/allocation/DeviceAllocator.js +1 -2
- package/src/devices/allocation/drivers/android/emulator/EmulatorAllocDriver.js +1 -1
- package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +1 -2
- package/src/devices/runtime/RuntimeDevice.js +7 -11
- package/src/devices/runtime/drivers/android/AndroidDriver.js +9 -1
- package/src/ios/expectTwo.js +152 -67
- package/src/utils/invocationTraceDescriptions.js +43 -0
- package/src/utils/trace.js +52 -10
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0-javadoc.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0-javadoc.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0-javadoc.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0-javadoc.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0.aar +0 -0
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0.aar.md5 +0 -1
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0.pom.md5 +0 -1
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox/19.9.3-prerelease.0/detox-19.9.3-prerelease.0.pom.sha512 +0 -1
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
9aba5676c7298fb259def31abb2391c2
|
@@ -0,0 +1 @@
|
|
1
|
+
8489941696f685e4d9ee0f2695e524a9ee882ff7
|
@@ -0,0 +1 @@
|
|
1
|
+
5c074864be82defddfe6f03d23f1023718773a6caf867fd6de97306167b96c10
|
@@ -0,0 +1 @@
|
|
1
|
+
fc404aa3532e1bf13a1e12871b9a4d6c27575cacdfae5b76179308f321091b67d60f5a81e74bd0b3d6304a7930c3a9f79d15015fda37d4cdc5cb849274eb4b6b
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
c607efb999d878b919150d3c868094fe
|
@@ -0,0 +1 @@
|
|
1
|
+
18641f7574235c6ec8c81ea52b75442ce919f213
|
@@ -0,0 +1 @@
|
|
1
|
+
0e23270810340a40547ede0002fb741353646db1878d5825f67a2212a13d3d41
|
@@ -0,0 +1 @@
|
|
1
|
+
440caa1e9ede22144e4f55d2c2c034c13e4b336f9f387f0fa0811bd651612c0bef7981c1b1ae826ab78519185c930a9287a6c6f3c76a554184282fdf8684a344
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
88fff568e621751c02f293579cce453a
|
@@ -0,0 +1 @@
|
|
1
|
+
9398e3ea8573a634ddc61abf4f6b21d9e17ba728
|
@@ -0,0 +1 @@
|
|
1
|
+
ae00e739f49017b43024ff3a508e03dafa7f002b406a746f43f742fa6c21cd15
|
@@ -0,0 +1 @@
|
|
1
|
+
0239c96c8027c9274b6823bfadd5ddea7ca0803db694f53ee30d0d39b8ce5c4dd8d72f4e7d0af089db5d722fecf629e81b62759b5dc4cc434be86910b9b37f5d
|
@@ -3,7 +3,7 @@
|
|
3
3
|
<modelVersion>4.0.0</modelVersion>
|
4
4
|
<groupId>com.wix</groupId>
|
5
5
|
<artifactId>detox</artifactId>
|
6
|
-
<version>19.
|
6
|
+
<version>19.11.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
|
+
2300f079161364c78e01d8c27334ac7f
|
@@ -0,0 +1 @@
|
|
1
|
+
1031ee5586ac864c9b0cbcaa5876dfbc07325f1f
|
@@ -0,0 +1 @@
|
|
1
|
+
25d21ff3daef4e4da80808464fc808efbd4d0fa75f5e88ce9376fb1d85a922d8
|
@@ -0,0 +1 @@
|
|
1
|
+
c1fae4e858403138b44db05d47128f74c1ac8b14a9f55dcae90ef90800040507bb8bdd97af6c64d26811ddcdf14be1a341531e4c8a4fab0323f500167b4d3499
|
@@ -3,11 +3,11 @@
|
|
3
3
|
<groupId>com.wix</groupId>
|
4
4
|
<artifactId>detox</artifactId>
|
5
5
|
<versioning>
|
6
|
-
<latest>19.
|
7
|
-
<release>19.
|
6
|
+
<latest>19.11.0</latest>
|
7
|
+
<release>19.11.0</release>
|
8
8
|
<versions>
|
9
|
-
<version>19.
|
9
|
+
<version>19.11.0</version>
|
10
10
|
</versions>
|
11
|
-
<lastUpdated>
|
11
|
+
<lastUpdated>20220831134632</lastUpdated>
|
12
12
|
</versioning>
|
13
13
|
</metadata>
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
63739c1fd16a9d1140a49b7857aa0fdf
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
0dcec1feec1b37fdf53e88ab4779a702631cd864
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
e1c67c307a105c7c7c82fae75e7d56f8b9718b1bb7dc9f604560909f39dce425
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
c5633deb1fbf020dd6bc03ba8796bd5bd85de50efadc76870c3e5f5cc2b27191bad2a59ea37abb50a96accc373810fa45799d1f60f4dd499637d3eef1f6d8601
|
package/Detox-ios-src.tbz
CHANGED
Binary file
|
package/Detox-ios.tbz
CHANGED
Binary file
|
@@ -6,7 +6,7 @@ import com.wix.detox.adapters.server.OutboundServerAdapter
|
|
6
6
|
class DetoxCrashHandler(private val outboundServerAdapter: OutboundServerAdapter) {
|
7
7
|
fun attach() {
|
8
8
|
Thread.setDefaultUncaughtExceptionHandler { thread, exception ->
|
9
|
-
Log.e(LOG_TAG, "Crash detected!!! thread=${thread.name} (${thread.id})")
|
9
|
+
Log.e(LOG_TAG, "Crash detected!!! thread=${thread.name} (${thread.id})", exception)
|
10
10
|
|
11
11
|
val crashInfo = mapOf("errorDetails" to "@Thread ${thread.name}(${thread.id}):\n${Log.getStackTraceString(exception)}\nCheck device logs for full details!")
|
12
12
|
outboundServerAdapter.sendMessage(ACTION_NAME, crashInfo, MESSAGE_ID)
|
@@ -14,6 +14,7 @@ public class LaunchArgs {
|
|
14
14
|
private static final String DETOX_NOTIFICATION_PATH_ARG = "detoxUserNotificationDataURL";
|
15
15
|
private static final String DETOX_BLACKLIST_URLS_ARG = "detoxURLBlacklistRegex";
|
16
16
|
private static final String DETOX_URL_OVERRIDE_ARG = "detoxURLOverride";
|
17
|
+
private static final String DETOX_ENABLE_SYNCHRONIZATION = "detoxEnableSynchronization";
|
17
18
|
private static final List<String> RESERVED_INSTRUMENTATION_ARGS = Arrays.asList("class", "package", "func", "unit", "size", "perf", "debug", "log", "emma", "coverageFile");
|
18
19
|
|
19
20
|
public boolean hasNotificationPath() {
|
@@ -36,6 +37,14 @@ public class LaunchArgs {
|
|
36
37
|
return InstrumentationRegistry.getArguments().containsKey(DETOX_BLACKLIST_URLS_ARG);
|
37
38
|
}
|
38
39
|
|
40
|
+
public String getEnableSynchronization() {
|
41
|
+
return InstrumentationRegistry.getArguments().getString(DETOX_ENABLE_SYNCHRONIZATION);
|
42
|
+
}
|
43
|
+
|
44
|
+
public boolean hasEnableSynchronization() {
|
45
|
+
return InstrumentationRegistry.getArguments().containsKey(DETOX_ENABLE_SYNCHRONIZATION);
|
46
|
+
}
|
47
|
+
|
39
48
|
public String getUrlOverride() {
|
40
49
|
return InstrumentationRegistry.getArguments().getString(DETOX_URL_OVERRIDE_ARG);
|
41
50
|
}
|
@@ -10,7 +10,7 @@ import com.wix.detox.reactnative.ReactNativeExtension
|
|
10
10
|
|
11
11
|
class TestEngineFacade {
|
12
12
|
fun awaitIdle(): Unit? = Espresso.onIdle() {
|
13
|
-
Log.i(LOG_TAG, "Wait is over:
|
13
|
+
Log.i(LOG_TAG, "Wait is over: App is now idle!")
|
14
14
|
null
|
15
15
|
}
|
16
16
|
fun syncIdle() = UiAutomatorHelper.espressoSync() // TODO Check whether this can be replaced with #awaitIdle()
|
@@ -39,7 +39,7 @@ object ReactNativeExtension {
|
|
39
39
|
reloadReactNativeInBackground(it)
|
40
40
|
val reactContext = awaitNewReactNativeContext(it, previousReactContext)
|
41
41
|
|
42
|
-
|
42
|
+
enableOrDisableSynchronization(reactContext, networkSyncEnabled)
|
43
43
|
hackRN50OrHigherWaitForReady()
|
44
44
|
}
|
45
45
|
}
|
@@ -58,7 +58,7 @@ object ReactNativeExtension {
|
|
58
58
|
(applicationContext as ReactApplication).let {
|
59
59
|
val reactContext = awaitNewReactNativeContext(it, null)
|
60
60
|
|
61
|
-
|
61
|
+
enableOrDisableSynchronization(reactContext)
|
62
62
|
hackRN50OrHigherWaitForReady()
|
63
63
|
}
|
64
64
|
}
|
@@ -124,6 +124,19 @@ object ReactNativeExtension {
|
|
124
124
|
return rnLoadingMonitor.getNewContext()!!
|
125
125
|
}
|
126
126
|
|
127
|
+
private fun enableOrDisableSynchronization(reactContext: ReactContext, networkSyncEnabled: Boolean = true) {
|
128
|
+
if (shouldDisableSynchronization()) {
|
129
|
+
clearAllSynchronization()
|
130
|
+
} else {
|
131
|
+
setupIdlingResources(reactContext, networkSyncEnabled)
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
private fun shouldDisableSynchronization(): Boolean {
|
136
|
+
val launchArgs = LaunchArgs()
|
137
|
+
return launchArgs.hasEnableSynchronization() && launchArgs.enableSynchronization.equals("0")
|
138
|
+
}
|
139
|
+
|
127
140
|
private fun setupIdlingResources(reactContext: ReactContext, networkSyncEnabled: Boolean = true) {
|
128
141
|
val launchArgs = LaunchArgs()
|
129
142
|
|
@@ -2,6 +2,7 @@ package com.wix.detox.reactnative
|
|
2
2
|
|
3
3
|
import android.os.Looper
|
4
4
|
import android.util.Log
|
5
|
+
import androidx.test.espresso.Espresso
|
5
6
|
import androidx.test.espresso.IdlingRegistry
|
6
7
|
import androidx.test.espresso.base.IdlingResourceRegistry
|
7
8
|
import com.facebook.react.bridge.ReactContext
|
@@ -12,7 +13,6 @@ import com.wix.detox.reactnative.idlingresources.timers.getInterrogationStrategy
|
|
12
13
|
import com.wix.detox.reactnative.idlingresources.uimodule.UIModuleIdlingResource
|
13
14
|
import org.joor.Reflect
|
14
15
|
import org.joor.ReflectException
|
15
|
-
import java.util.Set
|
16
16
|
|
17
17
|
private const val LOG_TAG = "DetoxRNIdleRes"
|
18
18
|
|
@@ -46,15 +46,11 @@ private class MQThreadReflected(private val queue: Any?, private val queueName:
|
|
46
46
|
}
|
47
47
|
|
48
48
|
class ReactNativeIdlingResources constructor(
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
{
|
55
|
-
|
49
|
+
private val reactContext: ReactContext,
|
50
|
+
private var launchArgs: LaunchArgs,
|
51
|
+
internal var networkSyncEnabled: Boolean = true
|
52
|
+
) {
|
56
53
|
companion object {
|
57
|
-
private const val FIELD_UI_BG_MSG_QUEUE = "mUiBackgroundMessageQueueThread"
|
58
54
|
private const val FIELD_NATIVE_MODULES_MSG_QUEUE = "mNativeModulesMessageQueueThread"
|
59
55
|
private const val FIELD_JS_MSG_QUEUE = "mJSMessageQueueThread"
|
60
56
|
}
|
@@ -69,17 +65,11 @@ class ReactNativeIdlingResources constructor(
|
|
69
65
|
|
70
66
|
fun registerAll() {
|
71
67
|
Log.i(LOG_TAG, "Setting up Espresso Idling Resources for React Native")
|
72
|
-
|
73
68
|
unregisterAll()
|
74
69
|
|
75
|
-
|
76
|
-
val blacklistUrls = launchArgs.getURLBlacklist()
|
77
|
-
setBlacklistUrls(blacklistUrls)
|
78
|
-
}
|
79
|
-
|
70
|
+
setupUrlBlacklist()
|
80
71
|
setupMQThreadsInterrogators()
|
81
72
|
syncIdlingResources()
|
82
|
-
|
83
73
|
setupCustomRNIdlingResources()
|
84
74
|
syncIdlingResources()
|
85
75
|
}
|
@@ -108,28 +98,42 @@ class ReactNativeIdlingResources constructor(
|
|
108
98
|
networkIdlingResource?.resume()
|
109
99
|
}
|
110
100
|
}
|
101
|
+
|
111
102
|
fun pauseRNTimersIdlingResource() = timersIdlingResource?.pause()
|
112
103
|
fun resumeRNTimersIdlingResource() = timersIdlingResource?.resume()
|
113
104
|
fun pauseUIIdlingResource() = uiModuleIdlingResource?.pause()
|
114
105
|
fun resumeUIIdlingResource() = uiModuleIdlingResource?.resume()
|
115
|
-
|
116
|
-
fun
|
106
|
+
|
107
|
+
fun setBlacklistUrls(urlList: String) {
|
108
|
+
setIldingResourceBlacklist(urlList)
|
109
|
+
}
|
110
|
+
|
111
|
+
private fun setIldingResourceBlacklist(urlList: String) {
|
112
|
+
val urlArray = toFormattedUrlArray(urlList)
|
113
|
+
NetworkIdlingResource.setURLBlacklist(urlArray)
|
114
|
+
}
|
117
115
|
|
118
116
|
private fun setupMQThreadsInterrogators() {
|
119
117
|
if (IdlingRegistry.getInstance().loopers.isEmpty()) {
|
120
118
|
val mqThreadsReflector = MQThreadsReflector(reactContext)
|
121
|
-
// val mqUIBackground = mqThreadsReflector.getQueue(FIELD_UI_BG_MSG_QUEUE)?.getLooper() TODO
|
122
119
|
val mqJS = mqThreadsReflector.getQueue(FIELD_JS_MSG_QUEUE)?.getLooper()
|
123
|
-
val mqNativeModules =
|
120
|
+
val mqNativeModules =
|
121
|
+
mqThreadsReflector.getQueue(FIELD_NATIVE_MODULES_MSG_QUEUE)?.getLooper()
|
124
122
|
|
125
123
|
IdlingRegistry.getInstance().apply {
|
126
|
-
// registerLooperAsIdlingResource(mqUIBackground)
|
127
124
|
registerLooperAsIdlingResource(mqJS)
|
128
125
|
registerLooperAsIdlingResource(mqNativeModules)
|
129
126
|
}
|
130
127
|
}
|
131
128
|
}
|
132
129
|
|
130
|
+
private fun setupUrlBlacklist() {
|
131
|
+
if (launchArgs.hasURLBlacklist()) {
|
132
|
+
val blacklistUrls = launchArgs.urlBlacklist
|
133
|
+
setIldingResourceBlacklist(blacklistUrls)
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
133
137
|
private fun setupCustomRNIdlingResources() {
|
134
138
|
rnBridgeIdlingResource = BridgeIdlingResource(reactContext)
|
135
139
|
timersIdlingResource = TimersIdlingResource(getInterrogationStrategy(reactContext)!!)
|
@@ -151,13 +155,16 @@ class ReactNativeIdlingResources constructor(
|
|
151
155
|
|
152
156
|
private fun syncIdlingResources() {
|
153
157
|
IdlingRegistry.getInstance().apply {
|
154
|
-
val irr: IdlingResourceRegistry =
|
158
|
+
val irr: IdlingResourceRegistry =
|
159
|
+
Reflect.on(Espresso::class.java).field("baseRegistry").get()
|
155
160
|
irr.sync(this.resources, this.loopers)
|
156
161
|
}
|
157
162
|
}
|
158
163
|
|
159
164
|
private fun unregisterMQThreadsInterrogators() {
|
160
|
-
|
165
|
+
val idlingResourceInstance = IdlingRegistry.getInstance()
|
166
|
+
val loopersField = Reflect.on(idlingResourceInstance).field("loopers")
|
167
|
+
loopersField.get<MutableSet<Any>>().clear()
|
161
168
|
}
|
162
169
|
|
163
170
|
private fun unregisterCustomRNIdlingResources() {
|
@@ -166,7 +173,8 @@ class ReactNativeIdlingResources constructor(
|
|
166
173
|
timersIdlingResource,
|
167
174
|
rnBridgeIdlingResource,
|
168
175
|
uiModuleIdlingResource,
|
169
|
-
animIdlingResource
|
176
|
+
animIdlingResource
|
177
|
+
)
|
170
178
|
rnBridgeIdlingResource?.onDetach()
|
171
179
|
|
172
180
|
removeNetworkIdlingResource()
|
@@ -174,13 +182,15 @@ class ReactNativeIdlingResources constructor(
|
|
174
182
|
}
|
175
183
|
|
176
184
|
private fun setupAsyncStorageIdlingResource() {
|
177
|
-
asyncStorageIdlingResource =
|
178
|
-
|
179
|
-
|
185
|
+
asyncStorageIdlingResource =
|
186
|
+
AsyncStorageIdlingResource.createIfNeeded(reactContext, false)?.also {
|
187
|
+
IdlingRegistry.getInstance().register(it)
|
188
|
+
}
|
180
189
|
|
181
|
-
legacyAsyncStorageIdlingResource =
|
182
|
-
|
183
|
-
|
190
|
+
legacyAsyncStorageIdlingResource =
|
191
|
+
AsyncStorageIdlingResource.createIfNeeded(reactContext, true)?.also {
|
192
|
+
IdlingRegistry.getInstance().register(it)
|
193
|
+
}
|
184
194
|
}
|
185
195
|
|
186
196
|
private fun removeAsyncStorageIdlingResource() {
|
@@ -212,13 +222,8 @@ class ReactNativeIdlingResources constructor(
|
|
212
222
|
|
213
223
|
private fun toFormattedUrlArray(urlList: String): List<String> {
|
214
224
|
var formattedUrls = urlList
|
215
|
-
formattedUrls = formattedUrls.replace(Regex("""[()"]"""), "")
|
216
|
-
formattedUrls = formattedUrls.trim()
|
217
|
-
return formattedUrls.split(',')
|
218
|
-
}
|
219
|
-
|
220
|
-
fun setBlacklistUrls(urlList: String) {
|
221
|
-
val urlArray = toFormattedUrlArray(urlList)
|
222
|
-
NetworkIdlingResource.setURLBlacklist(urlArray);
|
225
|
+
formattedUrls = formattedUrls.replace(Regex("""[()"]"""), "")
|
226
|
+
formattedUrls = formattedUrls.trim()
|
227
|
+
return formattedUrls.split(',')
|
223
228
|
}
|
224
229
|
}
|
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": "19.
|
4
|
+
"version": "19.11.0",
|
5
5
|
"bin": {
|
6
6
|
"detox": "local-cli/cli.js"
|
7
7
|
},
|
@@ -177,5 +177,5 @@
|
|
177
177
|
}
|
178
178
|
}
|
179
179
|
},
|
180
|
-
"gitHead": "
|
180
|
+
"gitHead": "900cdb17bd766869cb2d46915ff2c7821808c676"
|
181
181
|
}
|
@@ -22,16 +22,6 @@ class DetoxCoreListener {
|
|
22
22
|
this.detox = detox;
|
23
23
|
}
|
24
24
|
|
25
|
-
_getTestInvocations(test) {
|
26
|
-
const { DETOX_RERUN_INDEX } = process.env;
|
27
|
-
|
28
|
-
if (!isNaN(DETOX_RERUN_INDEX)) {
|
29
|
-
return Number(DETOX_RERUN_INDEX) * this._testRunTimes + test.invocations;
|
30
|
-
} else {
|
31
|
-
return test.invocations;
|
32
|
-
}
|
33
|
-
}
|
34
|
-
|
35
25
|
async run_describe_start({ describeBlock: { name, children } }) {
|
36
26
|
if (children.length) {
|
37
27
|
await this.detox[onRunDescribeStart]({ name });
|
@@ -80,20 +70,39 @@ class DetoxCoreListener {
|
|
80
70
|
this._startedTests.add(test);
|
81
71
|
|
82
72
|
await this.detox[onTestStart]({
|
73
|
+
...this._getTestMetadata(test),
|
74
|
+
status: 'running',
|
75
|
+
});
|
76
|
+
}
|
77
|
+
|
78
|
+
_getTestMetadata(test) {
|
79
|
+
return {
|
83
80
|
title: test.name,
|
81
|
+
parent: test.parent.name,
|
84
82
|
fullName: getFullTestName(test),
|
85
83
|
status: 'running',
|
84
|
+
functionCode: test.fn.toString(),
|
86
85
|
invocations: this._getTestInvocations(test),
|
87
|
-
}
|
86
|
+
};
|
87
|
+
}
|
88
|
+
|
89
|
+
_getTestInvocations(test) {
|
90
|
+
const { DETOX_RERUN_INDEX } = process.env;
|
91
|
+
|
92
|
+
if (!isNaN(DETOX_RERUN_INDEX)) {
|
93
|
+
return Number(DETOX_RERUN_INDEX) * this._testRunTimes + test.invocations;
|
94
|
+
} else {
|
95
|
+
return test.invocations;
|
96
|
+
}
|
88
97
|
}
|
89
98
|
|
90
99
|
async test_done({ test }) {
|
91
100
|
if (this._startedTests.has(test)) {
|
92
101
|
await this.detox[onTestDone]({
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
102
|
+
...this._getTestMetadata(test),
|
103
|
+
status: _.isEmpty(test.errors) ? 'passed' : 'failed',
|
104
|
+
errors: _.isEmpty(test.errors) ? undefined : test.errors,
|
105
|
+
asyncError: _.isEmpty(test.asyncError) ? undefined : test.asyncError,
|
97
106
|
timedOut: hasTimedOut(test)
|
98
107
|
});
|
99
108
|
|
@@ -5,6 +5,7 @@ const tempfile = require('tempfile');
|
|
5
5
|
|
6
6
|
const DetoxRuntimeError = require('../../errors/DetoxRuntimeError');
|
7
7
|
const invoke = require('../../invoke');
|
8
|
+
const { actionDescription } = require('../../utils/invocationTraceDescriptions');
|
8
9
|
const actions = require('../actions/native');
|
9
10
|
const DetoxMatcherApi = require('../espressoapi/DetoxMatcher');
|
10
11
|
const { ActionInteraction } = require('../interactions/native');
|
@@ -18,12 +19,11 @@ class NativeElement {
|
|
18
19
|
}
|
19
20
|
|
20
21
|
_selectElementWithMatcher(matcher) {
|
21
|
-
// if (!(matcher instanceof NativeMatcher)) throw new DetoxRuntimeError(`Element _selectElementWithMatcher argument must be a valid NativeMatcher, got ${typeof matcher}`);
|
22
22
|
this._call = invoke.call(invoke.Espresso, 'onView', matcher._call);
|
23
23
|
}
|
24
24
|
|
25
25
|
atIndex(index) {
|
26
|
-
if (typeof index !== 'number') throw new DetoxRuntimeError(`Element atIndex argument must be a number, got ${typeof index}`);
|
26
|
+
if (typeof index !== 'number') throw new DetoxRuntimeError({ message: `Element atIndex argument must be a number, got ${typeof index}` });
|
27
27
|
const matcher = this._originalMatcher;
|
28
28
|
this._originalMatcher._call = invoke.callDirectly(DetoxMatcherApi.matcherForAtIndex(index, matcher._call.value));
|
29
29
|
|
@@ -32,56 +32,84 @@ class NativeElement {
|
|
32
32
|
}
|
33
33
|
|
34
34
|
async tap(value) {
|
35
|
-
|
35
|
+
const action = new actions.TapAction(value);
|
36
|
+
const traceDescription = actionDescription.tapAtPoint(value);
|
37
|
+
return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
36
38
|
}
|
37
39
|
|
38
40
|
async tapAtPoint(value) {
|
39
|
-
|
41
|
+
const action = new actions.TapAtPointAction(value);
|
42
|
+
const traceDescription = actionDescription.tapAtPoint(value);
|
43
|
+
return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
40
44
|
}
|
41
45
|
|
42
46
|
async longPress() {
|
43
|
-
|
47
|
+
const action = new actions.LongPressAction();
|
48
|
+
const traceDescription = actionDescription.longPress();
|
49
|
+
return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
44
50
|
}
|
45
51
|
|
46
52
|
async multiTap(times) {
|
47
|
-
|
53
|
+
if (typeof times !== 'number') throw new Error('times should be a number, but got ' + (times + (' (' + (typeof times + ')'))));
|
54
|
+
if (times < 1) throw new Error('times should be greater than 0, but got ' + times);
|
55
|
+
|
56
|
+
const action = new actions.MultiClickAction(times);
|
57
|
+
const traceDescription = actionDescription.multiTap(times);
|
58
|
+
return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
48
59
|
}
|
49
60
|
|
50
61
|
async tapBackspaceKey() {
|
51
|
-
|
62
|
+
const action = new actions.PressKeyAction(67);
|
63
|
+
const traceDescription = actionDescription.tapBackspaceKey();
|
64
|
+
return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
52
65
|
}
|
53
66
|
|
54
67
|
async tapReturnKey() {
|
55
|
-
|
68
|
+
const action = new actions.TypeTextAction('\n');
|
69
|
+
const traceDescription = actionDescription.tapReturnKey();
|
70
|
+
return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
56
71
|
}
|
57
72
|
|
58
73
|
async typeText(value) {
|
59
|
-
|
74
|
+
const action = new actions.TypeTextAction(value);
|
75
|
+
const traceDescription = actionDescription.typeText(value);
|
76
|
+
return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
60
77
|
}
|
61
78
|
|
62
79
|
async replaceText(value) {
|
63
|
-
|
80
|
+
const action = new actions.ReplaceTextAction(value);
|
81
|
+
const traceDescription = actionDescription.replaceText(value);
|
82
|
+
return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
64
83
|
}
|
65
84
|
|
66
85
|
async clearText() {
|
67
|
-
|
86
|
+
const action = new actions.ClearTextAction();
|
87
|
+
const traceDescription = actionDescription.clearText();
|
88
|
+
return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
68
89
|
}
|
69
90
|
|
70
91
|
async scroll(amount, direction = 'down', startPositionX, startPositionY) {
|
71
|
-
|
72
|
-
|
73
|
-
return await new ActionInteraction(this._invocationManager, this,
|
92
|
+
const action = new actions.ScrollAmountAction(direction, amount, startPositionX, startPositionY);
|
93
|
+
const traceDescription = actionDescription.scroll(amount, direction, startPositionX, startPositionY);
|
94
|
+
return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
74
95
|
}
|
75
96
|
|
76
97
|
async scrollTo(edge) {
|
77
98
|
// override the user's element selection with an extended matcher that looks for UIScrollView children
|
78
99
|
this._selectElementWithMatcher(this._originalMatcher._extendToDescendantScrollViews());
|
79
|
-
|
100
|
+
|
101
|
+
const action = new actions.ScrollEdgeAction(edge);
|
102
|
+
const traceDescription = actionDescription.scrollTo(edge);
|
103
|
+
return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
80
104
|
}
|
81
105
|
|
82
106
|
async scrollToIndex(index) {
|
107
|
+
// override the user's element selection with an extended matcher that looks for UIScrollView children
|
83
108
|
this._selectElementWithMatcher(this._originalMatcher._extendToDescendantScrollViews());
|
84
|
-
|
109
|
+
|
110
|
+
const action = new actions.ScrollToIndex(index);
|
111
|
+
const traceDescription = actionDescription.scrollToIndex(index);
|
112
|
+
return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
85
113
|
}
|
86
114
|
|
87
115
|
/**
|
@@ -96,13 +124,17 @@ class NativeElement {
|
|
96
124
|
|
97
125
|
// override the user's element selection with an extended matcher that avoids RN issues with RCTScrollView
|
98
126
|
this._selectElementWithMatcher(this._originalMatcher._avoidProblematicReactNativeElements());
|
127
|
+
|
99
128
|
const action = new actions.SwipeAction(direction, speed, normalizedSwipeOffset, normalizedStartingPointX, normalizedStartingPointY);
|
100
|
-
|
129
|
+
const traceDescription = actionDescription.swipe(direction, speed, normalizedSwipeOffset, normalizedStartingPointX, normalizedStartingPointY);
|
130
|
+
return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
101
131
|
}
|
102
132
|
|
103
133
|
async takeScreenshot(screenshotName) {
|
104
134
|
// TODO this should be moved to a lower-layer handler of this use-case
|
105
|
-
const
|
135
|
+
const action = new actions.TakeElementScreenshot();
|
136
|
+
const traceDescription = actionDescription.takeScreenshot(screenshotName);
|
137
|
+
const resultBase64 = await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
106
138
|
const filePath = tempfile('detox.element-screenshot.png');
|
107
139
|
await fs.writeFile(filePath, resultBase64, 'base64');
|
108
140
|
|
@@ -115,12 +147,16 @@ class NativeElement {
|
|
115
147
|
}
|
116
148
|
|
117
149
|
async getAttributes() {
|
118
|
-
const
|
150
|
+
const action = new actions.GetAttributes();
|
151
|
+
const traceDescription = actionDescription.getAttributes();
|
152
|
+
const result = await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
119
153
|
return JSON.parse(result);
|
120
154
|
}
|
121
155
|
|
122
156
|
async adjustSliderToPosition(newPosition) {
|
123
|
-
|
157
|
+
const action = new actions.AdjustSliderToPosition(newPosition);
|
158
|
+
const traceDescription = actionDescription.adjustSliderToPosition(newPosition);
|
159
|
+
return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
|
124
160
|
}
|
125
161
|
}
|
126
162
|
|