detox 20.12.0 → 20.12.2
Sign up to get free protection for your applications and to get access to all the features.
- package/Detox-android/com/wix/detox/{20.12.0/detox-20.12.0-javadoc.jar → 20.12.2/detox-20.12.2-javadoc.jar} +0 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2-javadoc.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2-javadoc.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2-javadoc.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2-javadoc.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{20.12.0/detox-20.12.0-sources.jar → 20.12.2/detox-20.12.2-sources.jar} +0 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2-sources.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2-sources.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2-sources.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2-sources.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2.aar +0 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2.aar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2.aar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2.aar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2.aar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{20.12.0/detox-20.12.0.pom → 20.12.2/detox-20.12.2.pom} +1 -7
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2.pom.md5 +1 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2.pom.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2.pom.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.12.2/detox-20.12.2.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/detox/build.gradle +4 -3
- package/android/detox/src/full/java/com/wix/detox/espresso/action/AdjustSliderToPositionAction.kt +2 -2
- package/android/detox/src/full/java/com/wix/detox/espresso/action/GetAttributesAction.kt +30 -31
- package/android/detox/src/full/java/com/wix/detox/espresso/common/MaterialSliderHelper.kt +21 -0
- package/android/detox/src/full/java/com/wix/detox/espresso/common/{SliderHelper.kt → ReactSliderHelper.kt} +6 -5
- package/android/detox/src/full/java/com/wix/detox/espresso/matcher/ViewMatchers.kt +2 -2
- package/android/detox/src/testFull/java/com/wix/detox/espresso/common/MaterialSliderHelperTest.kt +33 -0
- package/android/detox/src/testFull/java/com/wix/detox/espresso/common/{SliderHelperTest.kt → ReactSliderHelperTest.kt} +3 -3
- package/index.d.ts +43 -0
- package/internals.d.ts +10 -1
- package/package.json +2 -2
- package/runners/jest/reporters/DetoxReporter.js +127 -9
- package/runners/jest/testEnvironment/index.js +5 -0
- package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +2 -0
- package/src/ipc/IPCClient.js +5 -0
- package/src/ipc/IPCServer.js +13 -0
- package/src/ipc/SessionState.js +1 -0
- package/src/realms/DetoxContext.js +2 -0
- package/src/realms/DetoxInternalsFacade.js +1 -0
- package/src/realms/DetoxPrimaryContext.js +6 -0
- package/src/realms/DetoxSecondaryContext.js +8 -0
- package/src/realms/symbols.js +2 -0
- package/src/utils/errorUtils.js +1 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-javadoc.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-javadoc.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-javadoc.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-javadoc.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.aar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.pom.md5 +0 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.pom.sha512 +0 -1
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
9f36d2885a93f2a409ee4e590f8678fe
|
@@ -0,0 +1 @@
|
|
1
|
+
7627d2bccbd1f922472cb85f9e8480210d672d39
|
@@ -0,0 +1 @@
|
|
1
|
+
43075c10900e4d81f273d56e642d1230ec01a4748996955a452ee0374aec0200
|
@@ -0,0 +1 @@
|
|
1
|
+
2ba3ccabd9c41ad2ffb785c5c2ca9b5baedfe51fadcdcdc7b2c7c215335b061e693f7985800d562dd2e7449503e7e5d44a4332daf00a85f4e5b05da848a1f37f
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
bc5126d7b11cf8ad581aab27d743b430
|
@@ -0,0 +1 @@
|
|
1
|
+
ad9dc488b327afa3154138a147f3873dd4f6b644
|
@@ -0,0 +1 @@
|
|
1
|
+
d80d2d1e03c7f3b8b75ed70946e31725694cb29d4900eacc115276295b773347
|
@@ -0,0 +1 @@
|
|
1
|
+
be1d9cc4b36042e3f0416159a7b9509ce9e35de4eaabad53c385690a893bc51a0f453e0fe46173e91436b9f1e3dcbe9ab209434e1173558d5a87e5a94c8b278b
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
0ff20c1510b97ba80b15a438ce65bddc
|
@@ -0,0 +1 @@
|
|
1
|
+
449b07e6bb8435baef57e3d0839e68b5f7f85af5
|
@@ -0,0 +1 @@
|
|
1
|
+
c3347ddd7b4e4a94c60c55c079451ea219e050f7c69b8dbc7b59a453d2398e67
|
@@ -0,0 +1 @@
|
|
1
|
+
ebcf7f52b7e34a391174fc8850879e39a3e3f8f8ccfa0a417937680187461d5b41f7811933ca5ca088c554ae7a4e8d8cb2198375fdbb55680888aac561c71f64
|
@@ -3,7 +3,7 @@
|
|
3
3
|
<modelVersion>4.0.0</modelVersion>
|
4
4
|
<groupId>com.wix</groupId>
|
5
5
|
<artifactId>detox</artifactId>
|
6
|
-
<version>20.12.
|
6
|
+
<version>20.12.2</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>
|
@@ -84,12 +84,6 @@
|
|
84
84
|
<version>1.2.0</version>
|
85
85
|
<scope>runtime</scope>
|
86
86
|
</dependency>
|
87
|
-
<dependency>
|
88
|
-
<groupId>com.google.android.material</groupId>
|
89
|
-
<artifactId>material</artifactId>
|
90
|
-
<version>1.2.1</version>
|
91
|
-
<scope>runtime</scope>
|
92
|
-
</dependency>
|
93
87
|
<dependency>
|
94
88
|
<groupId>org.apache.commons</groupId>
|
95
89
|
<artifactId>commons-lang3</artifactId>
|
@@ -0,0 +1 @@
|
|
1
|
+
06ea49e97933d82debed143a3e362af8
|
@@ -0,0 +1 @@
|
|
1
|
+
866a73f92aa581f2d23afd5df152cce65a882de6
|
@@ -0,0 +1 @@
|
|
1
|
+
b7e47d08915a497db5f42985f3435420bf7580178c6975d1f257123c7bc53b4f
|
@@ -0,0 +1 @@
|
|
1
|
+
f7fbbb355ce037d0519ad63caeebab6447f1e38f25ce44d495267510f7e4576978fff4b676f1a86966e7f638b4678b7bc769f50e4ffa1d106c786db72b9f7d6b
|
@@ -3,11 +3,11 @@
|
|
3
3
|
<groupId>com.wix</groupId>
|
4
4
|
<artifactId>detox</artifactId>
|
5
5
|
<versioning>
|
6
|
-
<latest>20.12.
|
7
|
-
<release>20.12.
|
6
|
+
<latest>20.12.2</latest>
|
7
|
+
<release>20.12.2</release>
|
8
8
|
<versions>
|
9
|
-
<version>20.12.
|
9
|
+
<version>20.12.2</version>
|
10
10
|
</versions>
|
11
|
-
<lastUpdated>
|
11
|
+
<lastUpdated>20230927202100</lastUpdated>
|
12
12
|
</versioning>
|
13
13
|
</metadata>
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
c4e29695a8333254dfdb58e83b723a94
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
8c90e83ee27dd4d9370742524f141054555c926b
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
5fb1606470374345397232c3529c053c5aa26fd8650b3f7d9706f251a7f2e3b8
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
541d2924f1ccdd6c901ba584a978d8d26ba3027c6abca381dcb6b2553b4b730ca428d6743bc9d1fe0836e2662a4e81f5d53049fa164376173e76960fcdc33ccc
|
package/Detox-ios-src.tbz
CHANGED
Binary file
|
package/Detox-ios.tbz
CHANGED
Binary file
|
@@ -126,9 +126,6 @@ dependencies {
|
|
126
126
|
|
127
127
|
// Third-party/extension deps.
|
128
128
|
dependencies {
|
129
|
-
implementation("com.google.android.material:material:$_materialMinVersion") {
|
130
|
-
because 'Material components are mentioned explicitly (e.g. Slider in get-attributes handler)'
|
131
|
-
}
|
132
129
|
implementation('org.apache.commons:commons-lang3:3.7') {
|
133
130
|
because 'Needed by invoke. Warning: Upgrading to newer versions is not seamless.'
|
134
131
|
}
|
@@ -150,6 +147,10 @@ dependencies {
|
|
150
147
|
testImplementation 'org.apache.commons:commons-io:1.3.2'
|
151
148
|
testImplementation 'org.mockito.kotlin:mockito-kotlin:4.0.0'
|
152
149
|
testImplementation 'org.robolectric:robolectric:4.4'
|
150
|
+
|
151
|
+
testImplementation("com.google.android.material:material:$_materialMinVersion") {
|
152
|
+
because 'Material components are mentioned explicitly (e.g. Slider in get-attributes handler)'
|
153
|
+
}
|
153
154
|
}
|
154
155
|
|
155
156
|
// Spek (https://spekframework.org/setup-android)
|
package/android/detox/src/full/java/com/wix/detox/espresso/action/AdjustSliderToPositionAction.kt
CHANGED
@@ -6,7 +6,7 @@ import androidx.test.espresso.UiController
|
|
6
6
|
import androidx.test.espresso.ViewAction
|
7
7
|
import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom
|
8
8
|
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
9
|
-
import com.wix.detox.espresso.common.
|
9
|
+
import com.wix.detox.espresso.common.ReactSliderHelper
|
10
10
|
import org.hamcrest.Matcher
|
11
11
|
import org.hamcrest.Matchers
|
12
12
|
|
@@ -16,7 +16,7 @@ class AdjustSliderToPositionAction(private val targetPositionPct: Double) : View
|
|
16
16
|
Matchers.allOf( isDisplayed(), isAssignableFrom(AppCompatSeekBar::class.java) )
|
17
17
|
|
18
18
|
override fun perform(uiController: UiController?, view: View) {
|
19
|
-
val sliderHelper =
|
19
|
+
val sliderHelper = ReactSliderHelper.create(view)
|
20
20
|
sliderHelper.setProgressPct(targetPositionPct)
|
21
21
|
}
|
22
22
|
}
|
@@ -7,10 +7,10 @@ import android.widget.CheckBox
|
|
7
7
|
import android.widget.ProgressBar
|
8
8
|
import android.widget.TextView
|
9
9
|
import androidx.test.espresso.UiController
|
10
|
-
import com.google.android.material.slider.Slider
|
11
10
|
import com.wix.detox.espresso.ViewActionWithResult
|
12
11
|
import com.wix.detox.espresso.MultipleViewsAction
|
13
|
-
import com.wix.detox.espresso.common.
|
12
|
+
import com.wix.detox.espresso.common.ReactSliderHelper
|
13
|
+
import com.wix.detox.espresso.common.MaterialSliderHelper
|
14
14
|
import com.wix.detox.reactnative.ui.getAccessibilityLabel
|
15
15
|
import org.hamcrest.Matcher
|
16
16
|
import org.hamcrest.Matchers
|
@@ -18,23 +18,25 @@ import org.hamcrest.Matchers.allOf
|
|
18
18
|
import org.hamcrest.Matchers.notNullValue
|
19
19
|
import org.json.JSONObject
|
20
20
|
|
21
|
+
private interface AttributeExtractor {
|
22
|
+
fun extractAttributes(json: JSONObject, view: View)
|
23
|
+
}
|
24
|
+
|
21
25
|
class GetAttributesAction() : ViewActionWithResult<JSONObject?>, MultipleViewsAction {
|
22
|
-
private val
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
26
|
+
private val attributeExtractors = listOf(
|
27
|
+
CommonAttributes(),
|
28
|
+
TextViewAttributes(),
|
29
|
+
CheckBoxAttributes(),
|
30
|
+
ProgressBarAttributes(),
|
31
|
+
MaterialSliderAttributes()
|
32
|
+
)
|
27
33
|
private var result: JSONObject? = null
|
28
34
|
|
29
35
|
override fun perform(uiController: UiController?, view: View?) {
|
30
36
|
view!!
|
31
37
|
|
32
38
|
val json = JSONObject()
|
33
|
-
|
34
|
-
textViewAttributes.get(json, view)
|
35
|
-
checkBoxAttributes.get(json, view)
|
36
|
-
progressBarAttributes.get(json, view)
|
37
|
-
sliderAttributes.get(json, view)
|
39
|
+
attributeExtractors.forEach { it.extractAttributes(json, view) }
|
38
40
|
|
39
41
|
result = json
|
40
42
|
}
|
@@ -44,8 +46,8 @@ class GetAttributesAction() : ViewActionWithResult<JSONObject?>, MultipleViewsAc
|
|
44
46
|
override fun getConstraints(): Matcher<View> = allOf(notNullValue(), Matchers.isA(View::class.java))
|
45
47
|
}
|
46
48
|
|
47
|
-
private class CommonAttributes {
|
48
|
-
fun
|
49
|
+
private class CommonAttributes : AttributeExtractor {
|
50
|
+
override fun extractAttributes(json: JSONObject, view: View) {
|
49
51
|
getId(json, view)
|
50
52
|
getVisibility(json, view)
|
51
53
|
getAccessibilityLabel(json, view)
|
@@ -89,8 +91,8 @@ private class CommonAttributes {
|
|
89
91
|
}
|
90
92
|
}
|
91
93
|
|
92
|
-
private class TextViewAttributes {
|
93
|
-
fun
|
94
|
+
private class TextViewAttributes : AttributeExtractor {
|
95
|
+
override fun extractAttributes(json: JSONObject, view: View) {
|
94
96
|
if (view is TextView) {
|
95
97
|
getText(json, view)
|
96
98
|
getLength(json, view)
|
@@ -118,8 +120,8 @@ private class TextViewAttributes {
|
|
118
120
|
}
|
119
121
|
}
|
120
122
|
|
121
|
-
private class CheckBoxAttributes {
|
122
|
-
fun
|
123
|
+
private class CheckBoxAttributes : AttributeExtractor {
|
124
|
+
override fun extractAttributes(json: JSONObject, view: View) {
|
123
125
|
if (view is CheckBox) {
|
124
126
|
getCheckboxValue(json, view)
|
125
127
|
}
|
@@ -133,31 +135,28 @@ private class CheckBoxAttributes {
|
|
133
135
|
* Note: this applies also to [androidx.appcompat.widget.AppCompatSeekBar], which
|
134
136
|
* is anything RN-slider-ish.
|
135
137
|
*/
|
136
|
-
private class ProgressBarAttributes {
|
137
|
-
fun
|
138
|
+
private class ProgressBarAttributes : AttributeExtractor {
|
139
|
+
override fun extractAttributes(json: JSONObject, view: View) {
|
138
140
|
if (view is ProgressBar) {
|
139
|
-
|
140
|
-
|
141
|
+
ReactSliderHelper.maybeCreate(view)?.let {
|
142
|
+
getReactSliderValue(json, it)
|
141
143
|
} ?:
|
142
144
|
getProgressBarValue(json, view)
|
143
145
|
}
|
144
146
|
}
|
145
147
|
|
146
|
-
private fun
|
147
|
-
rootObject.put("value",
|
148
|
+
private fun getReactSliderValue(rootObject: JSONObject, reactSliderHelper: ReactSliderHelper) {
|
149
|
+
rootObject.put("value", reactSliderHelper.getCurrentProgressPct())
|
148
150
|
}
|
149
151
|
|
150
152
|
private fun getProgressBarValue(rootObject: JSONObject, view: ProgressBar) =
|
151
153
|
rootObject.put("value", view.progress)
|
152
154
|
}
|
153
155
|
|
154
|
-
private class
|
155
|
-
fun
|
156
|
-
|
157
|
-
|
156
|
+
private class MaterialSliderAttributes : AttributeExtractor {
|
157
|
+
override fun extractAttributes(json: JSONObject, view: View) {
|
158
|
+
MaterialSliderHelper(view).getValueIfSlider()?.let {
|
159
|
+
json.put("value", it)
|
158
160
|
}
|
159
161
|
}
|
160
|
-
|
161
|
-
private fun getSliderValue(rootObject: JSONObject, view: Slider) =
|
162
|
-
rootObject.put("value", view.value)
|
163
162
|
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
package com.wix.detox.espresso.common
|
2
|
+
|
3
|
+
import android.view.View
|
4
|
+
import com.wix.detox.espresso.action.common.ReflectUtils
|
5
|
+
import org.joor.Reflect
|
6
|
+
|
7
|
+
private const val CLASS_MATERIAL_SLIDER = "com.google.android.material.slider.Slider"
|
8
|
+
|
9
|
+
open class MaterialSliderHelper(protected val view: View) {
|
10
|
+
fun getValueIfSlider(): Float? {
|
11
|
+
if (!isSlider()) {
|
12
|
+
return null
|
13
|
+
}
|
14
|
+
|
15
|
+
return getValue()
|
16
|
+
}
|
17
|
+
|
18
|
+
private fun isSlider() = ReflectUtils.isAssignableFrom(view, CLASS_MATERIAL_SLIDER)
|
19
|
+
|
20
|
+
private fun getValue() = Reflect.on(view).call("getValue").get() as Float
|
21
|
+
}
|
@@ -11,8 +11,9 @@ import org.joor.Reflect
|
|
11
11
|
|
12
12
|
private const val CLASS_REACT_SLIDER_LEGACY = "com.facebook.react.views.slider.ReactSlider"
|
13
13
|
private const val CLASS_REACT_SLIDER_COMMUNITY = "com.reactnativecommunity.slider.ReactSlider"
|
14
|
+
private const val CLASS_REACT_SLIDER_COMMUNITY_MANAGER = "com.reactnativecommunity.slider.ReactSliderManager"
|
14
15
|
|
15
|
-
abstract class
|
16
|
+
abstract class ReactSliderHelper(protected val slider: AppCompatSeekBar) {
|
16
17
|
fun getCurrentProgressPct(): Double {
|
17
18
|
val nativeProgress = slider.progress.toDouble()
|
18
19
|
val nativeMax = slider.max
|
@@ -46,7 +47,7 @@ abstract class SliderHelper(protected val slider: AppCompatSeekBar) {
|
|
46
47
|
?: throw DetoxIllegalStateException("Cannot handle this type of a seek-bar view (Class ${view.javaClass.canonicalName}). " +
|
47
48
|
"Only React Native sliders are currently supported.")
|
48
49
|
|
49
|
-
fun maybeCreate(view: View):
|
50
|
+
fun maybeCreate(view: View): ReactSliderHelper? =
|
50
51
|
when {
|
51
52
|
ReflectUtils.isAssignableFrom(view, CLASS_REACT_SLIDER_LEGACY)
|
52
53
|
-> LegacySliderHelper(view as ReactSlider)
|
@@ -58,7 +59,7 @@ abstract class SliderHelper(protected val slider: AppCompatSeekBar) {
|
|
58
59
|
}
|
59
60
|
}
|
60
61
|
|
61
|
-
private class LegacySliderHelper(slider: ReactSlider):
|
62
|
+
private class LegacySliderHelper(slider: ReactSlider): ReactSliderHelper(slider) {
|
62
63
|
override fun setProgressJS(valueJS: Double) {
|
63
64
|
val reactSliderManager = com.facebook.react.views.slider.ReactSliderManager()
|
64
65
|
reactSliderManager.updateProperties(slider as ReactSlider, buildStyles("value", valueJS))
|
@@ -67,9 +68,9 @@ private class LegacySliderHelper(slider: ReactSlider): SliderHelper(slider) {
|
|
67
68
|
private fun buildStyles(vararg keysAndValues: Any) = ReactStylesDiffMap(JavaOnlyMap.of(*keysAndValues))
|
68
69
|
}
|
69
70
|
|
70
|
-
private class CommunitySliderHelper(slider: AppCompatSeekBar):
|
71
|
+
private class CommunitySliderHelper(slider: AppCompatSeekBar): ReactSliderHelper(slider) {
|
71
72
|
override fun setProgressJS(valueJS: Double) {
|
72
|
-
val reactSliderManager = Class.forName(
|
73
|
+
val reactSliderManager = Class.forName(CLASS_REACT_SLIDER_COMMUNITY_MANAGER).newInstance()
|
73
74
|
Reflect.on(reactSliderManager).call("setValue", slider, valueJS)
|
74
75
|
}
|
75
76
|
}
|
@@ -7,7 +7,7 @@ import androidx.appcompat.widget.AppCompatSeekBar
|
|
7
7
|
import androidx.test.espresso.matcher.BoundedMatcher
|
8
8
|
import androidx.test.espresso.matcher.ViewMatchers
|
9
9
|
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
10
|
-
import com.wix.detox.espresso.common.
|
10
|
+
import com.wix.detox.espresso.common.ReactSliderHelper
|
11
11
|
import org.hamcrest.*
|
12
12
|
import org.hamcrest.Matchers.*
|
13
13
|
import kotlin.math.abs
|
@@ -60,7 +60,7 @@ fun toHaveSliderPosition(expectedValuePct: Double, tolerance: Double): Matcher<V
|
|
60
60
|
}
|
61
61
|
|
62
62
|
override fun matchesSafely(view: AppCompatSeekBar): Boolean {
|
63
|
-
val sliderHelper =
|
63
|
+
val sliderHelper = ReactSliderHelper.create(view)
|
64
64
|
val progressPct = sliderHelper.getCurrentProgressPct()
|
65
65
|
return (abs(progressPct - expectedValuePct) <= tolerance)
|
66
66
|
}
|
package/android/detox/src/testFull/java/com/wix/detox/espresso/common/MaterialSliderHelperTest.kt
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
package com.wix.detox.espresso.common
|
2
|
+
|
3
|
+
import android.view.View
|
4
|
+
import com.google.android.material.slider.Slider
|
5
|
+
import org.assertj.core.api.Assertions.assertThat
|
6
|
+
import org.junit.Test
|
7
|
+
import org.junit.runner.RunWith
|
8
|
+
import org.mockito.kotlin.doReturn
|
9
|
+
import org.mockito.kotlin.mock
|
10
|
+
import org.robolectric.RobolectricTestRunner
|
11
|
+
|
12
|
+
@RunWith(RobolectricTestRunner::class)
|
13
|
+
class MaterialSliderHelperTest {
|
14
|
+
@Test
|
15
|
+
fun `should return value if view is a slider`() {
|
16
|
+
val slider: Slider = mock {
|
17
|
+
on { value } doReturn 0.2f
|
18
|
+
}
|
19
|
+
|
20
|
+
val uut = MaterialSliderHelper(slider)
|
21
|
+
|
22
|
+
assertThat(uut.getValueIfSlider()).isEqualTo(0.2f)
|
23
|
+
}
|
24
|
+
|
25
|
+
@Test
|
26
|
+
fun `should return null if view is not a slider`() {
|
27
|
+
val view: View = mock()
|
28
|
+
|
29
|
+
val uut = MaterialSliderHelper(view)
|
30
|
+
|
31
|
+
assertThat(uut.getValueIfSlider()).isNull()
|
32
|
+
}
|
33
|
+
}
|
@@ -15,14 +15,14 @@ import org.robolectric.RobolectricTestRunner
|
|
15
15
|
* to avoid having to install the community slider under node_modules just for this.
|
16
16
|
*/
|
17
17
|
@RunWith(RobolectricTestRunner::class)
|
18
|
-
class
|
18
|
+
class ReactSliderHelperTest {
|
19
19
|
lateinit var slider: ReactSlider
|
20
|
-
lateinit var uut:
|
20
|
+
lateinit var uut: ReactSliderHelper
|
21
21
|
|
22
22
|
@Before
|
23
23
|
fun setup() {
|
24
24
|
slider = mock()
|
25
|
-
uut =
|
25
|
+
uut = ReactSliderHelper.create(slider)
|
26
26
|
}
|
27
27
|
|
28
28
|
private fun givenNativeProgressTraits(current: Int, max: Int) {
|
package/index.d.ts
CHANGED
@@ -624,6 +624,10 @@ declare global {
|
|
624
624
|
get(): object;
|
625
625
|
}
|
626
626
|
|
627
|
+
type DigitWithoutZero = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
|
628
|
+
type Digit = 0 | DigitWithoutZero;
|
629
|
+
type BatteryLevel = `${Digit}` | `${DigitWithoutZero}${Digit}` | "100";
|
630
|
+
|
627
631
|
interface Device {
|
628
632
|
/**
|
629
633
|
* Holds the environment-unique ID of the device, namely, the adb ID on Android (e.g. emulator-5554) and the Mac-global simulator UDID on iOS -
|
@@ -789,6 +793,45 @@ declare global {
|
|
789
793
|
*/
|
790
794
|
setLocation(lat: number, lon: number): Promise<void>;
|
791
795
|
|
796
|
+
/**
|
797
|
+
* (iOS only) Override simulator’s status bar.
|
798
|
+
* @platform iOS
|
799
|
+
* @param {config} config status bar configuration.
|
800
|
+
* @example
|
801
|
+
* await device.setStatusBar({
|
802
|
+
* time: "12:34",
|
803
|
+
* // Set the date or time to a fixed value.
|
804
|
+
* // If the string is a valid ISO date string it will also set the date on relevant devices.
|
805
|
+
* dataNetwork: "wifi",
|
806
|
+
* // If specified must be one of 'hide', 'wifi', '3g', '4g', 'lte', 'lte-a', 'lte+', '5g', '5g+', '5g-uwb', or '5g-uc'.
|
807
|
+
* wifiMode: "failed",
|
808
|
+
* // If specified must be one of 'searching', 'failed', or 'active'.
|
809
|
+
* wifiBars: "2",
|
810
|
+
* // If specified must be 0-3.
|
811
|
+
* cellularMode: "searching",
|
812
|
+
* // If specified must be one of 'notSupported', 'searching', 'failed', or 'active'.
|
813
|
+
* cellularBars: "3",
|
814
|
+
* // If specified must be 0-4.
|
815
|
+
* operatorName: "A1",
|
816
|
+
* // Set the cellular operator/carrier name. Use '' for the empty string.
|
817
|
+
* batteryState: "charging",
|
818
|
+
* // If specified must be one of 'charging', 'charged', or 'discharging'.
|
819
|
+
* batteryLevel: "50",
|
820
|
+
* // If specified must be 0-100.
|
821
|
+
* });
|
822
|
+
*/
|
823
|
+
setStatusBar(config: {
|
824
|
+
time?: string,
|
825
|
+
dataNetwork?: "hide" | "wifi" | "3g" | "4g" | "lte" | "lte-a" | "lte+" | "5g" | "5g+" | "5g-uwb" | "5g-uc",
|
826
|
+
wifiMode?: "searching" |"failed" | "active",
|
827
|
+
wifiBars?: "0" | "1" | "2" | "3",
|
828
|
+
cellularMode?: "notSupported" | "searching" | "failed" | "active",
|
829
|
+
cellularBars?: "0" | "1" | "2" | "3" | "4",
|
830
|
+
operatorName?: string;
|
831
|
+
batteryState?: "charging" | "charged" | "discharging",
|
832
|
+
batteryLevel?: BatteryLevel,
|
833
|
+
}): Promise<void>;
|
834
|
+
|
792
835
|
/**
|
793
836
|
* Disable network synchronization mechanism on preferred endpoints. Useful if you want to on skip over synchronizing on certain URLs.
|
794
837
|
*
|
package/internals.d.ts
CHANGED
@@ -113,7 +113,11 @@ declare global {
|
|
113
113
|
/** Test suite name */
|
114
114
|
name: string;
|
115
115
|
}): Promise<void>;
|
116
|
-
|
116
|
+
/**
|
117
|
+
* Workaround for Jest exiting abruptly in --bail mode.
|
118
|
+
* Makes sure that all workers and their test environments are properly torn down.
|
119
|
+
*/
|
120
|
+
unsafe_conductEarlyTeardown(): Promise<void>;
|
117
121
|
/**
|
118
122
|
* Reports to Detox CLI about passed and failed test files.
|
119
123
|
* The failed test files might be re-run again if
|
@@ -215,6 +219,11 @@ declare global {
|
|
215
219
|
* Randomly generated ID for the entire Detox test session, including retries.
|
216
220
|
*/
|
217
221
|
id: string;
|
222
|
+
/**
|
223
|
+
* Signalizes that the test session is being torn down.
|
224
|
+
* Experimental feature for Jest --bail mode.
|
225
|
+
*/
|
226
|
+
unsafe_earlyTeardown?: boolean;
|
218
227
|
/**
|
219
228
|
* Results of test file executions. Primarily used for Detox CLI retry mechanism.
|
220
229
|
*/
|
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": "20.12.
|
4
|
+
"version": "20.12.2",
|
5
5
|
"bin": {
|
6
6
|
"detox": "local-cli/cli.js"
|
7
7
|
},
|
@@ -206,5 +206,5 @@
|
|
206
206
|
"browserslist": [
|
207
207
|
"node 14"
|
208
208
|
],
|
209
|
-
"gitHead": "
|
209
|
+
"gitHead": "3ed86bf3628cda4673412a4e2c38e32077473851"
|
210
210
|
}
|
@@ -1,24 +1,142 @@
|
|
1
1
|
const resolveFrom = require('resolve-from');
|
2
|
-
/** @type {
|
2
|
+
/** @type {new (globalConfig: any) => import('@jest/reporters').VerboseReporter} */
|
3
3
|
const JestVerboseReporter = require(resolveFrom(process.cwd(), '@jest/reporters')).VerboseReporter;
|
4
|
+
/** @type {new (globalConfig: any) => import('@jest/reporters').SummaryReporter} */
|
5
|
+
const SummaryReporter = require(resolveFrom(process.cwd(), '@jest/reporters')).SummaryReporter;
|
4
6
|
|
5
|
-
const { config, reportTestResults } = require('../../../internals');
|
7
|
+
const { config, reportTestResults, unsafe_conductEarlyTeardown, cleanup } = require('../../../internals');
|
8
|
+
const Deferred = require('../../../src/utils/Deferred');
|
6
9
|
|
7
10
|
class DetoxReporter extends JestVerboseReporter {
|
11
|
+
constructor(globalConfig) {
|
12
|
+
super(globalConfig);
|
13
|
+
|
14
|
+
/** @type {Deferred | null} */
|
15
|
+
this._lastRunComplete = null;
|
16
|
+
/** @type {Set<string>} */
|
17
|
+
this._pendingTestFiles = new Set();
|
18
|
+
/** @type {Promise<any> | null} */
|
19
|
+
this._runCompletePromise = null;
|
20
|
+
/** @type {import('@jest/reporters').SummaryReporter | null} */
|
21
|
+
this._summaryReporter = this._initSummaryReporter();
|
22
|
+
}
|
23
|
+
|
24
|
+
onRunStart(aggregatedResults, options) {
|
25
|
+
super.onRunStart(aggregatedResults, options);
|
26
|
+
|
27
|
+
if (this._summaryReporter) {
|
28
|
+
this._summaryReporter.onRunStart(aggregatedResults, options);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
onTestFileStart(test) {
|
33
|
+
this._pendingTestFiles.add(test.path);
|
34
|
+
|
35
|
+
// @ts-ignore Precaution in case Jest migrates to the new signature
|
36
|
+
if (typeof super.onTestFileStart === 'function') {
|
37
|
+
// @ts-ignore
|
38
|
+
super.onTestFileStart(test);
|
39
|
+
} else {
|
40
|
+
super.onTestStart(test);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
onTestFileResult(test, testResult, aggregatedResult) {
|
45
|
+
this._pendingTestFiles.delete(test.path);
|
46
|
+
|
47
|
+
// @ts-ignore Precaution in case Jest migrates to the new signature
|
48
|
+
if (typeof super.onTestFileResult === 'function') {
|
49
|
+
// @ts-ignore
|
50
|
+
super.onTestFileResult(test, testResult, aggregatedResult);
|
51
|
+
} else {
|
52
|
+
super.onTestResult(test, testResult, aggregatedResult);
|
53
|
+
}
|
54
|
+
|
55
|
+
if (this._lastRunComplete && this._pendingTestFiles.size === 0) {
|
56
|
+
this._lastRunComplete.resolve(aggregatedResult);
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
8
60
|
/**
|
9
|
-
* @param {import('@jest/
|
61
|
+
* @param {Set<import('@jest/reporters').TestContext>} testContexts
|
62
|
+
* @param {import('@jest/reporters').AggregatedResult} aggregatedResult
|
63
|
+
* @returns {Promise<any> | null}
|
10
64
|
*/
|
11
|
-
// @ts-ignore
|
12
|
-
|
13
|
-
|
14
|
-
|
65
|
+
// @ts-ignore We need to use the complete signature, not the one from the base class
|
66
|
+
onRunComplete(testContexts, aggregatedResult) {
|
67
|
+
if (!this._runCompletePromise) {
|
68
|
+
// Both `_lastRunComplete` and `_runCompletePromise` are used to prevent
|
69
|
+
// a bug in Jest, where `onRunComplete` is called multiple times when
|
70
|
+
// Jest runs with `--bail` and multiple workers, and `onRunComplete`
|
71
|
+
// is implemented as an asynchronous long-running operation.
|
72
|
+
this._lastRunComplete = this._pendingTestFiles.size === 0
|
73
|
+
? Deferred.resolved(aggregatedResult)
|
74
|
+
: new Deferred();
|
15
75
|
|
16
|
-
|
76
|
+
this._runCompletePromise = this._onRunComplete(testContexts, aggregatedResult).catch(err => {
|
77
|
+
console.error(err);
|
78
|
+
throw err;
|
79
|
+
});
|
80
|
+
}
|
81
|
+
|
82
|
+
return this._runCompletePromise;
|
83
|
+
}
|
84
|
+
|
85
|
+
/**
|
86
|
+
* @param {Set<import('@jest/reporters').TestContext>} testContexts
|
87
|
+
* @param {import('@jest/reporters').AggregatedResult} aggregatedResult
|
88
|
+
* @returns {Promise<any> | null}
|
89
|
+
*/
|
90
|
+
async _onRunComplete(testContexts, { numFailedTests }) {
|
91
|
+
const bail = this._globalConfig.bail;
|
92
|
+
const earlyTeardown = bail > 0 && numFailedTests >= bail;
|
93
|
+
if (earlyTeardown) {
|
94
|
+
await unsafe_conductEarlyTeardown();
|
95
|
+
}
|
96
|
+
|
97
|
+
const aggregatedResult = await this._lastRunComplete.promise;
|
98
|
+
const lostTests = aggregatedResult.numTotalTestSuites - aggregatedResult.testResults.length;
|
99
|
+
|
100
|
+
// @ts-expect-error TS2554
|
101
|
+
super.onRunComplete(testContexts, aggregatedResult);
|
102
|
+
|
103
|
+
if (earlyTeardown && lostTests > 0 && config.testRunner.retries > 0) {
|
104
|
+
console.warn(
|
105
|
+
'Jest aborted the test execution before all scheduled test files have been reported.\n' +
|
106
|
+
'This brings us to a dilemma: retry the whole test run, or retry only known failed test files.\n' +
|
107
|
+
'Both options are bad in their own way, this is why we have decided to not support this edge case.\n' +
|
108
|
+
'If you want to retry the whole test run, please disable Jest\'s --bail option.'
|
109
|
+
);
|
110
|
+
}
|
111
|
+
|
112
|
+
await reportTestResults(aggregatedResult.testResults.map(r => ({
|
17
113
|
success: !r.failureMessage,
|
18
114
|
testFilePath: r.testFilePath,
|
19
115
|
testExecError: r.testExecError,
|
20
|
-
isPermanentFailure: this._isPermanentFailure(r),
|
116
|
+
isPermanentFailure: lostTests > 0 || this._isPermanentFailure(r),
|
21
117
|
})));
|
118
|
+
|
119
|
+
if (this._summaryReporter) {
|
120
|
+
this._summaryReporter.onRunComplete(testContexts, aggregatedResult);
|
121
|
+
}
|
122
|
+
|
123
|
+
if (earlyTeardown) {
|
124
|
+
await cleanup();
|
125
|
+
}
|
126
|
+
}
|
127
|
+
|
128
|
+
/**
|
129
|
+
* @returns {import('@jest/reporters').SummaryReporter | null}
|
130
|
+
* @private
|
131
|
+
*/
|
132
|
+
_initSummaryReporter() {
|
133
|
+
/** @type {(config: import('@jest/types').Config.ReporterConfig) => boolean} */
|
134
|
+
const isSummaryReporter = (config) => config[0] === 'summary';
|
135
|
+
if (this._globalConfig.reporters.some(isSummaryReporter)) {
|
136
|
+
return null;
|
137
|
+
}
|
138
|
+
|
139
|
+
return new SummaryReporter(this._globalConfig);
|
22
140
|
}
|
23
141
|
|
24
142
|
/**
|
@@ -70,7 +70,12 @@ class DetoxCircusEnvironment extends NodeEnvironment {
|
|
70
70
|
await this.initDetox();
|
71
71
|
}
|
72
72
|
|
73
|
+
// @ts-ignore
|
73
74
|
async handleTestEvent(event, state) {
|
75
|
+
if (detox.session.unsafe_earlyTeardown) {
|
76
|
+
throw new Error('Detox halted test execution due to an early teardown request');
|
77
|
+
}
|
78
|
+
|
74
79
|
this._timer.schedule(state.testTimeout != null ? state.testTimeout : this.setupTimeout);
|
75
80
|
|
76
81
|
if (SYNC_CIRCUS_EVENTS.has(event.name)) {
|
@@ -455,6 +455,8 @@ class AppleSimUtils {
|
|
455
455
|
overrides.push(`--cellularMode "${flags.cellularMode}"`);
|
456
456
|
if (flags.cellularBars)
|
457
457
|
overrides.push(`--cellularBars "${flags.cellularBars}"`);
|
458
|
+
if (flags.operatorName)
|
459
|
+
overrides.push(`--operatorName "${flags.operatorName}"`);
|
458
460
|
if (flags.batteryState)
|
459
461
|
overrides.push(`--batteryState "${flags.batteryState}"`);
|
460
462
|
if (flags.batteryLevel)
|
package/src/ipc/IPCClient.js
CHANGED
@@ -70,6 +70,11 @@ class IPCClient {
|
|
70
70
|
this._sessionState.patch(sessionState);
|
71
71
|
}
|
72
72
|
|
73
|
+
async conductEarlyTeardown() {
|
74
|
+
const sessionState = await this._emit('conductEarlyTeardown', {});
|
75
|
+
this._sessionState.patch(sessionState);
|
76
|
+
}
|
77
|
+
|
73
78
|
async _connectToServer() {
|
74
79
|
const serverId = this.serverId;
|
75
80
|
|
package/src/ipc/IPCServer.js
CHANGED
@@ -38,6 +38,7 @@ class IPCServer {
|
|
38
38
|
await new Promise((resolve) => {
|
39
39
|
// TODO: handle reject
|
40
40
|
this._ipc.serve(() => resolve());
|
41
|
+
this._ipc.server.on('conductEarlyTeardown', this.onConductEarlyTeardown.bind(this));
|
41
42
|
this._ipc.server.on('registerContext', this.onRegisterContext.bind(this));
|
42
43
|
this._ipc.server.on('registerWorker', this.onRegisterWorker.bind(this));
|
43
44
|
this._ipc.server.on('reportTestResults', this.onReportTestResults.bind(this));
|
@@ -83,6 +84,18 @@ class IPCServer {
|
|
83
84
|
}
|
84
85
|
}
|
85
86
|
|
87
|
+
onConductEarlyTeardown(_data = null, socket = null) {
|
88
|
+
// Note that we don't save `unsafe_earlyTeardown` in the primary session state
|
89
|
+
// because it's transient and needed only to make the workers quit early.
|
90
|
+
const newState = { unsafe_earlyTeardown: true };
|
91
|
+
|
92
|
+
if (socket) {
|
93
|
+
this._ipc.server.emit(socket, 'conductEarlyTeardownDone', newState);
|
94
|
+
}
|
95
|
+
|
96
|
+
this._ipc.server.broadcast('sessionStateUpdate', newState);
|
97
|
+
}
|
98
|
+
|
86
99
|
onReportTestResults({ testResults }, socket = null) {
|
87
100
|
const merged = uniqBy([
|
88
101
|
...testResults.map(r => serializeObjectWithError(r, 'testExecError')),
|
package/src/ipc/SessionState.js
CHANGED
@@ -24,6 +24,7 @@ class DetoxInternalsFacade {
|
|
24
24
|
this.resolveConfig = context[symbols.resolveConfig];
|
25
25
|
this.session = context[symbols.session];
|
26
26
|
this.tracing = context[symbols.tracing];
|
27
|
+
this.unsafe_conductEarlyTeardown = context[symbols.conductEarlyTeardown];
|
27
28
|
this.worker = funpermaproxy(() => context[symbols.worker]);
|
28
29
|
}
|
29
30
|
}
|
@@ -51,6 +51,12 @@ class DetoxPrimaryContext extends DetoxContext {
|
|
51
51
|
}
|
52
52
|
}
|
53
53
|
|
54
|
+
[symbols.conductEarlyTeardown] = async () => {
|
55
|
+
if (this[_ipcServer]) {
|
56
|
+
await this[_ipcServer].onConductEarlyTeardown();
|
57
|
+
}
|
58
|
+
};
|
59
|
+
|
54
60
|
async [symbols.resolveConfig](opts = {}) {
|
55
61
|
const session = this[$sessionState];
|
56
62
|
if (!session.detoxConfig) {
|
@@ -33,6 +33,14 @@ class DetoxSecondaryContext extends DetoxContext {
|
|
33
33
|
}
|
34
34
|
}
|
35
35
|
|
36
|
+
[symbols.conductEarlyTeardown] = async () => {
|
37
|
+
if (this[_ipcClient]) {
|
38
|
+
await this[_ipcClient].conductEarlyTeardown();
|
39
|
+
} else {
|
40
|
+
throw new DetoxInternalError('Detected an attempt to report early teardown using a non-initialized context.');
|
41
|
+
}
|
42
|
+
};
|
43
|
+
|
36
44
|
async [symbols.resolveConfig]() {
|
37
45
|
return this[symbols.config];
|
38
46
|
}
|
package/src/realms/symbols.js
CHANGED
@@ -12,6 +12,7 @@
|
|
12
12
|
* readonly onTestDone: unique symbol;
|
13
13
|
* readonly onTestFnFailure: unique symbol;
|
14
14
|
* readonly onTestStart: unique symbol;
|
15
|
+
* readonly conductEarlyTeardown: unique symbol;
|
15
16
|
* readonly reportTestResults: unique symbol;
|
16
17
|
* readonly resolveConfig: unique symbol;
|
17
18
|
* readonly session: unique symbol;
|
@@ -32,6 +33,7 @@ module.exports = {
|
|
32
33
|
|
33
34
|
//#region IPC
|
34
35
|
reportTestResults: Symbol('reportTestResults'),
|
36
|
+
conductEarlyTeardown: Symbol('conductEarlyTeardown'),
|
35
37
|
//#endregion
|
36
38
|
|
37
39
|
//#region Main
|
package/src/utils/errorUtils.js
CHANGED
@@ -1 +0,0 @@
|
|
1
|
-
fd803ad3b1d79693779077e2d5a030be
|
@@ -1 +0,0 @@
|
|
1
|
-
6e783294674107a7a02ffce8f5fc9bf5b5fa56de
|
@@ -1 +0,0 @@
|
|
1
|
-
250dd66ec2b951c59dd18d382ff84a0e05e9210543d66965d1c3704a36a5f16f
|
@@ -1 +0,0 @@
|
|
1
|
-
b6b8f084acbebaa8057529fe74ce10a2a700ef882f863aecf01a6e263f76164deb3ace7c5aa49164f3345bc3c930d18ca37e704f8814194906f32641187aa0d3
|
@@ -1 +0,0 @@
|
|
1
|
-
47c93868c2f09b970c68a3c21de6c2e8
|
@@ -1 +0,0 @@
|
|
1
|
-
6513d86c59c32e3b5a0d41e86f55e01c15dc0b8a
|
@@ -1 +0,0 @@
|
|
1
|
-
dbf7d435856960f5a0440f74248d677c6b7bcec0d9100f1e0f941401bd05f554
|
@@ -1 +0,0 @@
|
|
1
|
-
175323a595f1be240650f3d5109f0c7c099e93bdf1e9799b25f6ade82339aa42764dedbedefbfe6a9803cab1c0885f97dcd25ca77dd8840c9d5330bbbb66a9be
|
Binary file
|
@@ -1 +0,0 @@
|
|
1
|
-
c90cc85230997f3663da1741d1eabc0e
|
@@ -1 +0,0 @@
|
|
1
|
-
0e17ccf18dbb2e0295e72b77cae67275591d956a
|
@@ -1 +0,0 @@
|
|
1
|
-
00528b5d136df63bc93f55c2f890a1ad69179f341663310b520227f6b7aad63b
|
@@ -1 +0,0 @@
|
|
1
|
-
37984e2491685ede0325d74f460ad2a13dc55bd906124e0932fa09e29e2394a91cbbf691aa854848503113f04dfe148a483e616c736918f6e0077af6aa311a31
|
@@ -1 +0,0 @@
|
|
1
|
-
f936530422c3b067b14acf6882eb15c8
|
@@ -1 +0,0 @@
|
|
1
|
-
2528825c4917ba8994b81030daef2f0a7a908227
|
@@ -1 +0,0 @@
|
|
1
|
-
a0a195aa8f7511f6ee3b1bacc22f29d444e3d3eaacb96bf902c3e06df9afef5d
|
@@ -1 +0,0 @@
|
|
1
|
-
9702d3696a7170e3ac6cc0cdd15490cd1cd954903b602453a4ac53d336feda62822aef2796c83fd33552639f576a0234cb0052a76bd7ed2b2bc67a87df08544a
|