detox 19.3.1 → 19.4.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0-javadoc.jar +0 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0-javadoc.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0-javadoc.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0-javadoc.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0-javadoc.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{19.3.1/detox-19.3.1-sources.jar → 19.4.0-alpha.0/detox-19.4.0-alpha.0-sources.jar} +0 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0-sources.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0-sources.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0-sources.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0-sources.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0.aar +0 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0.aar.md5 +1 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0.aar.sha1 +1 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0.aar.sha256 +1 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0.aar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{19.3.1/detox-19.3.1.pom → 19.4.0-alpha.0/detox-19.4.0-alpha.0.pom} +5 -11
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0.pom.md5 +1 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0.pom.sha1 +1 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.0.pom.sha256 +1 -0
- package/Detox-android/com/wix/detox/19.4.0-alpha.0/detox-19.4.0-alpha.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-src.tbz +0 -0
- package/Detox-ios.tbz +0 -0
- package/android/build.gradle +5 -5
- package/android/detox/build.gradle +23 -13
- package/android/detox/proguard-rules-app.pro +1 -0
- package/android/detox/publishing.gradle +17 -27
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeIdlingResources.kt +1 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/DispatchCommandOperationReflected.kt +36 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/NativeHierarchyManagerReflected.kt +28 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/RN66Workaround.kt +59 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIManagerModuleReflected.kt +70 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIModuleIdlingResource.kt +83 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/ViewCommandOpsQueueReflected.kt +27 -0
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResourceSpec.kt +1 -0
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DefaultIdleInterrogationStrategySpec.kt +2 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +1 -1
- package/package.json +3 -3
- package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +1 -1
- package/src/utils/environment.js +2 -2
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1-javadoc.jar +0 -0
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1-javadoc.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1-javadoc.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1-javadoc.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1-javadoc.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1.aar +0 -0
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1.aar.md5 +0 -1
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1.pom.md5 +0 -1
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox/19.3.1/detox-19.3.1.pom.sha512 +0 -1
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/UIModuleIdlingResource.java +0 -148
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
14335d4accfdb6db18c017d6d4c559bc
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
a79d71c2692fa83edc476d2ffa6496fbb1604763
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
9842f3ec080250019cdc73325be798a37722e00bcde45f804980425e53ac9c2d
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
e70d36237404abd83bca254aebece2bae4eb35c9b80353c5e3b49a491a1ebea8d972d5870c3e57a8e8ce76c97a24547fc6231fce6b37f5ffa067516108cb6287
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1af7059a015aa9f321071ceab52be60f
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
a56771ac8e035424cc1c22a0a41dda08a172fc03
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3e02271c29f87482ad663a08d736c4e2614063c8b221704886bd6b7ef096eaa5
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
16722733fee56837646224847fff8f835e029f5a17d2ae32960f99497c3cbf04f45ce1a3eb9dae92bc8ca4cbefa63e6e17600ba27ab70bace35cf5702816d6ca
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
db5438a69056782c6b65faf53f746bfe
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
818e8057a07f4ea8145d6c0490906340ebad700d
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
082dac5e9d4dba9ac093cb3f25b8bde915469055fe1c986a401ea65fb5f10d65
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
878279c9e3df36b86a64f71f577138fbb7ebc9f8956e77d61c811c55d5f1f6d8cfa06750a29c2089905e1458fa0cac61c108fdacdfa89a05882c1e0dea54e077
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<modelVersion>4.0.0</modelVersion>
|
|
4
4
|
<groupId>com.wix</groupId>
|
|
5
5
|
<artifactId>detox</artifactId>
|
|
6
|
-
<version>19.
|
|
6
|
+
<version>19.4.0-alpha.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,31 +33,25 @@
|
|
|
33
33
|
<dependency>
|
|
34
34
|
<groupId>androidx.test.espresso</groupId>
|
|
35
35
|
<artifactId>espresso-core</artifactId>
|
|
36
|
-
<version>3.
|
|
36
|
+
<version>3.4.0</version>
|
|
37
37
|
<scope>compile</scope>
|
|
38
|
-
<exclusions>
|
|
39
|
-
<exclusion>
|
|
40
|
-
<groupId>com.google.code.findbugs</groupId>
|
|
41
|
-
<artifactId>jsr305</artifactId>
|
|
42
|
-
</exclusion>
|
|
43
|
-
</exclusions>
|
|
44
38
|
</dependency>
|
|
45
39
|
<dependency>
|
|
46
40
|
<groupId>androidx.test.espresso</groupId>
|
|
47
41
|
<artifactId>espresso-web</artifactId>
|
|
48
|
-
<version>3.
|
|
42
|
+
<version>3.4.0</version>
|
|
49
43
|
<scope>compile</scope>
|
|
50
44
|
</dependency>
|
|
51
45
|
<dependency>
|
|
52
46
|
<groupId>androidx.test</groupId>
|
|
53
47
|
<artifactId>rules</artifactId>
|
|
54
|
-
<version>1.
|
|
48
|
+
<version>1.4.0</version>
|
|
55
49
|
<scope>compile</scope>
|
|
56
50
|
</dependency>
|
|
57
51
|
<dependency>
|
|
58
52
|
<groupId>androidx.test.ext</groupId>
|
|
59
53
|
<artifactId>junit</artifactId>
|
|
60
|
-
<version>1.1.
|
|
54
|
+
<version>1.1.3</version>
|
|
61
55
|
<scope>compile</scope>
|
|
62
56
|
</dependency>
|
|
63
57
|
<dependency>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
a38333dfd1c07236c8b5d0eb10a08757
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2ddc1e10d6af2c7781ceb0ec9c668b7b90ce712b
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
707e4c68172fbc8ec9a1f784042d111e39f11ca5717f18fa9049c2ad16a68106
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
5b82f5611dd8d959c16d790134fa809d97fb3469108aa918179a7b26f14b016292598a3de8860d1cf4504220492db63d3d2df3b4d64face976404b6c2137b70d
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
<groupId>com.wix</groupId>
|
|
4
4
|
<artifactId>detox</artifactId>
|
|
5
5
|
<versioning>
|
|
6
|
-
<latest>19.
|
|
7
|
-
<release>19.
|
|
6
|
+
<latest>19.4.0-alpha.0</latest>
|
|
7
|
+
<release>19.4.0-alpha.0</release>
|
|
8
8
|
<versions>
|
|
9
|
-
<version>19.
|
|
9
|
+
<version>19.4.0-alpha.0</version>
|
|
10
10
|
</versions>
|
|
11
|
-
<lastUpdated>
|
|
11
|
+
<lastUpdated>20211223152137</lastUpdated>
|
|
12
12
|
</versioning>
|
|
13
13
|
</metadata>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
3d2fd5ee475a78c4a312206c7c654bde
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
850604928677367ba747042ab7194f3f2f145fe6
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
9ddbd8a3557e167a80a211bf2f3345f7ef8354160256d70c5afec52ce3080688
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
893c523faf3edff5a02bf0d1d6f5cac1c55225690ac62bd820ed02a0ef6ae268fd96549a1edbeba8679863edccbe00fb391885beabefde6f434632c273753ba0
|
package/Detox-ios-src.tbz
CHANGED
|
Binary file
|
package/Detox-ios.tbz
CHANGED
|
Binary file
|
package/android/build.gradle
CHANGED
|
@@ -2,10 +2,10 @@ buildscript {
|
|
|
2
2
|
ext {
|
|
3
3
|
isOfficialDetoxLib = true
|
|
4
4
|
kotlinVersion = '1.2.0'
|
|
5
|
-
dokkaVersion = '
|
|
6
|
-
buildToolsVersion = '
|
|
7
|
-
compileSdkVersion =
|
|
8
|
-
targetSdkVersion =
|
|
5
|
+
dokkaVersion = '1.6.0'
|
|
6
|
+
buildToolsVersion = '30.0.2'
|
|
7
|
+
compileSdkVersion = 31
|
|
8
|
+
targetSdkVersion = 31
|
|
9
9
|
minSdkVersion = 21
|
|
10
10
|
}
|
|
11
11
|
ext.detoxKotlinVersion = ext.kotlinVersion
|
|
@@ -15,7 +15,7 @@ buildscript {
|
|
|
15
15
|
google()
|
|
16
16
|
}
|
|
17
17
|
dependencies {
|
|
18
|
-
classpath 'com.android.tools.build:gradle:4.
|
|
18
|
+
classpath 'com.android.tools.build:gradle:4.2.2'
|
|
19
19
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
|
20
20
|
classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokkaVersion"
|
|
21
21
|
|
|
@@ -3,9 +3,9 @@ apply plugin: 'kotlin-android'
|
|
|
3
3
|
apply plugin: 'kotlin-android-extensions'
|
|
4
4
|
|
|
5
5
|
def _ext = rootProject.ext
|
|
6
|
-
def _compileSdkVersion = _ext.has('compileSdkVersion') ? _ext.compileSdkVersion :
|
|
7
|
-
def _targetSdkVersion = _ext.has('targetSdkVersion') ? _ext.targetSdkVersion :
|
|
8
|
-
def _buildToolsVersion = _ext.has('buildToolsVersion') ? _ext.buildToolsVersion : '
|
|
6
|
+
def _compileSdkVersion = _ext.has('compileSdkVersion') ? _ext.compileSdkVersion : 31
|
|
7
|
+
def _targetSdkVersion = _ext.has('targetSdkVersion') ? _ext.targetSdkVersion : 31
|
|
8
|
+
def _buildToolsVersion = _ext.has('buildToolsVersion') ? _ext.buildToolsVersion : '30.0.2'
|
|
9
9
|
def _minSdkVersion = _ext.has('minSdkVersion') ? _ext.minSdkVersion : 18
|
|
10
10
|
def _kotlinVersion = _ext.has('detoxKotlinVersion') ? _ext.detoxKotlinVersion : '1.2.0'
|
|
11
11
|
def _kotlinStdlib = _ext.has('detoxKotlinStdlib') ? _ext.detoxKotlinStdlib : 'kotlin-stdlib-jdk8'
|
|
@@ -80,22 +80,30 @@ dependencies {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
// androidx.test deps.
|
|
83
|
-
// All are aligned with this release: https://developer.android.com/jetpack/androidx/releases/test#1.
|
|
83
|
+
// All are aligned with this release: https://developer.android.com/jetpack/androidx/releases/test#1.4.0
|
|
84
84
|
dependencies {
|
|
85
85
|
|
|
86
|
-
// Versions are in-sync with the 'androidx-test-1.
|
|
87
|
-
// used by the Detox generator. See https://github.com/android/android-test/releases/tag/androidx-test-1.
|
|
86
|
+
// Versions are in-sync with the 'androidx-test-1.4.0' release/tag of the android-test github repo,
|
|
87
|
+
// used by the Detox generator. See https://github.com/android/android-test/releases/tag/androidx-test-1.4.0
|
|
88
88
|
// Important: Should remain so when generator tag is replaced!
|
|
89
|
-
api('androidx.test.espresso:espresso-core:3.
|
|
90
|
-
|
|
89
|
+
api('androidx.test.espresso:espresso-core:3.4.0') {
|
|
90
|
+
because 'Needed all across Detox but also makes Espresso seamlessly provided to Detox users with hybrid apps/E2E-tests.'
|
|
91
|
+
}
|
|
92
|
+
api('androidx.test.espresso:espresso-web:3.4.0') {
|
|
93
|
+
because 'Web-View testing'
|
|
94
|
+
}
|
|
95
|
+
api('androidx.test:rules:1.4.0') {
|
|
96
|
+
because 'of ActivityTestRule. Needed by users *and* internally used by Detox.'
|
|
97
|
+
}
|
|
98
|
+
api('androidx.test.ext:junit:1.1.3') {
|
|
99
|
+
because 'Needed so as to seamlessly provide AndroidJUnit4 to Detox users. Depends on junit core.'
|
|
91
100
|
}
|
|
92
|
-
api 'androidx.test.espresso:espresso-web:3.3.0' // Web-View testing
|
|
93
|
-
api 'androidx.test:rules:1.2.0' // Needed because of ActivityTestRule. Needed by users *and* internally used by Detox.
|
|
94
|
-
api 'androidx.test.ext:junit:1.1.1' // Needed so as to seamlessly provide AndroidJUnit4 to Detox users. Depends on junit core.
|
|
95
101
|
|
|
96
102
|
// Version is the latest; Cannot sync with the Github repo (e.g. android/android-test) because the androidx
|
|
97
103
|
// packaging version of associated classes is simply not there...
|
|
98
|
-
api
|
|
104
|
+
api('androidx.test.uiautomator:uiautomator:2.2.0') {
|
|
105
|
+
because 'Needed by Detox but also makes UIAutomator seamlessly provided to Detox users with hybrid apps/E2E-tests.'
|
|
106
|
+
}
|
|
99
107
|
}
|
|
100
108
|
|
|
101
109
|
// Third-party/extension deps.
|
|
@@ -103,7 +111,9 @@ dependencies {
|
|
|
103
111
|
implementation('com.google.android.material:material:1.2.1') {
|
|
104
112
|
because 'Material components are mentioned explicitly (e.g. Slider in get-attributes handler)'
|
|
105
113
|
}
|
|
106
|
-
implementation
|
|
114
|
+
implementation('org.apache.commons:commons-lang3:3.7') {
|
|
115
|
+
because 'Needed by invoke. Warning: Upgrading to newer versions is not seamless.'
|
|
116
|
+
}
|
|
107
117
|
implementation 'com.github.anrwatchdog:anrwatchdog:1.4.0'
|
|
108
118
|
|
|
109
119
|
implementation fileTree(dir: '../libs', includes: ['*.jar']) // Includes: Genymotion SDK
|
|
@@ -85,41 +85,31 @@ initPublishing()
|
|
|
85
85
|
* Dokka is the official javadoc equivalent that supports kotlin KDoc (see https://github.com/Kotlin/dokka)
|
|
86
86
|
*/
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
outputFormat = 'javadoc' // https://github.com/Kotlin/dokka#output-formats
|
|
105
|
-
outputDirectory = "$buildDir/dokkaDoc" // Temp 'exploded' dir for .jar creation (i.e. by dokkaDocJar task)
|
|
106
|
-
|
|
107
|
-
def suppressedPackages = ["android_libs", "com.wix.detox.espresso.common.annot"]
|
|
108
|
-
for (String packagePrefix: suppressedPackages) {
|
|
109
|
-
packageOptions {
|
|
110
|
-
prefix = packagePrefix
|
|
111
|
-
suppress = true
|
|
88
|
+
tasks.named("dokkaJavadoc") {
|
|
89
|
+
File dokkaDoc = new File("$buildDir/dokkaDoc");
|
|
90
|
+
outputDirectory.set(dokkaDoc)
|
|
91
|
+
dokkaSourceSets {
|
|
92
|
+
named("main") {
|
|
93
|
+
sourceRoots.from(android.sourceSets.main.java.srcDirs)
|
|
94
|
+
reportUndocumented.set(false)
|
|
95
|
+
skipEmptyPackages.set(true)
|
|
96
|
+
def suppressedPackages = ["android_libs", "com.wix.detox.espresso.common.annot"]
|
|
97
|
+
for (String packagePrefix : suppressedPackages) {
|
|
98
|
+
packageOptions {
|
|
99
|
+
prefix = packagePrefix
|
|
100
|
+
suppress = true
|
|
101
|
+
}
|
|
102
|
+
}
|
|
112
103
|
}
|
|
113
104
|
}
|
|
114
|
-
|
|
105
|
+
}
|
|
115
106
|
// Side note / TODO:
|
|
116
107
|
// Dokka outputs R and BuildConfig; currently, there's nothing to do about it, as issues such as
|
|
117
108
|
// this on - https://github.com/Kotlin/dokka/issues/419 are still open :-/
|
|
118
109
|
// We might want to revisit this in the future -- see if they've decided to export a custom classes
|
|
119
110
|
// suppression config var or something.
|
|
120
|
-
}
|
|
121
111
|
|
|
122
|
-
task dokkaDocJar(type: Jar, dependsOn:
|
|
112
|
+
task dokkaDocJar(type: Jar, dependsOn: dokkaJavadoc) {
|
|
123
113
|
from "$buildDir/dokkaDoc"
|
|
124
114
|
classifier = 'javadoc'
|
|
125
115
|
}
|
|
@@ -9,6 +9,7 @@ import com.wix.detox.LaunchArgs
|
|
|
9
9
|
import com.wix.detox.reactnative.idlingresources.*
|
|
10
10
|
import com.wix.detox.reactnative.idlingresources.timers.TimersIdlingResource
|
|
11
11
|
import com.wix.detox.reactnative.idlingresources.timers.getInterrogationStrategy
|
|
12
|
+
import com.wix.detox.reactnative.idlingresources.uimodule.UIModuleIdlingResource
|
|
12
13
|
import org.joor.Reflect
|
|
13
14
|
import org.joor.ReflectException
|
|
14
15
|
import java.util.Set
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
package com.wix.detox.reactnative.idlingresources.uimodule
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import com.wix.detox.common.DetoxLog
|
|
5
|
+
import org.joor.Reflect
|
|
6
|
+
import org.joor.ReflectException
|
|
7
|
+
|
|
8
|
+
private const val FIELD_TAG = "mTag"
|
|
9
|
+
private const val FIELD_NUM_RETRIES = "numRetries"
|
|
10
|
+
private const val FIELD_COMMAND = "mCommand"
|
|
11
|
+
|
|
12
|
+
class DispatchCommandOperationReflected(val instance: Any?) {
|
|
13
|
+
val tag: Int?
|
|
14
|
+
get() = try {
|
|
15
|
+
Reflect.on(instance).field(FIELD_TAG).get<Int>()
|
|
16
|
+
} catch (e: ReflectException) {
|
|
17
|
+
Log.e(DetoxLog.LOG_TAG, "failed to get $FIELD_TAG ", e)
|
|
18
|
+
null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
val numRetries: Int?
|
|
22
|
+
get() = try {
|
|
23
|
+
Reflect.on(instance).field(FIELD_NUM_RETRIES).get<Int>()
|
|
24
|
+
} catch (e: ReflectException) {
|
|
25
|
+
Log.e(DetoxLog.LOG_TAG, "failed to get $FIELD_NUM_RETRIES ", e)
|
|
26
|
+
0
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
val viewCommand: String?
|
|
30
|
+
get() = try {
|
|
31
|
+
Reflect.on(instance).field(FIELD_COMMAND).get<String>()
|
|
32
|
+
} catch (e: ReflectException) {
|
|
33
|
+
Log.e(DetoxLog.LOG_TAG, "failed to get $FIELD_COMMAND ", e)
|
|
34
|
+
null
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
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.NativeViewHierarchyManager
|
|
6
|
+
import com.facebook.react.uimanager.UIViewOperationQueue
|
|
7
|
+
import com.wix.detox.common.DetoxLog.Companion.LOG_TAG
|
|
8
|
+
import org.joor.Reflect
|
|
9
|
+
import org.joor.ReflectException
|
|
10
|
+
|
|
11
|
+
private const val FIELD_NATIVE_HIERARCHY_MANAGER = "mNativeViewHierarchyManager"
|
|
12
|
+
|
|
13
|
+
class NativeHierarchyManagerReflected(uIViewOperationQueueInstance: UIViewOperationQueue) {
|
|
14
|
+
private val reflected = Reflect.on(uIViewOperationQueueInstance)
|
|
15
|
+
|
|
16
|
+
fun getViewClass(tag: Int): View? {
|
|
17
|
+
return nativeViewHierarchyManager()?.resolveView(tag)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
private fun nativeViewHierarchyManager(): NativeViewHierarchyManager? {
|
|
21
|
+
return try {
|
|
22
|
+
reflected.field(FIELD_NATIVE_HIERARCHY_MANAGER).get<NativeViewHierarchyManager>()
|
|
23
|
+
} catch(e: ReflectException) {
|
|
24
|
+
Log.e(LOG_TAG, "failed to get $FIELD_NATIVE_HIERARCHY_MANAGER ", e.cause)
|
|
25
|
+
null
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
package com.wix.detox.reactnative.idlingresources.uimodule
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import android.view.View
|
|
5
|
+
import com.wix.detox.common.DetoxLog.Companion.LOG_TAG
|
|
6
|
+
import java.lang.ref.WeakReference
|
|
7
|
+
|
|
8
|
+
private const val NUM_TIMES_BEFORE_NOTIFY_IDLE = 10
|
|
9
|
+
private const val SET_NATIVE_VALUE = "setNativeValue"
|
|
10
|
+
private const val CLASS_REACT_SWITCH = "com.facebook.react.views.switchview.ReactSwitch"
|
|
11
|
+
|
|
12
|
+
class RN66Workaround {
|
|
13
|
+
private var timesStuckQueueDetected = 0
|
|
14
|
+
private var stuckOperation: WeakReference<Any?>? = null
|
|
15
|
+
|
|
16
|
+
// This is a workaround for https://github.com/facebook/react-native/issues/32594
|
|
17
|
+
// uses duck typing heuristics to determine that this is probably the stuck Switch operation and if so, ignores it
|
|
18
|
+
fun isScarceUISwitchCommandStuckInQueue(uiManagerModuleReflected: UIManagerModuleReflected): Boolean {
|
|
19
|
+
var isStuckSwitchOperation = false
|
|
20
|
+
|
|
21
|
+
if (uiManagerModuleReflected.getUIOpsCount() == 1) {
|
|
22
|
+
val nextUIOperation = uiManagerModuleReflected.getNextUIOpReflected()
|
|
23
|
+
val view = getUIOpView(uiManagerModuleReflected, nextUIOperation)
|
|
24
|
+
val isReactSwitch = isReactSwitch(view)
|
|
25
|
+
val hasOneRetryIncremented = nextUIOperation?.numRetries == 1
|
|
26
|
+
val isSetNativeValueCommand = (nextUIOperation?.viewCommand ?: "") == SET_NATIVE_VALUE
|
|
27
|
+
|
|
28
|
+
if (isReactSwitch && hasOneRetryIncremented && isSetNativeValueCommand) {
|
|
29
|
+
if (stuckOperation?.get() == nextUIOperation?.instance) {
|
|
30
|
+
timesStuckQueueDetected++
|
|
31
|
+
} else {
|
|
32
|
+
stuckOperation = WeakReference(nextUIOperation?.instance)
|
|
33
|
+
timesStuckQueueDetected = 0
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (timesStuckQueueDetected >= NUM_TIMES_BEFORE_NOTIFY_IDLE) {
|
|
38
|
+
isStuckSwitchOperation = true
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
timesStuckQueueDetected = 0
|
|
42
|
+
}
|
|
43
|
+
return isStuckSwitchOperation
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private fun getUIOpView(uiManagerModuleReflected: UIManagerModuleReflected, uiOperation: DispatchCommandOperationReflected?): View? {
|
|
47
|
+
val nativeViewHierarchyManager = uiManagerModuleReflected.nativeViewHierarchyManager() ?: return null
|
|
48
|
+
val tag = uiOperation?.tag ?: return null
|
|
49
|
+
return nativeViewHierarchyManager.getViewClass(tag)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private fun isReactSwitch(view: View?) = try {
|
|
53
|
+
val ReactSwitchClass: Class<*> = Class.forName(CLASS_REACT_SWITCH)
|
|
54
|
+
if (view != null) ReactSwitchClass.isAssignableFrom(view.javaClass) else false
|
|
55
|
+
} catch (e: ClassNotFoundException) {
|
|
56
|
+
Log.e(LOG_TAG, "failed to get $CLASS_REACT_SWITCH class ", e.cause)
|
|
57
|
+
false
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
package com.wix.detox.reactnative.idlingresources.uimodule
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import com.facebook.react.bridge.ReactContext
|
|
5
|
+
import com.facebook.react.uimanager.UIViewOperationQueue
|
|
6
|
+
import com.wix.detox.common.DetoxLog.Companion.LOG_TAG
|
|
7
|
+
import org.joor.Reflect
|
|
8
|
+
|
|
9
|
+
private const val CLASS_UI_MANAGER_MODULE = "com.facebook.react.uimanager.UIManagerModule"
|
|
10
|
+
private const val METHOD_GET_NATIVE_MODULE = "getNativeModule"
|
|
11
|
+
private const val METHOD_GET_UI_IMPLEMENTATION = "getUIImplementation"
|
|
12
|
+
private const val FIELD_UI_OPERATION_QUEUE = "mOperationsQueue"
|
|
13
|
+
private const val FIELD_DISPATCH_RUNNABLES = "mDispatchUIRunnables"
|
|
14
|
+
private const val FIELD_DISPATCH_RUNNABLES_LOCK = "mDispatchRunnablesLock"
|
|
15
|
+
private const val FIELD_NON_BATCHED_OPS = "mNonBatchedOperations"
|
|
16
|
+
private const val FIELD_NON_BATCHED_OPS_LOCK = "mNonBatchedOperationsLock"
|
|
17
|
+
private const val METHOD_IS_EMPTY = "isEmpty"
|
|
18
|
+
|
|
19
|
+
class UIManagerModuleReflected(private val reactContext: ReactContext) {
|
|
20
|
+
|
|
21
|
+
fun getUIOpsCount(): Int = (viewCommandOperations()?.size ?: 0)
|
|
22
|
+
fun getNextUIOpReflected() = viewCommandOperations()?.firstCommandReflected()
|
|
23
|
+
|
|
24
|
+
fun nativeViewHierarchyManager(): NativeHierarchyManagerReflected? =
|
|
25
|
+
getUIOperationQueue()?.let {
|
|
26
|
+
NativeHierarchyManagerReflected(it)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
fun isRunnablesListEmpty(): Boolean =
|
|
30
|
+
getUIOperationQueue()?.let {
|
|
31
|
+
synchronized(Reflect.on(it).field(FIELD_DISPATCH_RUNNABLES_LOCK).get()) {
|
|
32
|
+
Reflect.on(it)
|
|
33
|
+
.field(FIELD_DISPATCH_RUNNABLES)
|
|
34
|
+
.call(METHOD_IS_EMPTY).get<Boolean>()
|
|
35
|
+
}
|
|
36
|
+
} ?: true
|
|
37
|
+
|
|
38
|
+
fun isNonBatchOpsEmpty(): Boolean =
|
|
39
|
+
getUIOperationQueue()?.let {
|
|
40
|
+
synchronized(Reflect.on(it).field(FIELD_NON_BATCHED_OPS_LOCK).get()) {
|
|
41
|
+
Reflect.on(it)
|
|
42
|
+
.field(FIELD_NON_BATCHED_OPS)
|
|
43
|
+
.call(METHOD_IS_EMPTY).get<Boolean>()
|
|
44
|
+
}
|
|
45
|
+
} ?: true
|
|
46
|
+
|
|
47
|
+
fun isOperationQueueEmpty(): Boolean =
|
|
48
|
+
getUIOperationQueue()?.let {
|
|
49
|
+
Reflect.on(it).call(METHOD_IS_EMPTY).get<Boolean>()
|
|
50
|
+
} ?: true
|
|
51
|
+
|
|
52
|
+
private fun viewCommandOperations(): ViewCommandOpsQueueReflected? =
|
|
53
|
+
getUIOperationQueue()?.let {
|
|
54
|
+
ViewCommandOpsQueueReflected(it)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
private fun getUIOperationQueue(): UIViewOperationQueue? =
|
|
59
|
+
try {
|
|
60
|
+
val uiModuleClass = Class.forName(CLASS_UI_MANAGER_MODULE)
|
|
61
|
+
Reflect.on(reactContext)
|
|
62
|
+
.call(METHOD_GET_NATIVE_MODULE, uiModuleClass)
|
|
63
|
+
.call(METHOD_GET_UI_IMPLEMENTATION)
|
|
64
|
+
.field(FIELD_UI_OPERATION_QUEUE)
|
|
65
|
+
.get()
|
|
66
|
+
} catch (e: Exception) {
|
|
67
|
+
Log.e(LOG_TAG, "failed to get $CLASS_UI_MANAGER_MODULE instance ", e)
|
|
68
|
+
null
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
package com.wix.detox.reactnative.idlingresources.uimodule
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import android.view.Choreographer
|
|
5
|
+
import androidx.test.espresso.IdlingResource.ResourceCallback
|
|
6
|
+
import com.facebook.react.bridge.ReactContext
|
|
7
|
+
import com.wix.detox.reactnative.helpers.RNHelpers
|
|
8
|
+
import com.wix.detox.reactnative.idlingresources.DetoxBaseIdlingResource
|
|
9
|
+
import com.wix.detox.reactnative.idlingresources.IdlingResourceDescription
|
|
10
|
+
import org.joor.ReflectException
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Espresso IdlingResource for React Native's UI Module.
|
|
14
|
+
* Hooks up to React Native internals to grab the pending ui operations from it.
|
|
15
|
+
*/
|
|
16
|
+
class UIModuleIdlingResource(private val reactContext: ReactContext)
|
|
17
|
+
: DetoxBaseIdlingResource(), Choreographer.FrameCallback {
|
|
18
|
+
|
|
19
|
+
private val rn66workaround = RN66Workaround()
|
|
20
|
+
private val uiManagerModuleReflected = UIManagerModuleReflected(reactContext)
|
|
21
|
+
private var callback: ResourceCallback? = null
|
|
22
|
+
|
|
23
|
+
override fun getName(): String = UIModuleIdlingResource::class.java.name
|
|
24
|
+
override fun getDescription() =
|
|
25
|
+
IdlingResourceDescription.Builder()
|
|
26
|
+
.name("ui")
|
|
27
|
+
.addDescription("reason", "UI rendering activity")
|
|
28
|
+
.build()
|
|
29
|
+
|
|
30
|
+
override fun checkIdle(): Boolean {
|
|
31
|
+
try {
|
|
32
|
+
if (!reactContext.hasActiveCatalystInstance()) {
|
|
33
|
+
Log.e(LOG_TAG, "No active CatalystInstance. Should never see this.")
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (RNHelpers.getNativeModule(reactContext, "com.facebook.react.uimanager.UIManagerModule") == null) {
|
|
38
|
+
notifyIdle()
|
|
39
|
+
return true
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
val runnablesAreEmpty = uiManagerModuleReflected.isRunnablesListEmpty()
|
|
43
|
+
val nonBatchesOpsEmpty = uiManagerModuleReflected.isNonBatchOpsEmpty()
|
|
44
|
+
var operationQueueEmpty = uiManagerModuleReflected.isOperationQueueEmpty()
|
|
45
|
+
|
|
46
|
+
if (!operationQueueEmpty) {
|
|
47
|
+
operationQueueEmpty = rn66workaround.isScarceUISwitchCommandStuckInQueue(uiManagerModuleReflected)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (runnablesAreEmpty && nonBatchesOpsEmpty && operationQueueEmpty) {
|
|
51
|
+
notifyIdle()
|
|
52
|
+
return true
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
Log.i(LOG_TAG, "UIManagerModule is busy")
|
|
56
|
+
Choreographer.getInstance().postFrameCallback(this)
|
|
57
|
+
return false
|
|
58
|
+
} catch (e: ReflectException) {
|
|
59
|
+
Log.e(LOG_TAG, "Can't set up RN UIModule listener", e.cause)
|
|
60
|
+
}
|
|
61
|
+
notifyIdle()
|
|
62
|
+
return true
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
override fun registerIdleTransitionCallback(callback: ResourceCallback) {
|
|
66
|
+
this.callback = callback
|
|
67
|
+
Choreographer.getInstance().postFrameCallback(this)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
override fun doFrame(frameTimeNanos: Long) {
|
|
71
|
+
isIdleNow
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
override fun notifyIdle() {
|
|
75
|
+
callback?.run {
|
|
76
|
+
onTransitionToIdle()
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
companion object {
|
|
81
|
+
private const val LOG_TAG = "Detox"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
package com.wix.detox.reactnative.idlingresources.uimodule
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import com.facebook.react.uimanager.UIViewOperationQueue
|
|
5
|
+
import com.wix.detox.common.DetoxLog.Companion.LOG_TAG
|
|
6
|
+
import org.joor.Reflect
|
|
7
|
+
import org.joor.ReflectException
|
|
8
|
+
|
|
9
|
+
private const val FIELD_VIEW_COMMAND_OPERATIONS = "mViewCommandOperations"
|
|
10
|
+
|
|
11
|
+
class ViewCommandOpsQueueReflected(uiViewOperationQueueInstance: UIViewOperationQueue) {
|
|
12
|
+
private val instance = Reflect.on(uiViewOperationQueueInstance)
|
|
13
|
+
|
|
14
|
+
val size: Int?
|
|
15
|
+
get() = viewCommandOperations()?.size
|
|
16
|
+
|
|
17
|
+
fun firstCommandReflected() = DispatchCommandOperationReflected(firstCommand())
|
|
18
|
+
|
|
19
|
+
private fun firstCommand() = viewCommandOperations()?.elementAt(0)
|
|
20
|
+
private fun viewCommandOperations(): Collection<Any>? =
|
|
21
|
+
try {
|
|
22
|
+
instance.field(FIELD_VIEW_COMMAND_OPERATIONS).get<Collection<Any>>()
|
|
23
|
+
} catch(e: ReflectException) {
|
|
24
|
+
Log.e(LOG_TAG, "could not get reflected field mViewCommandOperations ", e)
|
|
25
|
+
null
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -16,6 +16,7 @@ private class AsyncStorageModuleStub: NativeModule {
|
|
|
16
16
|
override fun initialize() {}
|
|
17
17
|
override fun canOverrideExistingModule() = false
|
|
18
18
|
override fun onCatalystInstanceDestroy() {}
|
|
19
|
+
override fun invalidate() {}
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
class AsyncStorageIdlingResourceSpec: Spek({
|
|
@@ -22,6 +22,8 @@ class TimersNativeModuleStub : NativeModule {
|
|
|
22
22
|
val mTimerGuard = "Lock-Mock"
|
|
23
23
|
|
|
24
24
|
override fun onCatalystInstanceDestroy() {}
|
|
25
|
+
override fun invalidate() {}
|
|
26
|
+
|
|
25
27
|
override fun getName(): String = "TimersNativeModuleStub"
|
|
26
28
|
override fun canOverrideExistingModule() = false
|
|
27
29
|
override fun initialize() {}
|
|
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|
|
3
3
|
distributionPath=wrapper/dists
|
|
4
4
|
zipStoreBase=GRADLE_USER_HOME
|
|
5
5
|
zipStorePath=wrapper/dists
|
|
6
|
-
distributionUrl=https\://services.gradle.org/distributions/gradle-6.
|
|
6
|
+
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-all.zip
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "detox",
|
|
3
3
|
"description": "E2E tests and automation for mobile",
|
|
4
|
-
"version": "19.
|
|
4
|
+
"version": "19.4.0-alpha.0",
|
|
5
5
|
"bin": {
|
|
6
6
|
"detox": "local-cli/cli.js"
|
|
7
7
|
},
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"mocha": ">=6.0.0",
|
|
49
49
|
"mockdate": "^2.0.1",
|
|
50
50
|
"prettier": "1.7.0",
|
|
51
|
-
"react-native": "0.
|
|
51
|
+
"react-native": "0.66.1",
|
|
52
52
|
"react-native-codegen": "^0.0.8",
|
|
53
53
|
"typescript": "^4.5.2",
|
|
54
54
|
"wtfnode": "^0.9.1"
|
|
@@ -171,5 +171,5 @@
|
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
},
|
|
174
|
-
"gitHead": "
|
|
174
|
+
"gitHead": "542893790005eeca88614955e02bbb2f26c1d073"
|
|
175
175
|
}
|
|
@@ -344,7 +344,7 @@ class AppleSimUtils {
|
|
|
344
344
|
}
|
|
345
345
|
|
|
346
346
|
const cmdArgs = quote(_.flatten(this._mergeLaunchArgs(launchArgs, languageAndLocale)));
|
|
347
|
-
let launchBin = `SIMCTL_CHILD_DYLD_INSERT_LIBRARIES="${dylibs}" ` +
|
|
347
|
+
let launchBin = `SIMCTL_CHILD_NSZombieEnabled=YES SIMCTL_CHILD_DYLD_INSERT_LIBRARIES="${dylibs}" ` +
|
|
348
348
|
`/usr/bin/xcrun simctl launch ${udid} ${bundleId} --args ${cmdArgs}`;
|
|
349
349
|
|
|
350
350
|
const result = await exec.execWithRetriesAndLogs(launchBin, {
|
package/src/utils/environment.js
CHANGED
|
@@ -55,11 +55,11 @@ function getAvdDir(avdName) {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
function getAvdManagerPath() {
|
|
58
|
-
return path.join(getAndroidSDKPath(), 'tools', 'bin', 'avdmanager');
|
|
58
|
+
return path.join(getAndroidSDKPath(), 'cmdline-tools', 'latest', 'bin', 'avdmanager');
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
function getAndroidSdkManagerPath() {
|
|
62
|
-
return path.join(getAndroidSDKPath(), 'tools', 'bin', 'sdkmanager');
|
|
62
|
+
return path.join(getAndroidSDKPath(), 'cmdline-tools', 'latest', 'bin', 'sdkmanager');
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
function getAndroidEmulatorPath() {
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
aa55c9b00e351521ce69399a8505e412
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3f85c2fda9140c5b981ebd83c9b0316cdad5210a
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
b24730ebdb6b47b3cd27f8195f632e1117fc46565c0d6ce684bc8c4a6a3fa15b
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
b9442bd45c68c620ab97821382a095a4005326b4d1248fdb15d21f547b0f73701edd1009cdaf366c31cbf111b2a541f683e803e71f7b1951ec86480fa8bbb4a0
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3a57b68454634485e89378b459cdce7d
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
18907b1f57b790f717095345d325c1b48730ca04
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1522127c1dea373e9edf27a669431ba57bd1965aad9f1f30895d02a80dd55920
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
253133008032813ce6f15b399233521858dbf723911ea8a9afdf4e39886e4549cbc55cdfe89cb34c3f6e2135aab3730c7ead42a903f981d428f871b33d29e4a7
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
a32fc8da8e9d97ddb6a7e33be3be4cea
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
702aded71e6e005899a7a4de7e0ebc918e1a246b
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
eb0358d9b4e0e233fe61c516a7727154463639a206fa71341a5e9297147e3f2b
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
c323c30943f8d8c27e1defa9a68c8af7da9f3f73b77942401692fa7f5bf99971df8b064b87a9f01544c2feb7f97c08bf95f47cd08c3e6bfddb74203a069913a9
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
4364b6e95e1a47da2cf7bf04a6d56c85
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
8e8d4e7e8e18abd8e7b67c980b95d7b1ff56536a
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
038995f2e2992c90bbb67f45e3946546961ac68ed0a5db04e17dbc8a21f1c6c8
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
2a49593c977fee87aa54ba67534f9326928b23c35d874e17ce6354cca843779bc832105732004ec5c1e36ed14c82a2db1ee378bfdf59d21753ca8dd813807c4c
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
package com.wix.detox.reactnative.idlingresources;
|
|
2
|
-
|
|
3
|
-
import java.util.ArrayList;
|
|
4
|
-
import java.util.HashMap;
|
|
5
|
-
import java.util.Map;
|
|
6
|
-
import android.util.Log;
|
|
7
|
-
import android.view.Choreographer;
|
|
8
|
-
|
|
9
|
-
import org.jetbrains.annotations.NotNull;
|
|
10
|
-
import org.joor.Reflect;
|
|
11
|
-
import org.joor.ReflectException;
|
|
12
|
-
|
|
13
|
-
import androidx.annotation.NonNull;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Created by simonracz on 26/07/2017.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* <p>
|
|
21
|
-
* Espresso IdlingResource for React Native's UI Module.
|
|
22
|
-
* </p>
|
|
23
|
-
*
|
|
24
|
-
* <p>
|
|
25
|
-
* Hooks up to React Native internals to grab the pending ui operations from it.
|
|
26
|
-
* </p>
|
|
27
|
-
*
|
|
28
|
-
* TODO Rewrite this awful, awful class
|
|
29
|
-
*/
|
|
30
|
-
public class UIModuleIdlingResource extends DetoxBaseIdlingResource implements Choreographer.FrameCallback {
|
|
31
|
-
private static final String LOG_TAG = "Detox";
|
|
32
|
-
|
|
33
|
-
private final static String CLASS_UI_MANAGER_MODULE = "com.facebook.react.uimanager.UIManagerModule";
|
|
34
|
-
private final static String METHOD_GET_NATIVE_MODULE = "getNativeModule";
|
|
35
|
-
private final static String METHOD_HAS_NATIVE_MODULE = "hasNativeModule";
|
|
36
|
-
private final static String METHOD_GET_UI_IMPLEMENTATION = "getUIImplementation";
|
|
37
|
-
private final static String FIELD_UI_OPERATION_QUEUE = "mOperationsQueue";
|
|
38
|
-
private final static String METHOD_IS_EMPTY = "isEmpty";
|
|
39
|
-
private final static String FIELD_DISPATCH_RUNNABLES = "mDispatchUIRunnables";
|
|
40
|
-
private final static String FIELD_NON_BATCHES_OPERATIONS = "mNonBatchedOperations";
|
|
41
|
-
private final static String FIELD_CATALYST_INSTANCE = "mCatalystInstance";
|
|
42
|
-
private final static String LOCK_RUNNABLES = "mDispatchRunnablesLock";
|
|
43
|
-
private final static String LOCK_OPERATIONS = "mNonBatchedOperationsLock";
|
|
44
|
-
|
|
45
|
-
private ResourceCallback callback;
|
|
46
|
-
private Object reactContext;
|
|
47
|
-
|
|
48
|
-
public UIModuleIdlingResource(@NonNull Object reactContext) {
|
|
49
|
-
this.reactContext = reactContext;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
@Override
|
|
53
|
-
public String getName() {
|
|
54
|
-
return UIModuleIdlingResource.class.getName();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
@NotNull
|
|
58
|
-
@Override
|
|
59
|
-
public IdlingResourceDescription getDescription() {
|
|
60
|
-
return new IdlingResourceDescription.Builder()
|
|
61
|
-
.name("ui")
|
|
62
|
-
.addDescription("reason", "UI rendering activity")
|
|
63
|
-
.build();
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
@Override
|
|
67
|
-
protected boolean checkIdle() {
|
|
68
|
-
Class<?> uiModuleClass;
|
|
69
|
-
try {
|
|
70
|
-
uiModuleClass = Class.forName(CLASS_UI_MANAGER_MODULE);
|
|
71
|
-
} catch (ClassNotFoundException e) {
|
|
72
|
-
Log.e(LOG_TAG, "UIManagerModule is not on classpath.");
|
|
73
|
-
notifyIdle();
|
|
74
|
-
return true;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
try {
|
|
78
|
-
// reactContext.hasActiveCatalystInstance() should be always true here
|
|
79
|
-
// if called right after onReactContextInitialized(...)
|
|
80
|
-
if (Reflect.on(reactContext).field(FIELD_CATALYST_INSTANCE).get() == null) {
|
|
81
|
-
Log.e(LOG_TAG, "No active CatalystInstance. Should never see this.");
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (!(boolean)Reflect.on(reactContext).call(METHOD_HAS_NATIVE_MODULE, uiModuleClass).get()) {
|
|
86
|
-
Log.e(LOG_TAG, "Can't find UIManagerModule.");
|
|
87
|
-
notifyIdle();
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
Object uiOperationQueue = Reflect.on(reactContext)
|
|
92
|
-
.call(METHOD_GET_NATIVE_MODULE, uiModuleClass)
|
|
93
|
-
.call(METHOD_GET_UI_IMPLEMENTATION)
|
|
94
|
-
.field(FIELD_UI_OPERATION_QUEUE)
|
|
95
|
-
.get();
|
|
96
|
-
Object runnablesLock = Reflect.on(uiOperationQueue).field(LOCK_RUNNABLES).get();
|
|
97
|
-
Object operationsLock = Reflect.on(uiOperationQueue).field(LOCK_OPERATIONS).get();
|
|
98
|
-
|
|
99
|
-
boolean runnablesAreEmpty;
|
|
100
|
-
boolean nonBatchesOpsEmpty;
|
|
101
|
-
synchronized (runnablesLock) {
|
|
102
|
-
runnablesAreEmpty = (boolean) Reflect.on(uiOperationQueue)
|
|
103
|
-
.field(FIELD_DISPATCH_RUNNABLES)
|
|
104
|
-
.call(METHOD_IS_EMPTY).get();
|
|
105
|
-
}
|
|
106
|
-
synchronized (operationsLock) {
|
|
107
|
-
nonBatchesOpsEmpty = (boolean) Reflect.on(uiOperationQueue)
|
|
108
|
-
.field(FIELD_NON_BATCHES_OPERATIONS)
|
|
109
|
-
.call(METHOD_IS_EMPTY).get();
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
boolean isOperationQueueEmpty = (Boolean) Reflect.on(uiOperationQueue).call(METHOD_IS_EMPTY).get();
|
|
113
|
-
|
|
114
|
-
if (runnablesAreEmpty && nonBatchesOpsEmpty && isOperationQueueEmpty) {
|
|
115
|
-
notifyIdle();
|
|
116
|
-
// Log.i(LOG_TAG, "UIManagerModule is idle.");
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
Log.i(LOG_TAG, "UIManagerModule is busy");
|
|
121
|
-
Choreographer.getInstance().postFrameCallback(this);
|
|
122
|
-
return false;
|
|
123
|
-
} catch (ReflectException e) {
|
|
124
|
-
Log.e(LOG_TAG, "Can't set up RN UIModule listener", e.getCause());
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
notifyIdle();
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
@Override
|
|
132
|
-
public void registerIdleTransitionCallback(ResourceCallback callback) {
|
|
133
|
-
this.callback = callback;
|
|
134
|
-
Choreographer.getInstance().postFrameCallback(this);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
@Override
|
|
138
|
-
public void doFrame(long frameTimeNanos) {
|
|
139
|
-
isIdleNow();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
@Override
|
|
143
|
-
protected void notifyIdle() {
|
|
144
|
-
if (callback != null) {
|
|
145
|
-
callback.onTransitionToIdle();
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|