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.
Files changed (104) hide show
  1. 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
  2. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar +0 -0
  7. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/{20.28.0/detox-20.28.0.pom → 20.32.0/detox-20.32.0.pom} +2 -2
  12. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.pom.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.pom.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.pom.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.pom.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  17. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  18. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  19. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  20. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  21. package/Detox-ios-framework.tbz +0 -0
  22. package/Detox-ios-src.tbz +0 -0
  23. package/Detox-ios-xcuitest.tbz +0 -0
  24. package/android/build.gradle +5 -5
  25. package/android/detox/proguard-rules-app.pro +3 -0
  26. package/android/detox/src/full/java/com/wix/detox/espresso/EspressoDetox.java +1 -1
  27. package/android/detox/src/full/java/com/wix/detox/espresso/web/DetoxWebAtomMatcher.java +3 -3
  28. package/android/detox/src/full/java/com/wix/detox/espresso/web/WebElement.java +0 -1
  29. package/android/detox/src/full/java/com/wix/detox/espresso/web/WebViewElement.java +33 -8
  30. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeExtension.kt +6 -11
  31. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeInfo.kt +4 -11
  32. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxIdlingResource.kt +42 -0
  33. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/ReactNativeIdlingResources.kt +145 -0
  34. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/animations/AnimatedModuleIdlingResource.kt +61 -0
  35. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/bridge/BridgeIdlingResource.kt +72 -0
  36. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/DetoxIdlingResourceFactory.kt +32 -0
  37. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/IdlingResourcesName.kt +10 -0
  38. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/LooperName.kt +6 -0
  39. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/looper/MQThreadsReflector.kt +47 -0
  40. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/network/NetworkIdlingResource.kt +105 -0
  41. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/{NetworkingModuleReflected.kt → network/NetworkingModuleReflected.kt} +1 -1
  42. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/{AsyncStorageIdlingResource.kt → storage/AsyncStorageIdlingResource.kt} +33 -35
  43. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/{SerialExecutorReflected.kt → storage/SerialExecutorReflected.kt} +1 -1
  44. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResource.kt +21 -19
  45. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIManagerModuleReflected.kt +19 -27
  46. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIModuleIdlingResource.kt +5 -17
  47. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResourceTest.kt +248 -0
  48. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResourcesTest.kt +5 -1
  49. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/SerialExecutorReflectedSpec.kt +1 -0
  50. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResourceTest.kt +212 -0
  51. package/android/gradle/wrapper/gradle-wrapper.properties +1 -1
  52. package/android/rninfo.gradle +31 -24
  53. package/android/settings.gradle +11 -6
  54. package/package.json +11 -8
  55. package/scripts/postinstall.js +2 -2
  56. package/scripts/updateGradle.js +41 -8
  57. package/src/DetoxWorker.js +11 -6
  58. package/src/copilot/DetoxCopilot.js +3 -15
  59. package/src/devices/allocation/drivers/android/genycloud/exec/GenyCloudExec.js +14 -8
  60. package/src/devices/validation/android/GenycloudEnvValidator.js +20 -3
  61. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.md5 +0 -1
  62. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.sha1 +0 -1
  63. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.sha256 +0 -1
  64. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.sha512 +0 -1
  65. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar +0 -0
  66. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.md5 +0 -1
  67. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.sha1 +0 -1
  68. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.sha256 +0 -1
  69. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.sha512 +0 -1
  70. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.md5 +0 -1
  71. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.sha1 +0 -1
  72. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.sha256 +0 -1
  73. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.sha512 +0 -1
  74. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar +0 -0
  75. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.md5 +0 -1
  76. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.sha1 +0 -1
  77. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.sha256 +0 -1
  78. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.sha512 +0 -1
  79. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar +0 -0
  80. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.md5 +0 -1
  81. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.sha1 +0 -1
  82. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.sha256 +0 -1
  83. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.sha512 +0 -1
  84. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom +0 -100
  85. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom.md5 +0 -1
  86. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom.sha1 +0 -1
  87. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom.sha256 +0 -1
  88. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom.sha512 +0 -1
  89. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml +0 -13
  90. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.md5 +0 -1
  91. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha1 +0 -1
  92. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha256 +0 -1
  93. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha512 +0 -1
  94. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeIdlingResources.kt +0 -229
  95. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/AnimatedModuleIdlingResource.java +0 -215
  96. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/BridgeIdlingResource.java +0 -94
  97. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxBaseIdlingResource.java +0 -29
  98. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResource.java +0 -134
  99. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategy.kt +0 -23
  100. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/IdleInterrogationStrategy.kt +0 -16
  101. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/RN66Workaround.kt +0 -71
  102. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResourceSpec.kt +0 -227
  103. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategySpec.kt +0 -47
  104. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResourceSpec.kt +0 -189
