detox 20.28.0 → 20.32.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }