detox 20.12.0-smoke.0 → 20.12.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. package/Detox-android/com/wix/detox/{20.12.0-smoke.0/detox-20.12.0-smoke.0-javadoc.jar → 20.12.1/detox-20.12.1-javadoc.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1-javadoc.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1-javadoc.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1-javadoc.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1-javadoc.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.12.0-smoke.0/detox-20.12.0-smoke.0-sources.jar → 20.12.1/detox-20.12.1-sources.jar} +0 -0
  7. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1-sources.jar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1-sources.jar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1-sources.jar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1-sources.jar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1.aar +0 -0
  12. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1.aar.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1.aar.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1.aar.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1.aar.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/{20.12.0-smoke.0/detox-20.12.0-smoke.0.pom → 20.12.1/detox-20.12.1.pom} +1 -1
  17. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1.pom.md5 +1 -0
  18. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1.pom.sha1 +1 -0
  19. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1.pom.sha256 +1 -0
  20. package/Detox-android/com/wix/detox/20.12.1/detox-20.12.1.pom.sha512 +1 -0
  21. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  22. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  23. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  24. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  25. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  26. package/Detox-ios-src.tbz +0 -0
  27. package/Detox-ios.tbz +0 -0
  28. package/android/detox/build.gradle +1 -1
  29. package/android/detox/src/full/java/com/wix/detox/espresso/DetoxAssertion.java +44 -25
  30. package/android/detox/src/full/java/com/wix/detox/espresso/EspressoDetox.java +6 -7
  31. package/android/detox/src/full/java/com/wix/detox/espresso/action/GetAttributesAction.kt +4 -4
  32. package/android/detox/src/full/java/com/wix/detox/espresso/performer/MultipleViewsActionPerformer.kt +43 -0
  33. package/android/detox/src/full/java/com/wix/detox/espresso/performer/SingleViewActionPerformer.kt +19 -0
  34. package/android/detox/src/full/java/com/wix/detox/espresso/performer/ViewActionPerformer.kt +24 -0
  35. package/android/detox/src/full/java/com/wix/invoke/types/Invocation.java +5 -4
  36. package/android/detox/src/main/java/com/wix/detox/espresso/MultipleViewsAction.kt +4 -0
  37. package/android/detox/src/main/java/com/wix/detox/espresso/UiControllerSpy.kt +0 -1
  38. package/android/detox/src/main/java/com/wix/detox/espresso/ViewActionWithResult.kt +2 -1
  39. package/android/detox/src/testFull/java/com/wix/detox/espresso/action/GetAttributesActionTest.kt +6 -5
  40. package/android/detox/src/testFull/java/com/wix/detox/espresso/performer/ViewActionPerformerSpec.kt +37 -0
  41. package/index.d.ts +47 -3
  42. package/local-cli/reset-lock-file.js +9 -5
  43. package/package.json +6 -6
  44. package/src/DetoxWorker.js +9 -5
  45. package/src/android/core/NativeElement.js +26 -29
  46. package/src/android/espressoapi/DetoxAssertion.js +16 -14
  47. package/src/android/espressoapi/EspressoDetox.js +9 -2
  48. package/src/android/interactions/native.js +2 -3
  49. package/src/artifacts/providers/index.js +3 -3
  50. package/src/artifacts/screenshot/SimulatorScreenshotPlugin.js +17 -0
  51. package/src/devices/DeviceRegistry.js +176 -0
  52. package/src/devices/allocation/DeviceAllocator.js +15 -50
  53. package/src/devices/allocation/drivers/AllocationDriverBase.js +4 -10
  54. package/src/devices/allocation/drivers/android/attached/AttachedAndroidAllocDriver.js +6 -7
  55. package/src/devices/allocation/drivers/android/attached/AttachedAndroidLauncher.js +13 -0
  56. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocDriver.js +26 -108
  57. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocationHelper.js +72 -0
  58. package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +43 -33
  59. package/src/devices/allocation/drivers/android/emulator/FreeEmulatorFinder.js +1 -1
  60. package/src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js +3 -3
  61. package/src/devices/allocation/drivers/android/genycloud/GenyAllocDriver.js +27 -87
  62. package/src/devices/allocation/drivers/android/genycloud/GenyDeviceRegistryFactory.js +16 -0
  63. package/src/devices/allocation/drivers/android/genycloud/GenyInstanceAllocationHelper.js +65 -0
  64. package/src/devices/allocation/drivers/android/genycloud/GenyInstanceLauncher.js +28 -39
  65. package/src/devices/allocation/drivers/ios/SimulatorAllocDriver.js +40 -70
  66. package/src/devices/allocation/drivers/ios/SimulatorLauncher.js +7 -11
  67. package/src/devices/allocation/factories/android.js +35 -29
  68. package/src/devices/allocation/factories/ios.js +5 -7
  69. package/src/devices/common/drivers/DeviceAllocationHelper.js +20 -0
  70. package/src/devices/common/drivers/DeviceLauncher.js +19 -0
  71. package/src/devices/common/drivers/android/emulator/exec/EmulatorExec.js +5 -17
  72. package/src/devices/common/drivers/android/exec/ADB.js +0 -1
  73. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceLifecycleService.js +25 -0
  74. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceLookupService.js +38 -0
  75. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceNaming.js +14 -0
  76. package/src/devices/{allocation → common}/drivers/android/genycloud/services/GenyRecipesService.js +1 -1
  77. package/src/devices/{allocation → common}/drivers/android/genycloud/services/dto/GenyInstance.js +1 -6
  78. package/src/devices/{allocation/drivers/android → common/drivers/android/tools}/FreeDeviceFinder.js +10 -11
  79. package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +3 -1
  80. package/src/devices/cookies/AndroidDeviceCookie.js +0 -4
  81. package/src/devices/cookies/GenycloudEmulatorCookie.js +5 -3
  82. package/src/devices/cookies/IosSimulatorCookie.js +0 -4
  83. package/src/devices/lifecycle/GenyGlobalLifecycleHandler.js +71 -0
  84. package/src/devices/lifecycle/factories/GenyGlobalLifecycleHandlerFactory.js +18 -0
  85. package/src/devices/runtime/drivers/android/genycloud/GenyCloudDriver.js +2 -2
  86. package/src/devices/runtime/factories/android.js +1 -1
  87. package/src/devices/runtime/factories/ios.js +2 -3
  88. package/src/environmentFactory.js +11 -1
  89. package/src/ipc/IPCClient.js +1 -17
  90. package/src/ipc/IPCServer.js +1 -25
  91. package/src/realms/DetoxContext.js +0 -6
  92. package/src/realms/DetoxPrimaryContext.js +42 -42
  93. package/src/realms/DetoxSecondaryContext.js +0 -19
  94. package/src/realms/symbols.js +0 -4
  95. package/src/{devices/servicelocator → servicelocator}/android/emulatorServiceLocator.js +1 -1
  96. package/src/servicelocator/android/genycloudServiceLocator.js +21 -0
  97. package/src/servicelocator/android/index.js +25 -0
  98. package/src/servicelocator/ios.js +7 -0
  99. package/src/utils/environment.js +15 -8
  100. package/src/utils/errorUtils.js +2 -2
  101. package/src/{devices/validation → validation}/android/GenycloudEnvValidator.js +2 -2
  102. package/src/{devices/validation → validation}/factories/index.js +1 -1
  103. package/src/{devices/validation → validation}/ios/IosSimulatorEnvValidator.js +2 -2
  104. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-javadoc.jar.md5 +0 -1
  105. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-javadoc.jar.sha1 +0 -1
  106. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-javadoc.jar.sha256 +0 -1
  107. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-javadoc.jar.sha512 +0 -1
  108. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-sources.jar.md5 +0 -1
  109. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-sources.jar.sha1 +0 -1
  110. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-sources.jar.sha256 +0 -1
  111. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-sources.jar.sha512 +0 -1
  112. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.aar +0 -0
  113. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.aar.md5 +0 -1
  114. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.aar.sha1 +0 -1
  115. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.aar.sha256 +0 -1
  116. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.aar.sha512 +0 -1
  117. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.pom.md5 +0 -1
  118. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.pom.sha1 +0 -1
  119. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.pom.sha256 +0 -1
  120. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.pom.sha512 +0 -1
  121. package/src/devices/allocation/DeviceList.js +0 -44
  122. package/src/devices/allocation/DeviceRegistry.js +0 -186
  123. package/src/devices/allocation/drivers/android/emulator/FreePortFinder.js +0 -16
  124. package/src/devices/allocation/drivers/android/genycloud/GenyRegistry.js +0 -93
  125. package/src/devices/allocation/drivers/android/genycloud/services/GenyInstanceLifecycleService.js +0 -24
  126. package/src/devices/allocation/drivers/ios/SimulatorQuery.js +0 -24
  127. package/src/devices/servicelocator/android/genycloudServiceLocator.js +0 -17
  128. package/src/devices/servicelocator/android/index.js +0 -23
  129. package/src/utils/PIDService.js +0 -27
  130. /package/src/devices/{allocation → common}/drivers/android/genycloud/exec/GenyCloudExec.js +0 -0
  131. /package/src/devices/{allocation → common}/drivers/android/genycloud/services/GenyAuthService.js +0 -0
  132. /package/src/devices/{allocation → common}/drivers/android/genycloud/services/dto/GenyRecipe.js +0 -0
  133. /package/src/{devices/validation → validation}/EnvironmentValidatorBase.js +0 -0
@@ -0,0 +1 @@
1
+ 0780bd77755cae9d89bc326c195d8eb1
@@ -0,0 +1 @@
1
+ 9168cee63c5b35da49de50f34c9c41ad5fc0c449
@@ -0,0 +1 @@
1
+ d3b9a104400c779bb7a1e70546c33abd374cf8eeb55ac5b4098a6c54737d0411
@@ -0,0 +1 @@
1
+ ba86f8d9c3163eefc5d13776f4288708d96e00c83bea5527bbbd1a1c2027c79e6d44d19a8c85959bc48f3b7311c2969c96ea4d26569adb18f8f90fb56f7b558e
@@ -0,0 +1 @@
1
+ 70745a3a7e09a2682c6a8902a413bff1
@@ -0,0 +1 @@
1
+ 1da2776757d2a28dc4c3e73a7b469b4d92dee9c8
@@ -0,0 +1 @@
1
+ 931d28ebdf7b9bceb5ad5ec36cd7b3696f91e6955579f505c311c1b5334fb57a
@@ -0,0 +1 @@
1
+ 4750dd9cab79b2cab696c552101c755c609e6a4bfa5ab75d742004cbf4fe5bfdbc87b36096e1145559c5a5f65b6216181b6690efaa73016df660a4865d774782
@@ -0,0 +1 @@
1
+ c90cc85230997f3663da1741d1eabc0e
@@ -0,0 +1 @@
1
+ 0e17ccf18dbb2e0295e72b77cae67275591d956a
@@ -0,0 +1 @@
1
+ 00528b5d136df63bc93f55c2f890a1ad69179f341663310b520227f6b7aad63b
@@ -0,0 +1 @@
1
+ 37984e2491685ede0325d74f460ad2a13dc55bd906124e0932fa09e29e2394a91cbbf691aa854848503113f04dfe148a483e616c736918f6e0077af6aa311a31
@@ -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.0-smoke.0</version>
6
+ <version>20.12.1</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>
@@ -0,0 +1 @@
1
+ 1ebd5db42295ac98e2151fc5c24b8903
@@ -0,0 +1 @@
1
+ e5614e7546e21d6757c4b338efc93e6b6a0a4bf6
@@ -0,0 +1 @@
1
+ b38cc093a239ee307a854533ad801c3ee7548c01519f7964da7d0285486a09a8
@@ -0,0 +1 @@
1
+ 5f94777c0cbddf9a24e2f661fc598fec79e71d555107020bcbb366a728307e990ae7205b210346562faa08fc00774ff3a9336e8fd185c80bd1fa9ebb4d2fa8c5
@@ -3,11 +3,11 @@
3
3
  <groupId>com.wix</groupId>
4
4
  <artifactId>detox</artifactId>
5
5
  <versioning>
6
- <latest>20.12.0-smoke.0</latest>
7
- <release>20.12.0-smoke.0</release>
6
+ <latest>20.12.1</latest>
7
+ <release>20.12.1</release>
8
8
  <versions>
9
- <version>20.12.0-smoke.0</version>
9
+ <version>20.12.1</version>
10
10
  </versions>
11
- <lastUpdated>20230905081618</lastUpdated>
11
+ <lastUpdated>20230919081610</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- c0ebd655b45d26da7f4503b42682e6ac
1
+ 1e3fc98a2197d7ff387e7c2bba133329
@@ -1 +1 @@
1
- b28e7e113a3adf4f4ac956666bef4767712332c5
1
+ 0bd2298f41bb8578b4eb3bf4b744dbbec757a1ac
@@ -1 +1 @@
1
- 428cdbf9560b42fa11a47e4ad09d61f067e46c0222b046489e8cfdb914d43d3e
1
+ 01991e2c36e2b46d6ee16a7de9a7bb11fdb5bb1e2f134bcd7e06a6b5f2f74fa8
@@ -1 +1 @@
1
- c7042d22a9567df5b06587e91169041fb202a4881b61f76a2b8a3db7b31c571cd8a1b51e4a44fe54ac80499bc249e0b195f67854408cfa47f2388c2c2d0f76ca
1
+ 9c4f073180d321ea3a79f98c16155c2e55e0e2a53ea3052bda82a18a893d35af8e5a257b882f3dcbd723e0886ee3b874f92bdd2a102d06b80a8fb9090c480d2f
package/Detox-ios-src.tbz CHANGED
Binary file
package/Detox-ios.tbz CHANGED
Binary file
@@ -140,7 +140,7 @@ dependencies {
140
140
  // Unit-testing deps.
141
141
  dependencies {
142
142
  testImplementation "${_rnNativeArtifact}"
143
- testImplementation 'org.json:json:20140107'
143
+ testImplementation 'org.json:json:20230227'
144
144
 
145
145
  // https://github.com/spekframework/spek/issues/232#issuecomment-610732158
146
146
  testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.7.2'
@@ -24,42 +24,57 @@ import static org.hamcrest.Matchers.not;
24
24
 
25
25
  public class DetoxAssertion {
26
26
 
27
+ private static final double NANOSECONDS_IN_A_SECOND = 1_000_000_000.0;
28
+
27
29
  private DetoxAssertion() {
28
- // static class
30
+ // This is a utility class and shouldn't be instantiated.
29
31
  }
30
32
 
31
- public static ViewInteraction assertMatcher(ViewInteraction i, Matcher<View> m) {
32
- return i.check(matches(m));
33
+ /**
34
+ * Asserts the given matcher for the provided view interaction.
35
+ */
36
+ public static ViewInteraction assertMatcher(ViewInteraction viewInteraction, Matcher<View> viewMatcher) {
37
+ return viewInteraction.check(matches(viewMatcher));
33
38
  }
34
39
 
35
- public static ViewInteraction assertNotVisible(ViewInteraction i) {
36
- ViewInteraction ret;
40
+ /**
41
+ * Asserts that the given view interaction is not visible.
42
+ */
43
+ public static ViewInteraction assertNotVisible(ViewInteraction viewInteraction) {
44
+ ViewInteraction result;
37
45
  try {
38
- ret = i.check(doesNotExist());
39
- return ret;
46
+ result = viewInteraction.check(doesNotExist());
47
+ return result;
40
48
  } catch (AssertionFailedError e) {
41
- ret = i.check(matches(not(isDisplayed())));
42
- return ret;
49
+ result = viewInteraction.check(matches(not(isDisplayed())));
50
+ return result;
43
51
  }
44
52
  }
45
53
 
46
- public static ViewInteraction assertNotExists(ViewInteraction i) {
47
- return i.check(doesNotExist());
54
+ /**
55
+ * Asserts that the given view interaction does not exist.
56
+ */
57
+ public static ViewInteraction assertNotExists(ViewInteraction viewInteraction) {
58
+ return viewInteraction.check(doesNotExist());
48
59
  }
49
60
 
50
- public static void waitForAssertMatcher(final ViewInteraction i, final Matcher<View> m, double timeoutSeconds) {
51
- final long originTime = System.nanoTime();
61
+ /**
62
+ * Waits until the provided matcher matches the view interaction or a timeout occurs.
63
+ */
64
+ public static void waitForAssertMatcher(final ViewInteraction viewInteraction, final Matcher<View> viewMatcher, double timeoutSeconds) {
65
+ final long startTime = System.nanoTime();
52
66
 
53
67
  while (true) {
54
68
  long currentTime = System.nanoTime();
55
- long elapsed = currentTime - originTime;
56
- double seconds = (double) elapsed / 1000000000.0;
57
- if (seconds >= timeoutSeconds) {
58
- throw new DetoxRuntimeException("" + timeoutSeconds + "sec timeout expired without matching of given matcher: " + m);
69
+ long elapsedTime = currentTime - startTime;
70
+ double elapsedSeconds = (double) elapsedTime / NANOSECONDS_IN_A_SECOND;
71
+ if (elapsedSeconds >= timeoutSeconds) {
72
+ throw new DetoxRuntimeException(
73
+ "" + timeoutSeconds + "sec timeout expired without matching of given matcher: " + viewMatcher);
59
74
  }
60
75
 
61
76
  try {
62
- i.check(matches(m));
77
+ viewInteraction.check(matches(viewMatcher));
63
78
  break;
64
79
  } catch (AssertionFailedError err) {
65
80
  UiAutomatorHelper.espressoSync(20);
@@ -67,21 +82,25 @@ public class DetoxAssertion {
67
82
  }
68
83
  }
69
84
 
85
+ /**
86
+ * Continually asserts the provided matcher until a search action returns a matching view or a
87
+ * `StaleActionException` error is thrown.
88
+ */
70
89
  public static void waitForAssertMatcherWithSearchAction(
71
- final ViewInteraction i,
72
- final Matcher<View> vm,
73
- final ViewAction searchAction,
74
- final Matcher<View> searchMatcher) {
75
-
90
+ final ViewInteraction viewInteraction,
91
+ final Matcher<View> viewMatcher,
92
+ final ViewAction searchAction,
93
+ final Matcher<View> searchMatcher
94
+ ) {
76
95
  while (true) {
77
96
  try {
78
- assertMatcher(i, vm);
97
+ assertMatcher(viewInteraction, viewMatcher);
79
98
  break;
80
99
  } catch (AssertionFailedError err) {
81
100
  try {
82
101
  onView(searchMatcher).perform(searchAction);
83
102
  } catch (StaleActionException exStaleAction) {
84
- assertMatcher(i, vm);
103
+ assertMatcher(viewInteraction, viewMatcher);
85
104
  break;
86
105
  }
87
106
  }
@@ -1,5 +1,7 @@
1
1
  package com.wix.detox.espresso;
2
2
 
3
+ import com.wix.detox.espresso.performer.ViewActionPerformer;
4
+
3
5
  import android.app.Activity;
4
6
  import android.content.Context;
5
7
  import android.content.ContextWrapper;
@@ -20,6 +22,7 @@ import java.util.ArrayList;
20
22
  import androidx.test.espresso.UiController;
21
23
  import androidx.test.espresso.ViewAction;
22
24
  import androidx.test.espresso.ViewInteraction;
25
+ import androidx.test.espresso.NoMatchingViewException;
23
26
  import androidx.test.platform.app.InstrumentationRegistry;
24
27
 
25
28
  import static androidx.test.espresso.Espresso.onView;
@@ -31,13 +34,9 @@ import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
31
34
  public class EspressoDetox {
32
35
  private static final String LOG_TAG = "detox";
33
36
 
34
- public static Object perform(ViewInteraction interaction, ViewAction action) {
35
- interaction.perform(action);
36
-
37
- if (action instanceof ViewActionWithResult) {
38
- return ((ViewActionWithResult) action).getResult();
39
- }
40
- return null;
37
+ public static Object perform(Matcher<View> matcher, ViewAction action) {
38
+ ViewActionPerformer performer = ViewActionPerformer.forAction(action);
39
+ return performer.performOn(matcher);
41
40
  }
42
41
 
43
42
  public static Activity getActivity(Context context) {
@@ -9,6 +9,7 @@ import android.widget.TextView
9
9
  import androidx.test.espresso.UiController
10
10
  import com.google.android.material.slider.Slider
11
11
  import com.wix.detox.espresso.ViewActionWithResult
12
+ import com.wix.detox.espresso.MultipleViewsAction
12
13
  import com.wix.detox.espresso.common.SliderHelper
13
14
  import com.wix.detox.reactnative.ui.getAccessibilityLabel
14
15
  import org.hamcrest.Matcher
@@ -17,26 +18,25 @@ import org.hamcrest.Matchers.allOf
17
18
  import org.hamcrest.Matchers.notNullValue
18
19
  import org.json.JSONObject
19
20
 
20
- class GetAttributesAction() : ViewActionWithResult<String?> {
21
+ class GetAttributesAction() : ViewActionWithResult<JSONObject?>, MultipleViewsAction {
21
22
  private val commonAttributes = CommonAttributes()
22
23
  private val textViewAttributes = TextViewAttributes()
23
24
  private val checkBoxAttributes = CheckBoxAttributes()
24
25
  private val progressBarAttributes = ProgressBarAttributes()
25
26
  private val sliderAttributes = SliderAttributes()
26
- private var result: String = ""
27
+ private var result: JSONObject? = null
27
28
 
28
29
  override fun perform(uiController: UiController?, view: View?) {
29
30
  view!!
30
31
 
31
32
  val json = JSONObject()
32
-
33
33
  commonAttributes.get(json, view)
34
34
  textViewAttributes.get(json, view)
35
35
  checkBoxAttributes.get(json, view)
36
36
  progressBarAttributes.get(json, view)
37
37
  sliderAttributes.get(json, view)
38
38
 
39
- result = json.toString()
39
+ result = json
40
40
  }
41
41
 
42
42
  override fun getResult() = result
@@ -0,0 +1,43 @@
1
+ package com.wix.detox.espresso.performer
2
+
3
+ import com.wix.detox.espresso.DetoxMatcher
4
+ import com.wix.detox.espresso.ViewActionWithResult
5
+
6
+ import android.view.View
7
+ import androidx.test.espresso.Espresso.onView
8
+ import androidx.test.espresso.NoMatchingViewException
9
+ import androidx.test.espresso.ViewAction
10
+ import org.hamcrest.Matcher
11
+
12
+ class MultipleViewsActionPerformer(
13
+ private val action: ViewAction
14
+ ) : ViewActionPerformer {
15
+ override fun performOn(matcher: Matcher<View>): Any? {
16
+ val results = mutableListOf<Any?>()
17
+ var index = 0
18
+
19
+ while (true) {
20
+ val indexedMatcher = DetoxMatcher.matcherForAtIndex(index, matcher)
21
+
22
+ try {
23
+ onView(indexedMatcher).perform(action)
24
+
25
+ (action as? ViewActionWithResult<*>)?.getResult()?.let { results.add(it) }
26
+
27
+ index++
28
+ } catch (e: NoMatchingViewException) {
29
+ if (index == 0) {
30
+ throw e
31
+ }
32
+
33
+ break
34
+ }
35
+ }
36
+
37
+ return when {
38
+ results.isEmpty() -> null
39
+ results.size == 1 -> results.first()
40
+ else -> mapOf("elements" to results)
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,19 @@
1
+ package com.wix.detox.espresso.performer
2
+
3
+ import com.wix.detox.espresso.ViewActionWithResult
4
+
5
+ import android.view.View
6
+ import androidx.test.espresso.Espresso.onView
7
+ import androidx.test.espresso.NoMatchingViewException
8
+ import androidx.test.espresso.ViewAction
9
+ import org.hamcrest.Matcher
10
+
11
+ class SingleViewActionPerformer(
12
+ private val action: ViewAction
13
+ ) : ViewActionPerformer {
14
+ override fun performOn(matcher: Matcher<View>): Any? {
15
+ onView(matcher).perform(action)
16
+
17
+ return (action as? ViewActionWithResult<*>)?.getResult()
18
+ }
19
+ }
@@ -0,0 +1,24 @@
1
+ package com.wix.detox.espresso.performer
2
+
3
+ import com.wix.detox.espresso.MultipleViewsAction
4
+
5
+ import android.view.View
6
+ import androidx.test.espresso.Espresso.onView
7
+ import androidx.test.espresso.NoMatchingViewException
8
+ import androidx.test.espresso.ViewAction
9
+ import org.hamcrest.Matcher
10
+
11
+ interface ViewActionPerformer {
12
+ fun performOn(matcher: Matcher<View>): Any?
13
+
14
+ companion object {
15
+ @JvmStatic
16
+ fun forAction(action: ViewAction): ViewActionPerformer {
17
+ return if (action is MultipleViewsAction) {
18
+ MultipleViewsActionPerformer(action)
19
+ } else {
20
+ SingleViewActionPerformer(action)
21
+ }
22
+ }
23
+ }
24
+ }
@@ -92,9 +92,9 @@ public class Invocation {
92
92
  } else if (type.equals("boolean")) {
93
93
  argument = jsonArgument.optBoolean("value");
94
94
  } else if (type.equals("Invocation")) {
95
- argument = new Invocation(jsonArgument.optJSONObject("value"));
95
+ argument = new Invocation(jsonArgument.optJSONObject("value"));
96
96
  } else {
97
- throw new RuntimeException("Unhandled arg type" + type);
97
+ throw new RuntimeException("Unhandled arg type " + type);
98
98
  }
99
99
  }
100
100
  }
@@ -105,6 +105,8 @@ public class Invocation {
105
105
  }
106
106
 
107
107
  public void setArgs(Object[] args) {
108
+ JsonParser parser = new JsonParser();
109
+
108
110
  for (int i = 0; i < args.length; i++) {
109
111
  Object argument = args[i];
110
112
  if (argument instanceof HashMap && !((HashMap) argument).isEmpty()) {
@@ -125,10 +127,9 @@ public class Invocation {
125
127
  } else if (type.equals("boolean")) {
126
128
  argument = ((Boolean) value).booleanValue();
127
129
  } else if (type.equals("Invocation")) {
128
- JsonParser parser = new JsonParser();
129
130
  argument = parser.parse((String)value);
130
131
  } else {
131
- throw new RuntimeException("Unhandled arg type" + type);
132
+ throw new RuntimeException("Unhandled arg type " + type);
132
133
  }
133
134
 
134
135
  args[i] = argument;
@@ -0,0 +1,4 @@
1
+ package com.wix.detox.espresso
2
+
3
+ // Marker interface for actions that should be applied to all matching elements without ambiguity.
4
+ interface MultipleViewsAction
@@ -1,4 +1,3 @@
1
-
2
1
  package com.wix.detox.espresso
3
2
 
4
3
  import androidx.test.espresso.UiController
@@ -2,6 +2,7 @@ package com.wix.detox.espresso
2
2
 
3
3
  import androidx.test.espresso.ViewAction
4
4
 
5
- interface ViewActionWithResult<R: Any?>: ViewAction {
5
+ // Interface for actions that return a result.
6
+ interface ViewActionWithResult<R: Any?> : ViewAction {
6
7
  fun getResult(): R
7
8
  }
@@ -37,7 +37,7 @@ class GetAttributesActionTest {
37
37
 
38
38
  private fun perform(v: View = view): JSONObject {
39
39
  uut.perform(null, v)
40
- return JSONObject(uut.getResult())
40
+ return uut.getResult()!!
41
41
  }
42
42
 
43
43
  @Test
@@ -135,10 +135,10 @@ class GetAttributesActionTest {
135
135
  }
136
136
 
137
137
  val resultJson = perform()
138
- assertThat(resultJson.opt("alpha")).isEqualTo(0.42)
138
+ assertThat(resultJson.opt("alpha")).isEqualTo(0.42f)
139
139
  assertThat(resultJson.opt("width")).isEqualTo(123)
140
140
  assertThat(resultJson.opt("height")).isEqualTo(456)
141
- assertThat(resultJson.opt("elevation")).isEqualTo(0.314)
141
+ assertThat(resultJson.opt("elevation")).isEqualTo(0.314f)
142
142
  }
143
143
 
144
144
  @Test
@@ -208,7 +208,8 @@ class GetAttributesActionTest {
208
208
  }
209
209
 
210
210
  val resultJson = perform(slider)
211
- assertThat(resultJson.opt("value")).isEqualTo(0.42)
211
+ android.util.Log.i("TESTS", "should return material-Slider state through value attribute: "+ resultJson)
212
+ assertThat(resultJson.opt("value")).isEqualTo(0.42f)
212
213
  }
213
214
 
214
215
  @Test
@@ -221,7 +222,7 @@ class GetAttributesActionTest {
221
222
 
222
223
  val resultJson = perform(textView)
223
224
  assertThat(resultJson.opt("text")).isEqualTo("mock-text")
224
- assertThat(resultJson.opt("textSize")).isEqualTo(24)
225
+ assertThat(resultJson.opt("textSize")).isEqualTo(24f)
225
226
  assertThat(resultJson.opt("length")).isEqualTo(111)
226
227
  }
227
228
 
@@ -0,0 +1,37 @@
1
+ package com.wix.detox.espresso.performer
2
+
3
+ import org.spekframework.spek2.Spek
4
+ import org.spekframework.spek2.style.specification.describe
5
+ import androidx.test.espresso.ViewAction
6
+ import com.wix.detox.espresso.MultipleViewsAction
7
+ import org.hamcrest.Matcher
8
+ import org.mockito.Mockito.*
9
+ import org.mockito.kotlin.mock
10
+
11
+ object ViewActionPerformerSpec : Spek({
12
+
13
+ describe("ViewActionPerformer") {
14
+ context("forAction") {
15
+ context("given a regular ViewAction") {
16
+ val action = mock(ViewAction::class.java)
17
+
18
+ it("should return a SingleViewActionPerformer") {
19
+ val performer = ViewActionPerformer.forAction(action)
20
+ assert(performer is SingleViewActionPerformer)
21
+ }
22
+ }
23
+
24
+ context("given a MultipleViewsAction") {
25
+ val multipleViewsAction: ViewAction = mock(
26
+ ViewAction::class.java,
27
+ withSettings().extraInterfaces(MultipleViewsAction::class.java)
28
+ )
29
+
30
+ it("should return a MultipleViewsActionPerformer") {
31
+ val performer = ViewActionPerformer.forAction(multipleViewsAction)
32
+ assert(performer is MultipleViewsActionPerformer)
33
+ }
34
+ }
35
+ }
36
+ }
37
+ })
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
  *
@@ -1430,8 +1473,9 @@ declare global {
1430
1473
  takeScreenshot(name: string): Promise<string>;
1431
1474
 
1432
1475
  /**
1433
- * Gets the native (OS-dependent) attributes of the element.
1434
- * For more information, see {@link https://wix.github.io/Detox/docs/api/actions-on-element/#getattributes}
1476
+ * Retrieves the OS-dependent attributes of an element.
1477
+ * If there are multiple matches, it returns an array of attributes for all matched elements.
1478
+ * For detailed information, refer to {@link https://wix.github.io/Detox/docs/api/actions-on-element/#getattributes}
1435
1479
  *
1436
1480
  * @example
1437
1481
  * test('Get the attributes for my text element', async () => {
@@ -1445,7 +1489,7 @@ declare global {
1445
1489
  * jestExpect(attributes.width).toHaveValue(100);
1446
1490
  * })
1447
1491
  */
1448
- getAttributes(): Promise<IosElementAttributes | AndroidElementAttributes | { elements: IosElementAttributes[]; }>;
1492
+ getAttributes(): Promise<IosElementAttributes | AndroidElementAttributes | { elements: IosElementAttributes[] } | { elements: AndroidElementAttributes[] } >;
1449
1493
  }
1450
1494
 
1451
1495
  interface WebExpect<R = Promise<void>> {
@@ -1,12 +1,16 @@
1
1
  const { log } = require('../internals');
2
- const DeviceRegistry = require('../src/devices/allocation/DeviceRegistry');
2
+ const DeviceRegistry = require('../src/devices/DeviceRegistry');
3
+ const { getDetoxLibraryRootPath } = require('../src/utils/environment');
4
+
3
5
 
4
6
  module.exports.command = 'reset-lock-file';
5
- module.exports.desc = 'Resets all Detox lock files. Useful when you need to clean up leftover locks from a crashed Detox instance.';
7
+ module.exports.desc = 'Resets all Detox lock files. Useful when you need to run multiple `detox test` commands in parallel with --keepLockFile.';
6
8
 
7
9
  module.exports.handler = async function resetLockFile() {
8
- const registry = new DeviceRegistry();
9
- await registry.reset();
10
+ await Promise.all([
11
+ DeviceRegistry.forIOS().reset(),
12
+ DeviceRegistry.forAndroid().reset(),
13
+ ]);
10
14
 
11
- log.info(`Cleaned lock file at: ${registry.lockFilePath}`);
15
+ log.info(`Cleaned lock files from: ${getDetoxLibraryRootPath()}`);
12
16
  };