@@ -0,0 +1 @@
1
+ eee5ef30145285d5cb57b7a09afb8304
@@ -0,0 +1 @@
1
+ f454322216a38a2a565504eeeee3097cdf210dd0
@@ -0,0 +1 @@
1
+ bde47b3d7df6f70cc9812e1232aa5781a4dbfbd923ca52c6097ab9ea880eb207
@@ -0,0 +1 @@
1
+ 175ce023c440c5903a33af31f0ce39e603c6c930fa05ddf5a38f070cd99b29fc6ee2e82b816bc60507c7c4729e9c0b1d8d1247ecc4b6b75455e0924d397dfe37
@@ -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.28.0</version>
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.8.0</version>
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.28.0</latest>
7
- <release>20.28.0</release>
6
+ <latest>20.32.0</latest>
7
+ <release>20.32.0</release>
8
8
  <versions>
9
- <version>20.28.0</version>
9
+ <version>20.32.0</version>
10
10
  </versions>
11
- <lastUpdated>20241114182711</lastUpdated>
11
+ <lastUpdated>20250106191456</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- 4409ef64d1213179048bfd9fed283361
1
+ a21a21f5f33f0521ea5b27a6b7c9a53d
@@ -1 +1 @@
1
- 112cd653d1f7777391df1fb10e9a33619f5d0c1b
1
+ 3c0a9c339f4d397ac37a6779311c1c121ab01863
@@ -1 +1 @@
1
- 2177b496977ac272c3b7333fa2a4505f8756dca0bc265970801d60985a6a8dfd
1
+ fa21aff43ff2f349f95760a2467987cef206152f4277db7d005193124667457b
@@ -1 +1 @@
1
- da830892bc25886891e341fe7e167f4aa1138c8fc2c28246d31409c39e82aa64f13c0a0a39bb6394a260ee2f449bf16e5378be6026cf1862759d57cec40fd053
1
+ 91de105f632722548240b0ce79abfa9758dfb44827badc8828bdb09404f917038e5e2157757003141f2d676cf641b9734f063ea0f950e01842d491d3eb8f04fc
Binary file
package/Detox-ios-src.tbz CHANGED
Binary file
Binary file
@@ -3,12 +3,12 @@ buildscript {
3
3
 
4
4
  ext {
5
5
  isOfficialDetoxLib = true
6
- kotlinVersion = '1.8.0'
6
+ kotlinVersion = '1.9.24'
7
7
  dokkaVersion = '1.9.10'
8
- buildToolsVersion = '34.0.0'
9
- compileSdkVersion = 34
10
- targetSdkVersion = 34
11
- minSdkVersion = 21
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.CoreMatchers;
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 Matcher<View> matcher;
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> matcher) {
27
- this.matcher = matcher != null ? matcher : allOf(CoreMatchers.<View>instanceOf(WebView.class), isDisplayed());
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, networkSyncEnabled)
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, networkSyncEnabled: Boolean = true) {
127
+ private fun enableOrDisableSynchronization(reactContext: ReactContext) {
133
128
  if (shouldDisableSynchronization()) {
134
129
  clearAllSynchronization()
135
130
  } else {
136
- setupIdlingResources(reactContext, networkSyncEnabled)
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, networkSyncEnabled: Boolean = true) {
140
+ private fun setupIdlingResources(reactContext: ReactContext) {
146
141
  val launchArgs = LaunchArgs()
147
142
 
148
- rnIdlingResources = ReactNativeIdlingResources(reactContext, launchArgs, networkSyncEnabled).apply {
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 org.joor.Reflect
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
- try {
11
- val versionClass = Class.forName("com.facebook.react.modules.systeminfo.ReactNativeVersion")
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
@@ -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
+ }