detox 20.28.0 → 20.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Detox-android/com/wix/detox/{20.28.0/detox-20.28.0-sources.jar → 20.32.0/detox-20.32.0-sources.jar} +0 -0
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{20.28.0/detox-20.28.0.pom → 20.32.0/detox-20.32.0.pom} +2 -2
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.pom.md5 +1 -0
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.pom.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.pom.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.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-framework.tbz +0 -0
- package/Detox-ios-src.tbz +0 -0
- package/Detox-ios-xcuitest.tbz +0 -0
- package/android/build.gradle +5 -5
- package/android/detox/proguard-rules-app.pro +3 -0
- package/android/detox/src/full/java/com/wix/detox/espresso/EspressoDetox.java +1 -1
- package/android/detox/src/full/java/com/wix/detox/espresso/web/DetoxWebAtomMatcher.java +3 -3
- package/android/detox/src/full/java/com/wix/detox/espresso/web/WebElement.java +0 -1
- package/android/detox/src/full/java/com/wix/detox/espresso/web/WebViewElement.java +33 -8
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeExtension.kt +6 -11
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeInfo.kt +4 -11
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxIdlingResource.kt +42 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/ReactNativeIdlingResources.kt +145 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/animations/AnimatedModuleIdlingResource.kt +61 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/bridge/BridgeIdlingResource.kt +72 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/DetoxIdlingResourceFactory.kt +32 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/IdlingResourcesName.kt +10 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/LooperName.kt +6 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/looper/MQThreadsReflector.kt +47 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/network/NetworkIdlingResource.kt +105 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/{NetworkingModuleReflected.kt → network/NetworkingModuleReflected.kt} +1 -1
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/{AsyncStorageIdlingResource.kt → storage/AsyncStorageIdlingResource.kt} +33 -35
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/{SerialExecutorReflected.kt → storage/SerialExecutorReflected.kt} +1 -1
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResource.kt +21 -19
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIManagerModuleReflected.kt +19 -27
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIModuleIdlingResource.kt +5 -17
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResourceTest.kt +248 -0
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResourcesTest.kt +5 -1
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/SerialExecutorReflectedSpec.kt +1 -0
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResourceTest.kt +212 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +1 -1
- package/android/rninfo.gradle +31 -24
- package/android/settings.gradle +11 -6
- package/package.json +11 -8
- package/scripts/postinstall.js +2 -2
- package/scripts/updateGradle.js +41 -8
- package/src/DetoxWorker.js +11 -6
- package/src/copilot/DetoxCopilot.js +3 -15
- package/src/devices/allocation/drivers/android/genycloud/exec/GenyCloudExec.js +14 -8
- package/src/devices/validation/android/GenycloudEnvValidator.js +20 -3
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.md5 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.sha512 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar +0 -0
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar +0 -0
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.md5 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom +0 -100
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom.md5 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom.sha512 +0 -1
- package/Detox-android/com/wix/detox-legacy/maven-metadata.xml +0 -13
- package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.md5 +0 -1
- package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha1 +0 -1
- package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha256 +0 -1
- package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha512 +0 -1
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeIdlingResources.kt +0 -229
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/AnimatedModuleIdlingResource.java +0 -215
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/BridgeIdlingResource.java +0 -94
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxBaseIdlingResource.java +0 -29
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResource.java +0 -134
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategy.kt +0 -23
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/IdleInterrogationStrategy.kt +0 -16
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/RN66Workaround.kt +0 -71
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResourceSpec.kt +0 -227
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategySpec.kt +0 -47
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResourceSpec.kt +0 -189
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
eee5ef30145285d5cb57b7a09afb8304
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
f454322216a38a2a565504eeeee3097cdf210dd0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bde47b3d7df6f70cc9812e1232aa5781a4dbfbd923ca52c6097ab9ea880eb207
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
175ce023c440c5903a33af31f0ce39e603c6c930fa05ddf5a38f070cd99b29fc6ee2e82b816bc60507c7c4729e9c0b1d8d1247ecc4b6b75455e0924d397dfe37
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
c5f3daffcbc4e0f545784d563efc793c
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
fd392c76debf7d9afdbfd9f7eb0c48766395bd82
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
f6623de89efe2e0b49241ef2c9ec3fee79cf3d84e7dbf5d2f00d762427a32cab
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
92906ac80969295c0ca21b3428801173fa48bb93ffc0ff2450f2d74af4a6c2b6c9afdcb07c49bd46f2bb791317b8dd43bd30ff5801839fa3c7deafd6c8348548
|
|
@@ -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.32.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>
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
<dependency>
|
|
34
34
|
<groupId>org.jetbrains.kotlin</groupId>
|
|
35
35
|
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
|
36
|
-
<version>1.
|
|
36
|
+
<version>1.9.24</version>
|
|
37
37
|
<scope>compile</scope>
|
|
38
38
|
</dependency>
|
|
39
39
|
<dependency>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
8a89efbe63dd0bb5e8263bd728b2a6ce
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
73079f2074231a904b98113f686c7b7f8df79ad7
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
4c76f2991c6d5bb6fd4a883542bac697c8e3e49d1816e59f36b5b3678c6ae6ab
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
b856a9916b7e864eeb2226d29b56c5bea595545c7cb82e8c33619357fdfbf9a942201f1ecd70b57fb5499c5b59d38a1e4fc13bee6a84eaf2b75e2b630faeb6f7
|
|
@@ -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.32.0</latest>
|
|
7
|
+
<release>20.32.0</release>
|
|
8
8
|
<versions>
|
|
9
|
-
<version>20.
|
|
9
|
+
<version>20.32.0</version>
|
|
10
10
|
</versions>
|
|
11
|
-
<lastUpdated>
|
|
11
|
+
<lastUpdated>20250106191456</lastUpdated>
|
|
12
12
|
</versioning>
|
|
13
13
|
</metadata>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
a21a21f5f33f0521ea5b27a6b7c9a53d
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
3c0a9c339f4d397ac37a6779311c1c121ab01863
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
fa21aff43ff2f349f95760a2467987cef206152f4277db7d005193124667457b
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
91de105f632722548240b0ce79abfa9758dfb44827badc8828bdb09404f917038e5e2157757003141f2d676cf641b9734f063ea0f950e01842d491d3eb8f04fc
|
package/Detox-ios-framework.tbz
CHANGED
|
Binary file
|
package/Detox-ios-src.tbz
CHANGED
|
Binary file
|
package/Detox-ios-xcuitest.tbz
CHANGED
|
Binary file
|
package/android/build.gradle
CHANGED
|
@@ -3,12 +3,12 @@ buildscript {
|
|
|
3
3
|
|
|
4
4
|
ext {
|
|
5
5
|
isOfficialDetoxLib = true
|
|
6
|
-
kotlinVersion = '1.
|
|
6
|
+
kotlinVersion = '1.9.24'
|
|
7
7
|
dokkaVersion = '1.9.10'
|
|
8
|
-
buildToolsVersion = '
|
|
9
|
-
compileSdkVersion =
|
|
10
|
-
targetSdkVersion =
|
|
11
|
-
minSdkVersion =
|
|
8
|
+
buildToolsVersion = '35.0.0'
|
|
9
|
+
compileSdkVersion = 35
|
|
10
|
+
targetSdkVersion = 35
|
|
11
|
+
minSdkVersion = 24
|
|
12
12
|
}
|
|
13
13
|
ext.detoxKotlinVersion = ext.kotlinVersion
|
|
14
14
|
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
-keep class com.facebook.react.ReactInstanceManager { *; }
|
|
9
9
|
-keep class com.facebook.react.ReactInstanceManager** { *; }
|
|
10
10
|
-keep class com.facebook.react.ReactInstanceEventListener { *; }
|
|
11
|
+
-keep class com.facebook.react.soloader.OpenSourceMergedSoMapping { *; }
|
|
12
|
+
-keep class com.facebook.soloader.SoLoader { *; }
|
|
13
|
+
-keep class com.facebook.soloader.ExternalSoMapping { *; }
|
|
11
14
|
|
|
12
15
|
-keep class com.facebook.react.views.slider.** { *; }
|
|
13
16
|
-keep class com.google.android.material.slider.** { *; }
|
|
@@ -13,7 +13,7 @@ import android.view.ViewGroup;
|
|
|
13
13
|
import com.facebook.react.ReactApplication;
|
|
14
14
|
import com.wix.detox.common.UIThread;
|
|
15
15
|
import com.wix.detox.reactnative.ReactNativeExtension;
|
|
16
|
-
import com.wix.detox.reactnative.idlingresources.NetworkIdlingResource;
|
|
16
|
+
import com.wix.detox.reactnative.idlingresources.network.NetworkIdlingResource;
|
|
17
17
|
|
|
18
18
|
import org.hamcrest.Matcher;
|
|
19
19
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
package com.wix.detox.espresso.web;
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
import static androidx.test.espresso.web.webdriver.DriverAtoms.findMultipleElements;
|
|
5
|
+
|
|
4
6
|
import androidx.test.espresso.web.model.Atom;
|
|
5
7
|
import androidx.test.espresso.web.model.ElementReference;
|
|
6
8
|
import androidx.test.espresso.web.webdriver.Locator;
|
|
7
9
|
|
|
8
10
|
import java.util.List;
|
|
9
11
|
|
|
10
|
-
import static androidx.test.espresso.web.webdriver.DriverAtoms.findMultipleElements;
|
|
11
|
-
|
|
12
12
|
public class DetoxWebAtomMatcher {
|
|
13
13
|
|
|
14
14
|
private DetoxWebAtomMatcher() {
|
|
@@ -46,4 +46,4 @@ public class DetoxWebAtomMatcher {
|
|
|
46
46
|
public static Atom<List<ElementReference>> matcherForTagName(String tag) {
|
|
47
47
|
return findMultipleElements(Locator.TAG_NAME, tag);
|
|
48
48
|
}
|
|
49
|
-
}
|
|
49
|
+
}
|
|
@@ -3,7 +3,6 @@ package com.wix.detox.espresso.web;
|
|
|
3
3
|
import androidx.test.espresso.web.model.Atom;
|
|
4
4
|
import androidx.test.espresso.web.model.Atoms;
|
|
5
5
|
import androidx.test.espresso.web.model.ElementReference;
|
|
6
|
-
import androidx.test.espresso.web.model.Evaluation;
|
|
7
6
|
import androidx.test.espresso.web.model.SimpleAtom;
|
|
8
7
|
import androidx.test.espresso.web.sugar.Web;
|
|
9
8
|
import androidx.test.espresso.web.webdriver.DriverAtoms;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
package com.wix.detox.espresso.web;
|
|
2
2
|
|
|
3
|
+
import static androidx.test.espresso.web.sugar.Web.onWebView;
|
|
4
|
+
|
|
3
5
|
import android.view.View;
|
|
4
6
|
import android.webkit.WebView;
|
|
5
7
|
|
|
@@ -7,24 +9,47 @@ import androidx.test.espresso.web.model.Atom;
|
|
|
7
9
|
import androidx.test.espresso.web.model.ElementReference;
|
|
8
10
|
import androidx.test.espresso.web.sugar.Web;
|
|
9
11
|
|
|
10
|
-
import org.hamcrest.
|
|
12
|
+
import org.hamcrest.Description;
|
|
11
13
|
import org.hamcrest.Matcher;
|
|
14
|
+
import org.hamcrest.TypeSafeMatcher;
|
|
12
15
|
|
|
13
16
|
import java.util.List;
|
|
14
17
|
|
|
15
18
|
import javax.annotation.Nullable;
|
|
16
19
|
|
|
17
|
-
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
|
18
|
-
import static androidx.test.espresso.web.sugar.Web.onWebView;
|
|
19
|
-
import static org.hamcrest.CoreMatchers.allOf;
|
|
20
|
-
|
|
21
20
|
public class WebViewElement {
|
|
22
21
|
|
|
23
|
-
final
|
|
22
|
+
private final static String WRAPPER_WEBVIEW_CLASS_NAME = "RNCWebViewWrapper";
|
|
23
|
+
|
|
24
24
|
final Web.WebInteraction<Void> webViewInteraction;
|
|
25
25
|
|
|
26
|
-
WebViewElement(@Nullable Matcher<View>
|
|
27
|
-
|
|
26
|
+
WebViewElement(@Nullable Matcher<View> userMatcher) {
|
|
27
|
+
Matcher<View> matcher = null;
|
|
28
|
+
|
|
29
|
+
if (userMatcher != null) {
|
|
30
|
+
matcher = new TypeSafeMatcher<>() {
|
|
31
|
+
|
|
32
|
+
@Override
|
|
33
|
+
protected boolean matchesSafely(View item) {
|
|
34
|
+
// Support for react-native-webview >= 13.0.0
|
|
35
|
+
if (item instanceof WebView && item.getParent().getClass().getSimpleName().equals(WRAPPER_WEBVIEW_CLASS_NAME)) {
|
|
36
|
+
return userMatcher.matches(item.getParent());
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (item.getClass().getSimpleName().equals("RNCWebViewWrapper")) {
|
|
40
|
+
// We never want to match the wrapper of the webview
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return userMatcher.matches(item);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@Override
|
|
48
|
+
public void describeTo(Description description) {
|
|
49
|
+
userMatcher.describeTo(description);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
28
53
|
this.webViewInteraction = matcher != null ? onWebView(matcher) : onWebView();
|
|
29
54
|
}
|
|
30
55
|
|
|
@@ -8,6 +8,7 @@ import com.facebook.react.ReactApplication
|
|
|
8
8
|
import com.facebook.react.ReactInstanceManager
|
|
9
9
|
import com.facebook.react.bridge.ReactContext
|
|
10
10
|
import com.wix.detox.LaunchArgs
|
|
11
|
+
import com.wix.detox.reactnative.idlingresources.ReactNativeIdlingResources
|
|
11
12
|
|
|
12
13
|
private const val LOG_TAG = "DetoxRNExt"
|
|
13
14
|
|
|
@@ -56,7 +57,6 @@ object ReactNativeExtension {
|
|
|
56
57
|
Log.i(LOG_TAG, "Reloading React Native")
|
|
57
58
|
|
|
58
59
|
(applicationContext as ReactApplication).let {
|
|
59
|
-
val networkSyncEnabled = rnIdlingResources?.networkSyncEnabled ?: true
|
|
60
60
|
clearIdlingResources()
|
|
61
61
|
|
|
62
62
|
val previousReactContext = getCurrentReactContextSafe(it)
|
|
@@ -64,7 +64,7 @@ object ReactNativeExtension {
|
|
|
64
64
|
reloadReactNativeInBackground(it)
|
|
65
65
|
val reactContext = awaitNewReactNativeContext(it, previousReactContext)
|
|
66
66
|
|
|
67
|
-
enableOrDisableSynchronization(reactContext
|
|
67
|
+
enableOrDisableSynchronization(reactContext)
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -93,11 +93,6 @@ object ReactNativeExtension {
|
|
|
93
93
|
return null
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
@JvmStatic
|
|
97
|
-
fun setNetworkSynchronization(enable: Boolean) {
|
|
98
|
-
rnIdlingResources?.setNetworkSynchronization(enable)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
96
|
@JvmStatic
|
|
102
97
|
fun toggleNetworkSynchronization(enable: Boolean) {
|
|
103
98
|
rnIdlingResources?.let {
|
|
@@ -129,11 +124,11 @@ object ReactNativeExtension {
|
|
|
129
124
|
return rnLoadingMonitor.getNewContext()!!
|
|
130
125
|
}
|
|
131
126
|
|
|
132
|
-
private fun enableOrDisableSynchronization(reactContext: ReactContext
|
|
127
|
+
private fun enableOrDisableSynchronization(reactContext: ReactContext) {
|
|
133
128
|
if (shouldDisableSynchronization()) {
|
|
134
129
|
clearAllSynchronization()
|
|
135
130
|
} else {
|
|
136
|
-
setupIdlingResources(reactContext
|
|
131
|
+
setupIdlingResources(reactContext)
|
|
137
132
|
}
|
|
138
133
|
}
|
|
139
134
|
|
|
@@ -142,10 +137,10 @@ object ReactNativeExtension {
|
|
|
142
137
|
return launchArgs.hasEnableSynchronization() && launchArgs.enableSynchronization.equals("0")
|
|
143
138
|
}
|
|
144
139
|
|
|
145
|
-
private fun setupIdlingResources(reactContext: ReactContext
|
|
140
|
+
private fun setupIdlingResources(reactContext: ReactContext) {
|
|
146
141
|
val launchArgs = LaunchArgs()
|
|
147
142
|
|
|
148
|
-
rnIdlingResources = ReactNativeIdlingResources(reactContext, launchArgs
|
|
143
|
+
rnIdlingResources = ReactNativeIdlingResources(reactContext, launchArgs).apply {
|
|
149
144
|
registerAll()
|
|
150
145
|
}
|
|
151
146
|
}
|
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
package com.wix.detox.reactnative
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import java.util.Map
|
|
3
|
+
import com.facebook.react.modules.systeminfo.ReactNativeVersion
|
|
5
4
|
|
|
6
5
|
data class RNVersion(val major: Int, val minor: Int, val patch: Int)
|
|
7
6
|
|
|
8
7
|
object ReactNativeInfo {
|
|
9
|
-
private var rnVersion: RNVersion =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
val versionMap: Map<String, Int> = Reflect.on(versionClass).field("VERSION").get()
|
|
13
|
-
RNVersion(versionMap.get("major")!!, versionMap.get("minor")!!, versionMap.get("patch")!!)
|
|
14
|
-
} catch (e: ClassNotFoundException) {
|
|
15
|
-
// ReactNativeVersion was introduced in RN50, default to latest previous version.
|
|
16
|
-
RNVersion(0, 49, 0)
|
|
17
|
-
}
|
|
8
|
+
private var rnVersion: RNVersion = ReactNativeVersion.VERSION.run {
|
|
9
|
+
RNVersion(get("major") as Int, get("minor") as Int, get("patch") as Int)
|
|
10
|
+
}
|
|
18
11
|
|
|
19
12
|
@JvmStatic
|
|
20
13
|
fun rnVersion() = rnVersion
|
package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxIdlingResource.kt
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
package com.wix.detox.reactnative.idlingresources
|
|
2
|
+
|
|
3
|
+
import androidx.test.espresso.IdlingResource
|
|
4
|
+
import com.wix.detox.espresso.idlingresources.DescriptiveIdlingResource
|
|
5
|
+
import java.util.concurrent.atomic.AtomicBoolean
|
|
6
|
+
|
|
7
|
+
abstract class DetoxIdlingResource : DescriptiveIdlingResource {
|
|
8
|
+
private var callback: IdlingResource.ResourceCallback? = null
|
|
9
|
+
private var paused: AtomicBoolean = AtomicBoolean(false)
|
|
10
|
+
|
|
11
|
+
fun pause() {
|
|
12
|
+
paused.set(true)
|
|
13
|
+
notifyIdle()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fun resume() {
|
|
17
|
+
paused.set(false)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
|
|
22
|
+
this.callback = callback
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
final override fun isIdleNow(): Boolean {
|
|
26
|
+
if (paused.get()) {
|
|
27
|
+
return true
|
|
28
|
+
}
|
|
29
|
+
return checkIdle()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
open fun onUnregistered() {
|
|
33
|
+
// no-op
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
protected abstract fun checkIdle(): Boolean
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
fun notifyIdle() {
|
|
40
|
+
callback?.onTransitionToIdle()
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
package com.wix.detox.reactnative.idlingresources
|
|
2
|
+
|
|
3
|
+
import android.os.Looper
|
|
4
|
+
import android.util.Log
|
|
5
|
+
import androidx.test.espresso.Espresso
|
|
6
|
+
import androidx.test.espresso.IdlingRegistry
|
|
7
|
+
import androidx.test.espresso.base.IdlingResourceRegistry
|
|
8
|
+
import com.facebook.react.bridge.ReactContext
|
|
9
|
+
import com.wix.detox.LaunchArgs
|
|
10
|
+
import com.wix.detox.reactnative.idlingresources.factory.DetoxIdlingResourceFactory
|
|
11
|
+
import com.wix.detox.reactnative.idlingresources.factory.IdlingResourcesName
|
|
12
|
+
import com.wix.detox.reactnative.idlingresources.factory.LooperName
|
|
13
|
+
import com.wix.detox.reactnative.idlingresources.looper.MQThreadsReflector
|
|
14
|
+
import com.wix.detox.reactnative.idlingresources.network.NetworkIdlingResource
|
|
15
|
+
import kotlinx.coroutines.runBlocking
|
|
16
|
+
import org.joor.Reflect
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
private const val LOG_TAG = "DetoxRNIdleRes"
|
|
20
|
+
|
|
21
|
+
class ReactNativeIdlingResources(
|
|
22
|
+
private val reactContext: ReactContext,
|
|
23
|
+
private var launchArgs: LaunchArgs,
|
|
24
|
+
private val idlingResourcesFactory: DetoxIdlingResourceFactory = DetoxIdlingResourceFactory(reactContext)
|
|
25
|
+
) {
|
|
26
|
+
|
|
27
|
+
private val idlingResources = mutableMapOf<IdlingResourcesName, DetoxIdlingResource>()
|
|
28
|
+
private val loopers = mutableMapOf<LooperName, Looper>()
|
|
29
|
+
|
|
30
|
+
fun registerAll() {
|
|
31
|
+
runBlocking {
|
|
32
|
+
Log.i(LOG_TAG, "Setting up Espresso Idling Resources for React Native")
|
|
33
|
+
unregisterAll()
|
|
34
|
+
|
|
35
|
+
setupUrlBlacklist()
|
|
36
|
+
setupMQThreadsInterrogators()
|
|
37
|
+
syncIdlingResources()
|
|
38
|
+
setupIdlingResources()
|
|
39
|
+
syncIdlingResources()
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
fun unregisterAll() {
|
|
44
|
+
unregisterMQThreadsInterrogators()
|
|
45
|
+
unregisterIdlingResources()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fun pauseNetworkSynchronization() = pauseIdlingResource(IdlingResourcesName.Network)
|
|
49
|
+
fun resumeNetworkSynchronization() {
|
|
50
|
+
resumeIdlingResource(IdlingResourcesName.Network)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
fun pauseRNTimersIdlingResource() = pauseIdlingResource(IdlingResourcesName.Timers)
|
|
54
|
+
fun resumeRNTimersIdlingResource() = resumeIdlingResource(IdlingResourcesName.Timers)
|
|
55
|
+
fun pauseUIIdlingResource() = pauseIdlingResource(IdlingResourcesName.UIModule)
|
|
56
|
+
fun resumeUIIdlingResource() = resumeIdlingResource(IdlingResourcesName.UIModule)
|
|
57
|
+
|
|
58
|
+
fun setBlacklistUrls(urlList: String) {
|
|
59
|
+
setIdlingResourceBlacklist(urlList)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private fun setIdlingResourceBlacklist(urlList: String) {
|
|
63
|
+
val urlArray = toFormattedUrlArray(urlList)
|
|
64
|
+
NetworkIdlingResource.setURLBlacklist(urlArray)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private fun setupMQThreadsInterrogators() {
|
|
68
|
+
setupMQThreadsInterrogator(LooperName.JS)
|
|
69
|
+
setupMQThreadsInterrogator(LooperName.NativeModules)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private fun setupUrlBlacklist() {
|
|
73
|
+
if (launchArgs.hasURLBlacklist()) {
|
|
74
|
+
val blacklistUrls = launchArgs.urlBlacklist
|
|
75
|
+
setIdlingResourceBlacklist(blacklistUrls)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private fun setupMQThreadsInterrogator(looperName: LooperName) {
|
|
80
|
+
val mqThreadsReflector = MQThreadsReflector(reactContext)
|
|
81
|
+
val looper = when (looperName) {
|
|
82
|
+
LooperName.JS -> mqThreadsReflector.getJSMQueue()?.getLooper()
|
|
83
|
+
LooperName.NativeModules -> mqThreadsReflector.getNativeModulesQueue()?.getLooper()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
looper?.let {
|
|
87
|
+
IdlingRegistry.getInstance().registerLooperAsIdlingResource(it)
|
|
88
|
+
loopers[looperName] = it
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private suspend fun setupIdlingResources() {
|
|
93
|
+
idlingResources.putAll(idlingResourcesFactory.create())
|
|
94
|
+
idlingResources.forEach { (_, idlingResource) ->
|
|
95
|
+
IdlingRegistry.getInstance().register(idlingResource)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private fun syncIdlingResources() {
|
|
100
|
+
IdlingRegistry.getInstance().apply {
|
|
101
|
+
val irr: IdlingResourceRegistry =
|
|
102
|
+
Reflect.on(Espresso::class.java).field("baseRegistry").get()
|
|
103
|
+
irr.sync(this.resources, this.loopers)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private fun unregisterMQThreadsInterrogators() {
|
|
108
|
+
loopers.values.forEach {
|
|
109
|
+
IdlingRegistry.getInstance().unregisterLooperAsIdlingResource(it)
|
|
110
|
+
}
|
|
111
|
+
loopers.clear()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private fun unregisterIdlingResources() {
|
|
115
|
+
IdlingResourcesName.entries.forEach {
|
|
116
|
+
removeIdlingResource(it)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private fun pauseIdlingResource(idlingResourcesName: IdlingResourcesName) {
|
|
121
|
+
val idlingResource = idlingResources[idlingResourcesName]
|
|
122
|
+
idlingResource?.pause()
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private fun resumeIdlingResource(idlingResourcesName: IdlingResourcesName) {
|
|
126
|
+
val idlingResource = idlingResources[idlingResourcesName]
|
|
127
|
+
idlingResource?.resume()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private fun removeIdlingResource(idlingResourcesName: IdlingResourcesName) {
|
|
131
|
+
val idlingResource = idlingResources[idlingResourcesName]
|
|
132
|
+
idlingResource?.let {
|
|
133
|
+
IdlingRegistry.getInstance().unregister(it)
|
|
134
|
+
idlingResource.onUnregistered()
|
|
135
|
+
idlingResources.remove(idlingResourcesName)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private fun toFormattedUrlArray(urlList: String): List<String> {
|
|
140
|
+
var formattedUrls = urlList
|
|
141
|
+
formattedUrls = formattedUrls.replace(Regex("""[()"]"""), "")
|
|
142
|
+
formattedUrls = formattedUrls.trim()
|
|
143
|
+
return formattedUrls.split(',')
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
package com.wix.detox.reactnative.idlingresources.animations
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import android.view.Choreographer
|
|
5
|
+
import androidx.test.espresso.IdlingResource.ResourceCallback
|
|
6
|
+
import com.facebook.react.animated.NativeAnimatedModule
|
|
7
|
+
import com.facebook.react.bridge.ReactContext
|
|
8
|
+
import com.wix.detox.reactnative.idlingresources.DetoxIdlingResource
|
|
9
|
+
|
|
10
|
+
private const val LOG_TAG = "Detox"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Created by simonracz on 25/08/2017.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
*
|
|
18
|
+
* Espresso IdlingResource for React Native's Animated Module.
|
|
19
|
+
*
|
|
20
|
+
*
|
|
21
|
+
* Hooks up to React Native internals to monitor the state of the animations.
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
class AnimatedModuleIdlingResource(private val reactContext: ReactContext) : DetoxIdlingResource(),
|
|
25
|
+
Choreographer.FrameCallback {
|
|
26
|
+
|
|
27
|
+
override fun getName() = AnimatedModuleIdlingResource::class.java.name
|
|
28
|
+
|
|
29
|
+
override fun getDebugName(): String {
|
|
30
|
+
return "AnimatedModule"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
override fun getBusyHint(): Map<String, Any> {
|
|
34
|
+
return mapOf("reason" to "Animations running on screen")
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
override fun checkIdle(): Boolean {
|
|
38
|
+
val animatedModule = reactContext.getNativeModule(NativeAnimatedModule::class.java)
|
|
39
|
+
val hasAnimations = animatedModule?.nodesManager?.hasActiveAnimations() ?: false
|
|
40
|
+
|
|
41
|
+
if (hasAnimations) {
|
|
42
|
+
Log.i(LOG_TAG, "AnimatedModule is busy.")
|
|
43
|
+
Choreographer.getInstance().postFrameCallback(this)
|
|
44
|
+
return false
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
notifyIdle()
|
|
48
|
+
return true
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
override fun registerIdleTransitionCallback(callback: ResourceCallback?) {
|
|
52
|
+
super.registerIdleTransitionCallback(callback)
|
|
53
|
+
Choreographer.getInstance().postFrameCallback(this)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
override fun doFrame(frameTimeNanos: Long) {
|
|
57
|
+
isIdleNow
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
package com.wix.detox.reactnative.idlingresources.bridge
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener
|
|
5
|
+
import com.facebook.react.bridge.ReactContext
|
|
6
|
+
import com.wix.detox.reactnative.idlingresources.DetoxIdlingResource
|
|
7
|
+
import java.util.concurrent.atomic.AtomicBoolean
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Created by simonracz on 01/06/2017.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
*
|
|
15
|
+
* IdlingResource for Espresso, which monitors the traffic of
|
|
16
|
+
* React Native's JS bridge.
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
class BridgeIdlingResource(private val reactContext: ReactContext) : DetoxIdlingResource(),
|
|
20
|
+
NotThreadSafeBridgeIdleDebugListener {
|
|
21
|
+
private val idleNow = AtomicBoolean(true)
|
|
22
|
+
|
|
23
|
+
init {
|
|
24
|
+
reactContext.catalystInstance.addBridgeIdleDebugListener(this)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fun onDetach() {
|
|
28
|
+
reactContext.catalystInstance.removeBridgeIdleDebugListener(this)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
override fun getName(): String {
|
|
32
|
+
return BridgeIdlingResource::class.java.name
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
override fun getDebugName(): String {
|
|
36
|
+
return "bridge"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override fun getBusyHint(): Map<String, Any>? {
|
|
40
|
+
return null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override fun checkIdle(): Boolean {
|
|
44
|
+
val ret = idleNow.get()
|
|
45
|
+
if (!ret) {
|
|
46
|
+
Log.i(LOG_TAG, "JS Bridge is busy")
|
|
47
|
+
}
|
|
48
|
+
return ret
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
override fun onTransitionToBridgeIdle() {
|
|
52
|
+
idleNow.set(true)
|
|
53
|
+
notifyIdle()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
override fun onTransitionToBridgeBusy() {
|
|
57
|
+
idleNow.set(false)
|
|
58
|
+
// Log.i(LOG_TAG, "JS Bridge transitions to busy.");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
override fun onBridgeDestroyed() {
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
override fun onUnregistered() {
|
|
65
|
+
super.onUnregistered()
|
|
66
|
+
onDetach()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
companion object {
|
|
70
|
+
private const val LOG_TAG = "Detox"
|
|
71
|
+
}
|
|
72
|
+
}
|