detox 20.28.0 → 20.31.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{20.28.0/detox-20.28.0.pom → 20.30.0/detox-20.30.0.pom} +2 -2
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.md5 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.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/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
@@ -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
|
-
}
|