detox 20.28.0 → 20.31.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. package/Detox-android/com/wix/detox/{20.28.0/detox-20.28.0-sources.jar → 20.30.0/detox-20.30.0-sources.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar +0 -0
  7. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/{20.28.0/detox-20.28.0.pom → 20.30.0/detox-20.30.0.pom} +2 -2
  12. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.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/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.md5 +0 -1
  60. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.sha1 +0 -1
  61. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.sha256 +0 -1
  62. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.sha512 +0 -1
  63. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar +0 -0
  64. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.md5 +0 -1
  65. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.sha1 +0 -1
  66. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.sha256 +0 -1
  67. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.sha512 +0 -1
  68. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.md5 +0 -1
  69. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.sha1 +0 -1
  70. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.sha256 +0 -1
  71. package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.sha512 +0 -1
  72. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar +0 -0
  73. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.md5 +0 -1
  74. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.sha1 +0 -1
  75. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.sha256 +0 -1
  76. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.sha512 +0 -1
  77. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar +0 -0
  78. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.md5 +0 -1
  79. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.sha1 +0 -1
  80. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.sha256 +0 -1
  81. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.sha512 +0 -1
  82. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom +0 -100
  83. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom.md5 +0 -1
  84. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom.sha1 +0 -1
  85. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom.sha256 +0 -1
  86. package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom.sha512 +0 -1
  87. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml +0 -13
  88. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.md5 +0 -1
  89. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha1 +0 -1
  90. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha256 +0 -1
  91. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha512 +0 -1
  92. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeIdlingResources.kt +0 -229
  93. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/AnimatedModuleIdlingResource.java +0 -215
  94. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/BridgeIdlingResource.java +0 -94
  95. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxBaseIdlingResource.java +0 -29
  96. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResource.java +0 -134
  97. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategy.kt +0 -23
  98. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/IdleInterrogationStrategy.kt +0 -16
  99. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/RN66Workaround.kt +0 -71
  100. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResourceSpec.kt +0 -227
  101. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategySpec.kt +0 -47
  102. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResourceSpec.kt +0 -189
@@ -1,215 +0,0 @@
1
- package com.wix.detox.reactnative.idlingresources;
2
-
3
- import android.util.Log;
4
- import android.view.Choreographer;
5
-
6
- import com.wix.detox.espresso.idlingresources.DescriptiveIdlingResource;
7
- import com.wix.detox.reactnative.ReactNativeInfo;
8
-
9
- import org.joor.Reflect;
10
- import org.joor.ReflectException;
11
-
12
- import java.util.HashMap;
13
- import java.util.Map;
14
-
15
- import androidx.annotation.NonNull;
16
- import androidx.annotation.Nullable;
17
-
18
- /**
19
- * Created by simonracz on 25/08/2017.
20
- */
21
-
22
- /**
23
- * <p>
24
- * Espresso IdlingResource for React Native's Animated Module.
25
- * </p>
26
- * <p>
27
- * <p>
28
- * Hooks up to React Native internals to monitor the state of the animations.
29
- * </p>
30
- * <p>
31
- * This Idling Resource is inherently tied to the UI Module IR. It must be registered after
32
- * the UI Module IR. This order is not enforced now.
33
- *
34
- * @see <a href="https://github.com/facebook/react-native/blob/259eac8c30b536abddab7925f4c51f0bf7ced58d/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java#L143">AnimatedModule</a>
35
- */
36
- public class AnimatedModuleIdlingResource implements DescriptiveIdlingResource, Choreographer.FrameCallback {
37
- private static final String LOG_TAG = "Detox";
38
-
39
- private final static String CLASS_ANIMATED_MODULE = "com.facebook.react.animated.NativeAnimatedModule";
40
- private final static String METHOD_GET_NATIVE_MODULE = "getNativeModule";
41
- private final static String METHOD_HAS_NATIVE_MODULE = "hasNativeModule";
42
- private final static String METHOD_IS_EMPTY = "isEmpty";
43
-
44
- private final static String LOCK_OPERATIONS = "mOperationsCopyLock";
45
- private final static String FIELD_OPERATIONS = "mReadyOperations";
46
- private final static String FIELD_NODES_MANAGER = "mNodesManager";
47
-
48
- private final static String FIELD_ITERATIONS = "mIterations";
49
- private final static String FIELD_ACTIVE_ANIMATIONS = "mActiveAnimations";
50
- private final static String FIELD_UPDATED_NODES = "mUpdatedNodes";
51
- private final static String FIELD_CATALYST_INSTANCE = "mCatalystInstance";
52
-
53
- private final static String METHOD_SIZE = "size";
54
- private final static String METHOD_VALUE_AT = "valueAt";
55
-
56
- private final static String METHOD_HAS_ACTIVE_ANIMATIONS = "hasActiveAnimations";
57
-
58
- private final static Map<String, Object> busyHint = new HashMap<String, Object>() {{
59
- put("reason", "Animations running on screen");
60
- }};
61
-
62
- private ResourceCallback callback = null;
63
- private Object reactContext = null;
64
-
65
- public AnimatedModuleIdlingResource(@NonNull Object reactContext) {
66
- this.reactContext = reactContext;
67
- }
68
-
69
- @Override
70
- public String getName() {
71
- return AnimatedModuleIdlingResource.class.getName();
72
- }
73
-
74
- @NonNull
75
- @Override
76
- public String getDebugName() {
77
- return "ui";
78
- }
79
-
80
- @Nullable
81
- @Override
82
- public Map<String, Object> getBusyHint() {
83
- return busyHint;
84
- }
85
-
86
- @Override
87
- public boolean isIdleNow() {
88
- Class<?> animModuleClass = null;
89
- try {
90
- animModuleClass = Class.forName(CLASS_ANIMATED_MODULE);
91
- } catch (ClassNotFoundException e) {
92
- Log.e(LOG_TAG, "Animated Module is not on classpath.");
93
- if (callback != null) {
94
- callback.onTransitionToIdle();
95
- }
96
- return true;
97
- }
98
-
99
- try {
100
- // reactContext.hasActiveCatalystInstance() should be always true here
101
- // if called right after onReactContextInitialized(...)
102
- if (Reflect.on(reactContext).field(FIELD_CATALYST_INSTANCE).get() == null) {
103
- Log.e(LOG_TAG, "No active CatalystInstance. Should never see this.");
104
- return false;
105
- }
106
-
107
- if (!(boolean) Reflect.on(reactContext).call(METHOD_HAS_NATIVE_MODULE, animModuleClass).get()) {
108
- Log.e(LOG_TAG, "Can't find Animated Module.");
109
- if (callback != null) {
110
- callback.onTransitionToIdle();
111
- }
112
- return true;
113
- }
114
-
115
- if (ReactNativeInfo.rnVersion().getMinor() >= 51) {
116
- if(isIdleRN51(animModuleClass)) {
117
- return true;
118
- }
119
- } else {
120
- if (isIdleRNOld(animModuleClass)) {
121
- return true;
122
- }
123
- }
124
-
125
- Log.i(LOG_TAG, "AnimatedModule is busy.");
126
- Choreographer.getInstance().postFrameCallback(this);
127
- return false;
128
- } catch (ReflectException e) {
129
- Log.e(LOG_TAG, "Couldn't set up RN AnimatedModule listener, old RN version?");
130
- Log.e(LOG_TAG, "Can't set up RN AnimatedModule listener", e.getCause());
131
- }
132
-
133
- if (callback != null) {
134
- callback.onTransitionToIdle();
135
- }
136
- // Log.i(LOG_TAG, "AnimatedModule is idle.");
137
- return true;
138
- }
139
-
140
- private boolean isIdleRN51(Object animModuleClass) {
141
- Object animModule = Reflect.on(reactContext).call(METHOD_GET_NATIVE_MODULE, animModuleClass).get();
142
- Object nodesManager = Reflect.on(animModule).call("getNodesManager").get();
143
- boolean hasActiveAnimations = Reflect.on(nodesManager).call("hasActiveAnimations").get();
144
- if (!hasActiveAnimations) {
145
- if (callback != null) {
146
- callback.onTransitionToIdle();
147
- }
148
- // Log.i(LOG_TAG, "AnimatedModule is idle, no operations");
149
- return true;
150
- }
151
- return false;
152
- }
153
-
154
- private boolean isIdleRNOld(Object animModuleClass) {
155
- Object animModule = Reflect.on(reactContext).call(METHOD_GET_NATIVE_MODULE, animModuleClass).get();
156
- Object operationsLock = Reflect.on(animModule).field(LOCK_OPERATIONS).get();
157
- boolean operationsAreEmpty;
158
- boolean animationsConsideredIdle;
159
- synchronized (operationsLock) {
160
- Object operations = Reflect.on(animModule).field(FIELD_OPERATIONS).get();
161
- if (operations == null) {
162
- operationsAreEmpty = true;
163
- } else {
164
- operationsAreEmpty = Reflect.on(operations).call(METHOD_IS_EMPTY).get();
165
- }
166
- }
167
- Object nodesManager = Reflect.on(animModule).field(FIELD_NODES_MANAGER).get();
168
-
169
- // We do this in this complicated way
170
- // to not consider looped animations
171
- // as a busy state.
172
- int updatedNodesSize = Reflect.on(nodesManager).field(FIELD_UPDATED_NODES).call(METHOD_SIZE).get();
173
- if (updatedNodesSize > 0) {
174
- animationsConsideredIdle = false;
175
- } else {
176
- Object activeAnims = Reflect.on(nodesManager).field(FIELD_ACTIVE_ANIMATIONS).get();
177
- int activeAnimsSize = Reflect.on(activeAnims).call(METHOD_SIZE).get();
178
- if (activeAnimsSize == 0) {
179
- animationsConsideredIdle = true;
180
- } else {
181
- animationsConsideredIdle = true;
182
- for (int i = 0; i < activeAnimsSize; ++i) {
183
- int iterations = Reflect.on(activeAnims).call(METHOD_VALUE_AT, i).field(FIELD_ITERATIONS).get();
184
- // -1 means it is looped
185
- if (iterations != -1) {
186
- animationsConsideredIdle = false;
187
- break;
188
- }
189
- }
190
- }
191
- }
192
-
193
- if (operationsAreEmpty && animationsConsideredIdle) {
194
- if (callback != null) {
195
- callback.onTransitionToIdle();
196
- }
197
- // Log.i(LOG_TAG, "AnimatedModule is idle.");
198
- return true;
199
- }
200
- return false;
201
- }
202
-
203
- @Override
204
- public void registerIdleTransitionCallback(ResourceCallback callback) {
205
- this.callback = callback;
206
-
207
- Choreographer.getInstance().postFrameCallback(this);
208
- }
209
-
210
- @Override
211
- public void doFrame(long frameTimeNanos) {
212
- isIdleNow();
213
- }
214
- }
215
-
@@ -1,94 +0,0 @@
1
- package com.wix.detox.reactnative.idlingresources;
2
-
3
- import android.util.Log;
4
-
5
- import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
6
- import com.facebook.react.bridge.ReactContext;
7
-
8
- import java.util.Map;
9
- import java.util.concurrent.atomic.AtomicBoolean;
10
-
11
- import androidx.annotation.NonNull;
12
- import androidx.annotation.Nullable;
13
-
14
- /**
15
- * Created by simonracz on 01/06/2017.
16
- */
17
-
18
- /**
19
- * <p>
20
- * IdlingResource for Espresso, which monitors the traffic of
21
- * React Native's JS bridge.
22
- * </p>
23
- */
24
- public class BridgeIdlingResource extends DetoxBaseIdlingResource implements NotThreadSafeBridgeIdleDebugListener {
25
- private static final String LOG_TAG = "Detox";
26
- private final ReactContext reactContext;
27
-
28
- private AtomicBoolean idleNow = new AtomicBoolean(true);
29
- private ResourceCallback callback = null;
30
-
31
- public BridgeIdlingResource(ReactContext reactContext) {
32
- this.reactContext = reactContext;
33
- this.reactContext.getCatalystInstance().addBridgeIdleDebugListener(this);
34
- }
35
-
36
- public void onDetach() {
37
- this.reactContext.getCatalystInstance().removeBridgeIdleDebugListener(this);
38
- }
39
-
40
- @Override
41
- public String getName() {
42
- return BridgeIdlingResource.class.getName();
43
- }
44
-
45
- @NonNull
46
- @Override
47
- public String getDebugName() {
48
- return "bridge";
49
- }
50
-
51
- @Nullable
52
- @Override
53
- public Map<String, Object> getBusyHint() {
54
- return null;
55
- }
56
-
57
- @Override
58
- protected boolean checkIdle() {
59
- boolean ret = idleNow.get();
60
- if (!ret) {
61
- Log.i(LOG_TAG, "JS Bridge is busy");
62
- }
63
- return ret;
64
- }
65
-
66
- @Override
67
- public void registerIdleTransitionCallback(ResourceCallback callback) {
68
- this.callback = callback;
69
- }
70
-
71
- @Override
72
- public void onTransitionToBridgeIdle() {
73
- idleNow.set(true);
74
- notifyIdle();
75
- }
76
-
77
- @Override
78
- public void onTransitionToBridgeBusy() {
79
- idleNow.set(false);
80
- // Log.i(LOG_TAG, "JS Bridge transitions to busy.");
81
- }
82
-
83
- @Override
84
- public void onBridgeDestroyed() {
85
- }
86
-
87
- @Override
88
- protected void notifyIdle() {
89
- // Log.i(LOG_TAG, "JS Bridge transitions to idle.");
90
- if (callback != null) {
91
- callback.onTransitionToIdle();
92
- }
93
- }
94
- }
@@ -1,29 +0,0 @@
1
- package com.wix.detox.reactnative.idlingresources;
2
-
3
- import com.wix.detox.espresso.idlingresources.DescriptiveIdlingResource;
4
-
5
- import java.util.concurrent.atomic.AtomicBoolean;
6
-
7
- public abstract class DetoxBaseIdlingResource implements DescriptiveIdlingResource {
8
- AtomicBoolean paused = new AtomicBoolean(false);
9
-
10
- public void pause() {
11
- paused.set(true);
12
- notifyIdle();
13
- }
14
-
15
- public void resume() {
16
- paused.set(false);
17
- }
18
-
19
- @Override
20
- final public boolean isIdleNow() {
21
- if (paused.get()) {
22
- return true;
23
- }
24
- return checkIdle();
25
- }
26
-
27
- protected abstract boolean checkIdle();
28
- protected abstract void notifyIdle();
29
- }
@@ -1,134 +0,0 @@
1
- package com.wix.detox.reactnative.idlingresources;
2
-
3
- import android.util.Log;
4
- import android.view.Choreographer;
5
-
6
- import com.facebook.react.bridge.ReactContext;
7
-
8
- import java.util.ArrayList;
9
- import java.util.HashMap;
10
- import java.util.HashSet;
11
- import java.util.List;
12
- import java.util.Map;
13
- import java.util.Set;
14
- import java.util.regex.Pattern;
15
- import java.util.regex.PatternSyntaxException;
16
-
17
- import androidx.annotation.NonNull;
18
- import androidx.annotation.Nullable;
19
- import okhttp3.Call;
20
- import okhttp3.Dispatcher;
21
-
22
-
23
- /**
24
- * Created by simonracz on 09/10/2017.
25
- *
26
- * Idling Resource which monitors React Native's OkHttpClient.
27
- * <p>
28
- * Must call stop() on it, before removing it from Espresso.
29
- */
30
- public class NetworkIdlingResource extends DetoxBaseIdlingResource implements Choreographer.FrameCallback {
31
-
32
- private static final String LOG_TAG = "Detox";
33
-
34
- private ResourceCallback callback;
35
- private Dispatcher dispatcher;
36
- private final Set<String> busyResources = new HashSet<>();
37
-
38
- private static final ArrayList<Pattern> blacklist = new ArrayList<>();
39
-
40
- /**
41
- * Must be called on the UI thread.
42
- *
43
- * @param urls list of regexes of blacklisted urls
44
- */
45
- public static void setURLBlacklist(List<String> urls) {
46
- blacklist.clear();
47
- if (urls == null) return;
48
-
49
- for (String url : urls) {
50
- try {
51
- blacklist.add(Pattern.compile(url));
52
- } catch (PatternSyntaxException e) {
53
- Log.e(LOG_TAG, "Couldn't parse regular expression for Black list url: " + url, e);
54
- }
55
- }
56
- }
57
-
58
- public NetworkIdlingResource(@NonNull ReactContext reactContext) {
59
- this(new NetworkingModuleReflected(reactContext).getHttpClient().dispatcher());
60
- }
61
-
62
- public NetworkIdlingResource(@NonNull Dispatcher dispatcher) {
63
- this.dispatcher = dispatcher;
64
- }
65
-
66
- @Override
67
- public String getName() {
68
- return NetworkIdlingResource.class.getName();
69
- }
70
-
71
- @NonNull
72
- @Override
73
- public String getDebugName() {
74
- return "network";
75
- }
76
-
77
- @Nullable
78
- @Override
79
- public synchronized Map<String, Object> getBusyHint() {
80
- return new HashMap<String, Object>() {{
81
- put("urls", new ArrayList<>(busyResources));
82
- }};
83
- }
84
-
85
- @Override
86
- public void registerIdleTransitionCallback(ResourceCallback callback) {
87
- this.callback = callback;
88
- Choreographer.getInstance().postFrameCallback(this);
89
- }
90
-
91
- @Override
92
- public void doFrame(long frameTimeNanos) {
93
- isIdleNow();
94
- }
95
-
96
- @Override
97
- protected synchronized boolean checkIdle() {
98
- busyResources.clear();
99
-
100
- List<Call> calls = dispatcher.runningCalls();
101
- for (Call call: calls) {
102
- final String url = call.request().url().toString();
103
-
104
- if (!isUrlBlacklisted(url)) {
105
- busyResources.add(url);
106
- }
107
- }
108
-
109
- if (!busyResources.isEmpty()) {
110
- Log.i(LOG_TAG, "Network is busy, with " + busyResources.size() + " in-flight calls");
111
- Choreographer.getInstance().postFrameCallback(this);
112
- return false;
113
- }
114
-
115
- notifyIdle();
116
- return true;
117
- }
118
-
119
- @Override
120
- protected void notifyIdle() {
121
- if (callback != null) {
122
- callback.onTransitionToIdle();
123
- }
124
- }
125
-
126
- private boolean isUrlBlacklisted(String url) {
127
- for (Pattern pattern: blacklist) {
128
- if (pattern.matcher(url).matches()) {
129
- return true;
130
- }
131
- }
132
- return false;
133
- }
134
- }
@@ -1,23 +0,0 @@
1
-
2
- package com.wix.detox.reactnative.idlingresources.timers
3
-
4
- import com.facebook.react.bridge.ReactContext
5
- import com.facebook.react.modules.core.TimingModule
6
-
7
- private const val BUSY_WINDOW_THRESHOLD = 1500L
8
-
9
- /**
10
- * Delegates the interrogation to the native module itself, added
11
- * [here](https://github.com/facebook/react-native/pull/27539) in the context
12
- * of RN v0.62 (followed by a previous refactor and rename of the class).
13
- */
14
- class DelegatedIdleInterrogationStrategy(private val timingModule: TimingModule): IdleInterrogationStrategy {
15
- override fun isIdleNow(): Boolean = !timingModule.hasActiveTimersInRange(BUSY_WINDOW_THRESHOLD)
16
-
17
- companion object {
18
- fun create(reactContext: ReactContext): DelegatedIdleInterrogationStrategy {
19
- val timingModule = reactContext.getNativeModule(TimingModule::class.java)!!
20
- return DelegatedIdleInterrogationStrategy(timingModule)
21
- }
22
- }
23
- }
@@ -1,16 +0,0 @@
1
- package com.wix.detox.reactnative.idlingresources.timers
2
-
3
- import com.facebook.react.bridge.ReactContext
4
- import com.wix.detox.common.UIThread
5
- import java.util.concurrent.Callable
6
-
7
- interface IdleInterrogationStrategy {
8
- fun isIdleNow(): Boolean
9
- }
10
-
11
- fun getInterrogationStrategy(reactContext: ReactContext): IdleInterrogationStrategy? =
12
- // Getting a native-module (inside) also initializes it if needed. That has to run on a
13
- // looper thread, and the easiest to make sure that happens is to use the main thread.
14
- UIThread.runSync(Callable {
15
- return@Callable DelegatedIdleInterrogationStrategy.create(reactContext)
16
- })
@@ -1,71 +0,0 @@
1
- package com.wix.detox.reactnative.idlingresources.uimodule
2
-
3
- import android.util.Log
4
- import android.view.View
5
- import com.facebook.react.uimanager.IllegalViewOperationException
6
- import com.wix.detox.common.DetoxLog.Companion.LOG_TAG
7
- import com.wix.detox.reactnative.ReactNativeInfo
8
- import java.lang.ref.WeakReference
9
-
10
- private const val NUM_TIMES_BEFORE_NOTIFY_IDLE = 10
11
- private const val SET_NATIVE_VALUE = "setNativeValue"
12
- private const val CLASS_REACT_SWITCH = "com.facebook.react.views.switchview.ReactSwitch"
13
-
14
- class RN66Workaround {
15
- private var timesStuckQueueDetected = 0
16
- private var stuckOperation: WeakReference<Any?>? = null
17
-
18
- // This is a workaround for https://github.com/facebook/react-native/issues/32594
19
- // uses duck typing heuristics to determine that this is probably the stuck Switch operation and if so, ignores it
20
- fun isScarceUISwitchCommandStuckInQueue(uiManagerModuleReflected: UIManagerModuleReflected): Boolean {
21
- var isStuckSwitchOperation = false
22
-
23
- if (isRelevantRNVersion() && uiManagerModuleReflected.getUIOpsCount() >= 1) {
24
- val nextUIOperation = uiManagerModuleReflected.getNextUIOpReflected()
25
- val view = getUIOpView(uiManagerModuleReflected, nextUIOperation)
26
- val isReactSwitch = isReactSwitch(view)
27
- val hasOneRetryIncremented = nextUIOperation?.numRetries == 1
28
- val isSetNativeValueCommand = (nextUIOperation?.viewCommand ?: "") == SET_NATIVE_VALUE
29
-
30
- if (isReactSwitch && hasOneRetryIncremented && isSetNativeValueCommand) {
31
- if (stuckOperation?.get() == nextUIOperation?.instance) {
32
- timesStuckQueueDetected++
33
- } else {
34
- stuckOperation = WeakReference(nextUIOperation?.instance)
35
- timesStuckQueueDetected = 0
36
- }
37
- }
38
-
39
- if (timesStuckQueueDetected >= NUM_TIMES_BEFORE_NOTIFY_IDLE) {
40
- isStuckSwitchOperation = true
41
- }
42
- } else {
43
- timesStuckQueueDetected = 0
44
- }
45
- return isStuckSwitchOperation
46
- }
47
-
48
- private fun isRelevantRNVersion(): Boolean {
49
- val rnVersion = ReactNativeInfo.rnVersion()
50
- return rnVersion.minor == 66 || (rnVersion.minor == 67 && rnVersion.patch < 4)
51
- }
52
-
53
- private fun getUIOpView(uiManagerModuleReflected: UIManagerModuleReflected, uiOperation: DispatchCommandOperationReflected?): View? {
54
- val nativeViewHierarchyManager = uiManagerModuleReflected.nativeViewHierarchyManager() ?: return null
55
- val tag = uiOperation?.tag ?: return null
56
- return try {
57
- nativeViewHierarchyManager.getViewClass(tag)
58
- } catch(e: IllegalViewOperationException) {
59
- Log.e(LOG_TAG, "failed to get view from tag ", e.cause)
60
- null
61
- }
62
- }
63
-
64
- private fun isReactSwitch(view: View?) = try {
65
- val ReactSwitchClass: Class<*> = Class.forName(CLASS_REACT_SWITCH)
66
- if (view != null) ReactSwitchClass.isAssignableFrom(view.javaClass) else false
67
- } catch (e: ClassNotFoundException) {
68
- Log.e(LOG_TAG, "failed to get $CLASS_REACT_SWITCH class ", e.cause)
69
- false
70
- }
71
- }