detox 21.0.0-breaking.new-global-lifecycle.0 → 21.0.1-rc.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (304) hide show
  1. package/.eslintrc.js +2 -7
  2. package/Detox-android/com/wix/detox/{21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0-javadoc.jar → 21.0.1-rc.0/detox-21.0.1-rc.0-javadoc.jar} +0 -0
  3. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0-javadoc.jar.md5 +1 -0
  4. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0-javadoc.jar.sha1 +1 -0
  5. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0-javadoc.jar.sha256 +1 -0
  6. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0-javadoc.jar.sha512 +1 -0
  7. package/Detox-android/com/wix/detox/{21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0-sources.jar → 21.0.1-rc.0/detox-21.0.1-rc.0-sources.jar} +0 -0
  8. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0-sources.jar.md5 +1 -0
  9. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0-sources.jar.sha1 +1 -0
  10. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0-sources.jar.sha256 +1 -0
  11. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0-sources.jar.sha512 +1 -0
  12. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0.aar +0 -0
  13. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0.aar.md5 +1 -0
  14. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0.aar.sha1 +1 -0
  15. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0.aar.sha256 +1 -0
  16. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0.aar.sha512 +1 -0
  17. package/Detox-android/com/wix/detox/{21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0.pom → 21.0.1-rc.0/detox-21.0.1-rc.0.pom} +22 -10
  18. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0.pom.md5 +1 -0
  19. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0.pom.sha1 +1 -0
  20. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0.pom.sha256 +1 -0
  21. package/Detox-android/com/wix/detox/21.0.1-rc.0/detox-21.0.1-rc.0.pom.sha512 +1 -0
  22. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  23. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  24. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  25. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  26. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  27. package/Detox-ios-framework.tbz +0 -0
  28. package/Detox-ios-src.tbz +0 -0
  29. package/Detox-ios-xcuitest.tbz +0 -0
  30. package/README.md +1 -1
  31. package/android/build.gradle +13 -8
  32. package/android/detox/build.gradle +24 -13
  33. package/android/detox/proguard-rules-app.pro +6 -0
  34. package/android/detox/proguard-rules.pro +3 -0
  35. package/android/detox/publish-pom.gradle +5 -1
  36. package/android/detox/publishing.gradle +35 -33
  37. package/android/detox/src/full/java/com/wix/detox/DetoxCrashHandler.kt +1 -1
  38. package/android/detox/src/full/java/com/wix/detox/LaunchArgs.java +9 -0
  39. package/android/detox/src/full/java/com/wix/detox/TestEngineFacade.kt +4 -4
  40. package/android/detox/src/full/java/com/wix/detox/adapters/server/QueryStatusActionHandler.kt +12 -80
  41. package/android/detox/src/full/java/com/wix/detox/adapters/server/WebSocketClient.java +3 -1
  42. package/android/detox/src/full/java/com/wix/detox/common/UIExtensions.kt +28 -0
  43. package/android/detox/src/full/java/com/wix/detox/espresso/DetoxAction.java +37 -3
  44. package/android/detox/src/full/java/com/wix/detox/espresso/DetoxMatcher.java +11 -1
  45. package/android/detox/src/full/java/com/wix/detox/espresso/UiAutomatorHelper.java +1 -1
  46. package/android/detox/src/full/java/com/wix/detox/espresso/action/AdjustSliderToPositionAction.kt +22 -0
  47. package/android/detox/src/{main → full}/java/com/wix/detox/espresso/action/GetAttributesAction.kt +17 -4
  48. package/android/detox/src/full/java/com/wix/detox/espresso/action/RNDetoxAccessibilityAction.kt +46 -0
  49. package/android/detox/src/full/java/com/wix/detox/espresso/common/SliderHelper.kt +75 -0
  50. package/android/detox/src/full/java/com/wix/detox/espresso/common/UiControllerImplReflected.kt +16 -0
  51. package/android/detox/src/full/java/com/wix/detox/espresso/idlingresources/DescriptiveIdlingResource.kt +8 -0
  52. package/android/detox/src/full/java/com/wix/detox/espresso/matcher/ViewMatchers.kt +24 -28
  53. package/android/detox/src/full/java/com/wix/detox/espresso/matcher/WithAccessibilityLabelMatcher.kt +23 -0
  54. package/android/detox/src/full/java/com/wix/detox/espresso/registry/BusyResourcesInquirer.kt +48 -0
  55. package/android/detox/src/full/java/com/wix/detox/inquiry/DetoxBusyResource.kt +92 -0
  56. package/android/detox/src/full/java/com/wix/detox/inquiry/DetoxBusyResourceDescription.kt +26 -0
  57. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeExtension.kt +15 -2
  58. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeIdlingResources.kt +43 -38
  59. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeLoadingMonitor.kt +54 -8
  60. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/AnimatedModuleIdlingResource.java +18 -7
  61. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResource.kt +3 -4
  62. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/BridgeIdlingResource.java +12 -6
  63. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxBaseIdlingResource.java +2 -0
  64. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResource.java +43 -34
  65. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategy.kt +7 -27
  66. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/IdleInterrogationStrategy.kt +1 -11
  67. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResource.kt +2 -6
  68. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/RN66Workaround.kt +13 -4
  69. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIManagerModuleReflected.kt +1 -1
  70. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIModuleIdlingResource.kt +4 -6
  71. package/android/detox/src/full/java/com/wix/detox/reactnative/ui/UIExtensions.kt +37 -0
  72. package/android/detox/src/full/java/com/wix/detox/reactnative/utils/RNUtils.kt +6 -0
  73. package/android/detox/src/main/java/com/wix/detox/common/DetoxErrors.java +4 -1
  74. package/android/detox/src/main/java/com/wix/detox/common/TextFileReader.kt +1 -1
  75. package/android/detox/src/main/java/com/wix/detox/espresso/UiControllerSpy.kt +2 -1
  76. package/android/detox/src/main/java/com/wix/detox/espresso/action/common/ReflectUtils.kt +10 -0
  77. package/android/detox/src/main/java/com/wix/detox/espresso/action/common/utils/UiControllerUtils.kt +1 -1
  78. package/android/detox/src/testFull/java/com/wix/detox/UTHelpers.kt +12 -0
  79. package/android/detox/src/testFull/java/com/wix/detox/adapters/server/QueryStatusActionHandlerSpec.kt +35 -94
  80. package/android/detox/src/testFull/java/com/wix/detox/common/UIExtensionsTest.kt +107 -0
  81. package/android/detox/src/testFull/java/com/wix/detox/espresso/action/DetoxMultiTapSpec.kt +4 -3
  82. package/android/detox/src/testFull/java/com/wix/detox/espresso/action/GetAttributesActionTest.kt +22 -9
  83. package/android/detox/src/testFull/java/com/wix/detox/espresso/common/SliderHelperTest.kt +39 -0
  84. package/android/detox/src/testFull/java/com/wix/detox/espresso/matcher/ViewAtIndexMatcherSpec.kt +1 -2
  85. package/android/detox/src/testFull/java/com/wix/detox/espresso/registry/{IRStatusInquirerTest.kt → BusyResourcesInquirerTest.kt} +46 -7
  86. package/android/detox/src/testFull/java/com/wix/detox/{reactnative/idlingresources/IdlingResourceDescriptionSpec.kt → inquiry/DetoxBusyResourceDescriptionSpec.kt} +6 -6
  87. package/android/detox/src/testFull/java/com/wix/detox/inquiry/DetoxBusyResourceSpec.kt +134 -0
  88. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResourceSpec.kt +4 -5
  89. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResourcesTest.kt +61 -0
  90. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategySpec.kt +3 -11
  91. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResourceSpec.kt +4 -6
  92. package/android/gradle/wrapper/gradle-wrapper.properties +2 -1
  93. package/android/gradlew +181 -107
  94. package/index.d.ts +239 -83
  95. package/index.js +12 -1
  96. package/internals.d.ts +219 -45
  97. package/internals.js +10 -3
  98. package/local-cli/build-framework-cache.js +1 -1
  99. package/local-cli/build-xcuitest-cache.js +16 -0
  100. package/local-cli/build.js +2 -2
  101. package/local-cli/clean-framework-cache.js +1 -1
  102. package/local-cli/clean-xcuitest-cache.js +19 -0
  103. package/local-cli/cli.js +13 -7
  104. package/local-cli/init.js +61 -21
  105. package/local-cli/rebuild-framework-cache.js +4 -4
  106. package/local-cli/rebuild-xcuitest-cache.js +21 -0
  107. package/local-cli/reset-lock-file.js +16 -0
  108. package/local-cli/run-server.js +12 -1
  109. package/local-cli/start.js +49 -0
  110. package/local-cli/startCommand/AppStartCommand.js +65 -0
  111. package/local-cli/templates/jest.js +13 -10
  112. package/local-cli/test.js +14 -8
  113. package/local-cli/testCommand/TestRunnerCommand.js +126 -77
  114. package/local-cli/testCommand/TestRunnerError.js +13 -0
  115. package/local-cli/testCommand/builder.js +5 -1
  116. package/local-cli/testCommand/middlewares.js +4 -13
  117. package/local-cli/testCommand/warnings.js +0 -3
  118. package/local-cli/utils/cliErrorHandling.js +15 -0
  119. package/local-cli/utils/jestInternals.js +4 -1
  120. package/package.json +46 -26
  121. package/runners/deprecation.js +42 -44
  122. package/runners/jest/globalSetup.js +1 -1
  123. package/runners/jest/globalTeardown.js +1 -1
  124. package/runners/jest/index.d.ts +61 -0
  125. package/runners/jest/index.js +3 -8
  126. package/runners/jest/reporters/DetoxReporter.js +33 -2
  127. package/runners/jest/testEnvironment/index.js +119 -68
  128. package/runners/jest/testEnvironment/listeners/DetoxCoreListener.js +97 -51
  129. package/runners/jest/testEnvironment/listeners/DetoxPlatformFilterListener.js +1 -1
  130. package/runners/jest/testEnvironment/listeners/SpecReporter.js +15 -17
  131. package/runners/jest/testEnvironment/listeners/WorkerAssignReporter.js +3 -7
  132. package/runners/jest/testEnvironment/utils/assertJestCircus27.js +17 -3
  133. package/scripts/build_framework.ios.sh +26 -60
  134. package/scripts/build_local_framework.ios.sh +62 -0
  135. package/scripts/build_local_xcuitest.ios.sh +53 -0
  136. package/scripts/build_xcuitest.ios.sh +23 -0
  137. package/scripts/pack_ios.sh +14 -5
  138. package/scripts/postinstall.js +10 -4
  139. package/src/DetoxWorker.js +112 -64
  140. package/src/android/actions/native.js +16 -0
  141. package/src/android/core/NativeElement.js +72 -20
  142. package/src/android/core/NativeExpect.js +28 -9
  143. package/src/android/core/NativeMatcher.js +31 -10
  144. package/src/android/core/NativeWaitFor.js +8 -0
  145. package/src/android/espressoapi/DetoxAction.js +37 -0
  146. package/src/android/espressoapi/DetoxMatcher.js +24 -0
  147. package/src/android/espressoapi/EspressoDetox.js +1 -1
  148. package/src/android/espressoapi/web/WebElement.js +1 -1
  149. package/src/android/interactions/native.js +25 -18
  150. package/src/android/matchers/index.js +2 -2
  151. package/src/android/matchers/native.js +10 -3
  152. package/src/artifacts/ArtifactsManager.js +14 -47
  153. package/src/artifacts/instruments/ios/SimulatorInstrumentsRecording.js +3 -3
  154. package/src/artifacts/log/android/ADBLogcatRecording.js +11 -28
  155. package/src/artifacts/log/ios/SimulatorLogRecording.js +1 -1
  156. package/src/artifacts/screenshot/SimulatorScreenshotPlugin.js +1 -1
  157. package/src/artifacts/templates/artifact/Artifact.js +1 -1
  158. package/src/artifacts/templates/plugin/ArtifactPlugin.js +2 -2
  159. package/src/artifacts/templates/plugin/TwoSnapshotsPerTestPlugin.js +2 -1
  160. package/src/artifacts/templates/plugin/WholeTestRecorderPlugin.js +3 -2
  161. package/src/artifacts/timeline/TimelineContextTypes.js +7 -0
  162. package/src/artifacts/utils/temporaryPath.js +47 -8
  163. package/src/artifacts/video/SimulatorRecordVideoPlugin.js +1 -1
  164. package/src/client/AsyncWebSocket.js +11 -19
  165. package/src/client/Client.js +35 -3
  166. package/src/client/actions/SyncStatusSchema.json +21 -0
  167. package/src/client/actions/actions.js +38 -0
  168. package/src/client/actions/formatters/SyncStatusFormatter.js +2 -0
  169. package/src/client/actions/formatters/sync-resources/BgThreadFormatter.js +5 -0
  170. package/src/client/actions/formatters/sync-resources/NetworkFormatter.js +1 -1
  171. package/src/configuration/collectCliConfig.js +3 -13
  172. package/src/configuration/composeAppsConfig.js +5 -1
  173. package/src/configuration/composeDeviceConfig.js +1 -1
  174. package/src/configuration/composeLoggerConfig.js +20 -10
  175. package/src/configuration/composeRunnerConfig.js +62 -9
  176. package/src/configuration/index.js +14 -9
  177. package/src/configuration/loadExternalConfig.js +1 -1
  178. package/src/devices/allocation/DeviceAllocator.js +15 -2
  179. package/src/devices/allocation/drivers/AllocationDriverBase.js +10 -2
  180. package/src/devices/allocation/drivers/android/attached/AttachedAndroidAllocDriver.js +10 -1
  181. package/src/devices/allocation/drivers/android/emulator/AVDValidator.js +5 -5
  182. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocDriver.js +28 -29
  183. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocationHelper.js +1 -1
  184. package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +6 -5
  185. package/src/devices/allocation/drivers/android/emulator/EmulatorVersionResolver.js +4 -6
  186. package/src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js +4 -17
  187. package/src/devices/allocation/drivers/android/genycloud/GenyAllocDriver.js +27 -18
  188. package/src/devices/allocation/drivers/android/genycloud/GenyInstanceAllocationHelper.js +1 -1
  189. package/src/devices/allocation/drivers/ios/SimulatorAllocDriver.js +12 -7
  190. package/src/devices/allocation/factories/base.js +1 -1
  191. package/src/devices/common/drivers/android/exec/ADB.js +9 -0
  192. package/src/devices/common/drivers/android/genycloud/exec/GenyCloudExec.js +1 -1
  193. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceNaming.js +3 -3
  194. package/src/devices/common/drivers/android/genycloud/services/GenyRecipesService.js +1 -1
  195. package/src/devices/common/drivers/android/tools/AppInstallHelper.js +4 -4
  196. package/src/devices/common/drivers/android/tools/EmulatorTelnet.js +1 -1
  197. package/src/devices/common/drivers/android/tools/{FileXfer.js → FileTransfer.js} +2 -2
  198. package/src/devices/common/drivers/android/tools/FreeDeviceFinder.js +1 -1
  199. package/src/devices/common/drivers/android/tools/MonitoredInstrumentation.js +1 -1
  200. package/src/devices/common/drivers/android/tools/TempFileTransfer.js +14 -0
  201. package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +21 -4
  202. package/src/devices/lifecycle/GenyGlobalLifecycleHandler.js +13 -15
  203. package/src/devices/runtime/RuntimeDevice.js +24 -12
  204. package/src/devices/runtime/drivers/DeviceDriverBase.js +2 -1
  205. package/src/devices/runtime/drivers/android/AndroidDriver.js +17 -8
  206. package/src/devices/runtime/drivers/ios/SimulatorDriver.js +42 -2
  207. package/src/devices/runtime/drivers/ios/XCUITestUtils.js +209 -0
  208. package/src/devices/runtime/drivers/ios/allowNetworkPermissionsXCUITest.scpt +14 -0
  209. package/src/devices/runtime/factories/android.js +6 -5
  210. package/src/devices/runtime/factories/base.js +3 -2
  211. package/src/errors/DetoxConfigErrorComposer.js +18 -3
  212. package/src/errors/DetoxError.js +5 -1
  213. package/src/ios/expectTwo.js +199 -78
  214. package/src/ipc/IPCClient.js +36 -27
  215. package/src/ipc/IPCServer.js +40 -21
  216. package/src/ipc/SessionState.js +60 -0
  217. package/src/logger/DetoxLogger.js +287 -154
  218. package/src/logger/index.js +5 -0
  219. package/src/logger/utils/BunyanLogger.js +105 -0
  220. package/src/logger/utils/CategoryThreadDispatcher.js +37 -0
  221. package/src/logger/utils/DetoxLogFinalizer.js +166 -0
  222. package/src/logger/utils/MessageStack.js +35 -0
  223. package/src/logger/utils/ThreadDispatcher.js +61 -0
  224. package/src/logger/{customConsoleLogger.js → utils/customConsoleLogger.js} +23 -6
  225. package/src/logger/utils/getMainCategory.js +5 -0
  226. package/src/logger/utils/sanitizeBunyanContext.js +30 -0
  227. package/src/logger/utils/streams/BunyanTransformer.js +72 -0
  228. package/src/logger/utils/streams/ChromeTraceTransformer.js +132 -0
  229. package/src/logger/utils/streams/DetoxJSONLParser.js +31 -0
  230. package/src/logger/utils/streams/JSONLStringer.js +55 -0
  231. package/src/logger/utils/streams/index.js +7 -0
  232. package/src/logger/utils/streams/transformers.js +39 -0
  233. package/src/logger/utils/tracerLegacy.js +37 -0
  234. package/src/realms/DetoxContext.js +83 -66
  235. package/src/realms/DetoxInternalsFacade.js +9 -13
  236. package/src/realms/DetoxPrimaryContext.js +117 -74
  237. package/src/realms/DetoxSecondaryContext.js +32 -35
  238. package/src/{symbols.js → realms/symbols.js} +16 -22
  239. package/src/server/DetoxConnection.js +18 -23
  240. package/src/server/DetoxServer.js +7 -10
  241. package/src/server/DetoxSession.js +9 -6
  242. package/src/server/DetoxSessionManager.js +2 -1
  243. package/src/server/handlers/AnonymousConnectionHandler.js +1 -0
  244. package/src/server/handlers/RegisteredConnectionHandler.js +1 -2
  245. package/src/servicelocator/android/index.js +2 -2
  246. package/src/utils/ExclusiveLockfile.js +1 -0
  247. package/src/utils/Timer.js +59 -36
  248. package/src/utils/argparse.js +11 -27
  249. package/src/utils/childProcess/exec.js +4 -2
  250. package/src/utils/childProcess/spawn.js +1 -1
  251. package/src/utils/dateUtils.js +5 -0
  252. package/src/utils/environment.js +55 -16
  253. package/src/utils/errorUtils.js +24 -3
  254. package/src/utils/invocationTraceDescriptions.js +44 -0
  255. package/src/utils/isPromise.js +8 -1
  256. package/src/utils/logger.js +2 -2
  257. package/src/utils/pathUtils.js +11 -0
  258. package/src/utils/shellUtils.js +17 -0
  259. package/src/utils/traceInvocationCall.js +21 -0
  260. package/src/utils/traceMethods.js +15 -0
  261. package/src/validation/ios/IosSimulatorEnvValidator.js +7 -4
  262. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0-javadoc.jar.md5 +0 -1
  263. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0-javadoc.jar.sha1 +0 -1
  264. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0-javadoc.jar.sha256 +0 -1
  265. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0-javadoc.jar.sha512 +0 -1
  266. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0-sources.jar.md5 +0 -1
  267. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0-sources.jar.sha1 +0 -1
  268. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0-sources.jar.sha256 +0 -1
  269. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0-sources.jar.sha512 +0 -1
  270. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0.aar +0 -0
  271. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0.aar.md5 +0 -1
  272. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0.aar.sha1 +0 -1
  273. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0.aar.sha256 +0 -1
  274. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0.aar.sha512 +0 -1
  275. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0.pom.md5 +0 -1
  276. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0.pom.sha1 +0 -1
  277. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0.pom.sha256 +0 -1
  278. package/Detox-android/com/wix/detox/21.0.0-breaking.new-global-lifecycle.0/detox-21.0.0-breaking.new-global-lifecycle.0.pom.sha512 +0 -1
  279. package/Detox-ios.tbz +0 -0
  280. package/android/detox/src/full/java/com/wix/detox/espresso/registry/IRStatusInquirer.kt +0 -24
  281. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DescriptiveIdlingResource.kt +0 -10
  282. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/IdlingResourceDescription.kt +0 -20
  283. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/DefaultIdleInterrogationStrategy.kt +0 -84
  284. package/android/detox/src/main/java/com/wix/detox/espresso/action/AdjustSliderToPositionAction.kt +0 -36
  285. package/android/detox/src/testFull/java/com/wix/detox/espresso/action/AdjustSliderToPositionActionTest.kt +0 -59
  286. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DefaultIdleInterrogationStrategySpec.kt +0 -115
  287. package/local-cli/build.test.js +0 -104
  288. package/local-cli/run-server.test.js +0 -23
  289. package/local-cli/test.test.js +0 -515
  290. package/runners/jest/deprecation.js +0 -25
  291. package/runners/jest/testEnvironment/utils/assertJestCircus27.test.js +0 -23
  292. package/scripts/build_universal_framework.sh +0 -14
  293. package/scripts/build_universal_framework_legacy.sh +0 -76
  294. package/scripts/build_universal_framework_modern.sh +0 -28
  295. package/src/configuration/utils/warnings.js +0 -12
  296. package/src/devices/common/drivers/android/tools/TempFileXfer.js +0 -16
  297. package/src/ipc/state.js +0 -76
  298. package/src/logger/DetoxTraceEventBuilder.js +0 -21
  299. package/src/logger/DetoxTracer.js +0 -133
  300. package/src/logger/TraceThreadDispatcher.js +0 -52
  301. package/src/realms/index.js +0 -10
  302. package/src/utils/ChromeTracingExporter.js +0 -53
  303. package/src/utils/streamUtils.js +0 -214
  304. package/src/utils/trace.js +0 -19
@@ -1,96 +1,28 @@
1
1
  package com.wix.detox.adapters.server
2
2
 
3
- import androidx.test.espresso.IdlingResource
4
3
  import com.wix.detox.TestEngineFacade
5
- import com.wix.detox.reactnative.idlingresources.DescriptiveIdlingResource
4
+ import com.wix.detox.inquiry.DetoxBusyResource
6
5
 
7
6
  class QueryStatusActionHandler(
8
7
  private val outboundServerAdapter: OutboundServerAdapter,
9
8
  private val testEngineFacade: TestEngineFacade
10
- )
11
- : DetoxActionHandler {
9
+ ) : DetoxActionHandler {
12
10
 
13
11
  override fun handle(params: String, messageId: Long) {
14
- val data = mutableMapOf<String, Any?>()
15
- data["status"] = formatStatus(testEngineFacade.getBusyIdlingResources())
16
-
12
+ val busyResources = testEngineFacade.getAllBusyResources()
13
+ val data = mapOf<String, Any?>(
14
+ "status" to formatStatus(busyResources)
15
+ )
17
16
  outboundServerAdapter.sendMessage("currentStatusResult", data, messageId)
18
17
  }
19
18
 
20
- private fun formatStatus(busyResources: List<IdlingResource>): Map<String, Any> {
19
+ private fun formatStatus(busyResources: List<DetoxBusyResource>): Map<String, Any> =
21
20
  if (busyResources.isEmpty()) {
22
- return mapOf("app_status" to "idle")
23
- }
24
-
25
- val status = mutableMapOf<String, Any>()
26
- status["app_status"] = "busy"
27
- status["busy_resources"] = busyResources.map{ formatResource(it) }
28
-
29
- return status
30
- }
31
-
32
- private fun formatResource(resource: IdlingResource): Map<String, Any> {
33
- if (resource is DescriptiveIdlingResource) {
34
- return resource.getDescription().json()
35
- }
36
-
37
- if (resource.javaClass.name.contains("LooperIdlingResource")) {
38
- return formatLooperResourceFromName(resource.name)
39
- }
40
-
41
- return mapOf<String, Any>(
42
- "name" to "unknown",
43
- "description" to mapOf<String, Any>(
44
- "identifier" to resource.name
21
+ mapOf("app_status" to "idle")
22
+ } else {
23
+ mapOf(
24
+ "app_status" to "busy",
25
+ "busy_resources" to busyResources.map { it.getDescription().json() }
45
26
  )
46
- )
47
- }
48
-
49
- private fun formatLooperResourceFromName(resourceName: String): Map<String, Any> {
50
- return when {
51
- isJSCodeExecution(resourceName) -> {
52
- formatLooperResource(
53
- "\"${resourceName}\" (JS Thread)",
54
- "JavaScript code"
55
- )
56
- }
57
- isNativeCodeExecution(resourceName) -> {
58
- formatLooperResource(
59
- "\"${resourceName}\" (Native Modules Thread)",
60
- "native module calls"
61
- )
62
- }
63
- else -> {
64
- formatLooperResource(
65
- "\"${resourceName}\""
66
- )
67
- }
68
27
  }
69
- }
70
-
71
- /**
72
- * @see URL https://reactnative.dev/docs/profiling
73
- */
74
- private fun isJSCodeExecution(looperName: String): Boolean {
75
- return looperName.contains("mqt_js")
76
- }
77
-
78
- private fun formatLooperResource(thread: String, executionType: String? = null): Map<String, Any> {
79
- return mapOf<String, Any>(
80
- "name" to "looper",
81
- "description" to
82
- mutableMapOf<String, Any>(
83
- "thread" to thread
84
- ).apply {
85
- if (executionType != null) put("execution_type", executionType)
86
- }
87
- )
88
- }
89
-
90
- /**
91
- * @see URL https://reactnative.dev/docs/profiling
92
- */
93
- private fun isNativeCodeExecution(looperName: String): Boolean {
94
- return looperName.contains("mqt_native")
95
- }
96
28
  }
@@ -2,6 +2,8 @@ package com.wix.detox.adapters.server;
2
2
 
3
3
  import android.util.Log;
4
4
 
5
+ import com.wix.detox.common.DetoxErrors;
6
+
5
7
  import org.json.JSONException;
6
8
  import org.json.JSONObject;
7
9
 
@@ -84,7 +86,7 @@ public class WebSocketClient {
84
86
  wsEventsHandler.onAction(type, params.toString(), messageId);
85
87
  }
86
88
  } catch (JSONException e) {
87
- Log.e(LOG_TAG, "Detox Error: receiveAction decode - " + e.toString());
89
+ throw new DetoxErrors.DetoxIllegalArgumentException(e);
88
90
  }
89
91
  }
90
92
 
@@ -0,0 +1,28 @@
1
+ package com.wix.detox.common
2
+
3
+ import android.view.View
4
+ import android.view.ViewGroup
5
+
6
+ fun View.forEachChild(callback: (child: View) -> Unit) {
7
+ if (this is ViewGroup) {
8
+ for (index in 0 until childCount) {
9
+ val child = getChildAt(index)
10
+ callback(child)
11
+ }
12
+ }
13
+ }
14
+
15
+ /**
16
+ * In-order traverse the view-hierarchy specified by a view, considered to be the hierarchy's root.
17
+ *
18
+ * @param view The hierarchy's root-view.
19
+ * @param callback A function to call per each view. Returning `false` from the callback indicates
20
+ * a request to refrain from traversing the sub-hierarchy associated with the current view.
21
+ */
22
+ fun traverseViewHierarchy(view: View, callback: (view: View) -> Boolean) {
23
+ if (callback(view)) {
24
+ view.forEachChild { child ->
25
+ traverseViewHierarchy(child, callback)
26
+ }
27
+ }
28
+ }
@@ -1,10 +1,11 @@
1
1
  package com.wix.detox.espresso;
2
2
 
3
3
  import android.view.View;
4
+ import android.os.Build;
4
5
 
5
- import com.facebook.react.views.slider.ReactSliderManager;
6
6
  import com.wix.detox.common.DetoxErrors.DetoxRuntimeException;
7
7
  import com.wix.detox.common.DetoxErrors.StaleActionException;
8
+ import com.wix.detox.espresso.action.RNDetoxAccessibilityAction;
8
9
  import com.wix.detox.espresso.action.AdjustSliderToPositionAction;
9
10
  import com.wix.detox.espresso.action.DetoxMultiTap;
10
11
  import com.wix.detox.espresso.action.RNClickAction;
@@ -20,6 +21,11 @@ import com.wix.detox.espresso.scroll.ScrollHelper;
20
21
  import com.wix.detox.espresso.scroll.SwipeHelper;
21
22
 
22
23
  import org.hamcrest.Matcher;
24
+ import java.text.ParseException;
25
+ import java.text.SimpleDateFormat;
26
+ import java.time.ZonedDateTime;
27
+ import java.util.Calendar;
28
+ import java.util.Date;
23
29
 
24
30
  import androidx.test.espresso.UiController;
25
31
  import androidx.test.espresso.ViewAction;
@@ -27,10 +33,12 @@ import androidx.test.espresso.action.CoordinatesProvider;
27
33
  import androidx.test.espresso.action.GeneralClickAction;
28
34
  import androidx.test.espresso.action.GeneralLocation;
29
35
  import androidx.test.espresso.action.Press;
36
+ import androidx.test.espresso.contrib.PickerActions;
30
37
 
31
38
  import static androidx.test.espresso.action.ViewActions.actionWithAssertions;
32
39
  import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
33
40
  import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
41
+
34
42
  import static org.hamcrest.Matchers.allOf;
35
43
 
36
44
 
@@ -40,6 +48,8 @@ import static org.hamcrest.Matchers.allOf;
40
48
 
41
49
  public class DetoxAction {
42
50
  private static final String LOG_TAG = "detox";
51
+ private static final String ISO8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";
52
+ private static final String ISO8601_FORMAT_NO_TZ = "yyyy-MM-dd'T'HH:mm:ss";
43
53
 
44
54
  private DetoxAction() {
45
55
  // static class
@@ -150,9 +160,21 @@ public class DetoxAction {
150
160
  return new ScrollToIndexAction(index);
151
161
  }
152
162
 
163
+ public static ViewAction setDatePickerDate(String dateString, String formatString) throws ParseException {
164
+ Date date;
165
+ if (formatString.equals("ISO8601")) {
166
+ date = parseDateISO8601(dateString);
167
+ } else {
168
+ date = new SimpleDateFormat(formatString).parse(dateString);
169
+ }
170
+
171
+ Calendar cal = Calendar.getInstance();
172
+ cal.setTime(date);
173
+ return PickerActions.setDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH));
174
+ }
175
+
153
176
  public static ViewAction adjustSliderToPosition(final double newPosition) {
154
- ReactSliderManager reactSliderManager = new ReactSliderManager();
155
- return new AdjustSliderToPositionAction(newPosition, reactSliderManager);
177
+ return new AdjustSliderToPositionAction(newPosition);
156
178
  }
157
179
 
158
180
  public static ViewAction takeViewScreenshot() {
@@ -181,4 +203,16 @@ public class DetoxAction {
181
203
  }
182
204
  };
183
205
  }
206
+
207
+ public static ViewAction accessibilityAction(final String actionName) {
208
+ return new RNDetoxAccessibilityAction(actionName);
209
+ }
210
+
211
+ private static Date parseDateISO8601(String dateString) throws ParseException {
212
+ try {
213
+ return new SimpleDateFormat(ISO8601_FORMAT).parse(dateString);
214
+ } catch (ParseException e) {
215
+ return new SimpleDateFormat(ISO8601_FORMAT_NO_TZ).parse(dateString);
216
+ }
217
+ }
184
218
  }
@@ -12,15 +12,17 @@ import static androidx.test.espresso.matcher.ViewMatchers.isChecked;
12
12
  import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
13
13
  import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
14
14
  import static androidx.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
15
+ import static androidx.test.espresso.matcher.ViewMatchers.isFocused;
15
16
  import static androidx.test.espresso.matcher.ViewMatchers.isNotChecked;
16
17
  import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
17
18
  import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
18
19
  import static androidx.test.espresso.matcher.ViewMatchers.withTagValue;
19
20
  import static androidx.test.espresso.matcher.ViewMatchers.withText;
20
- import static androidx.test.espresso.matcher.ViewMatchers.isFocused;
21
21
  import static com.wix.detox.espresso.matcher.ViewMatchers.isMatchingAtIndex;
22
22
  import static com.wix.detox.espresso.matcher.ViewMatchers.isOfClassName;
23
23
  import static com.wix.detox.espresso.matcher.ViewMatchers.toHaveSliderPosition;
24
+ import static com.wix.detox.espresso.matcher.ViewMatchers.withAccessibilityLabel;
25
+ import static com.wix.detox.espresso.matcher.ViewMatchers.withShallowAccessibilityLabel;
24
26
  import static org.hamcrest.Matchers.allOf;
25
27
  import static org.hamcrest.Matchers.anyOf;
26
28
  import static org.hamcrest.Matchers.is;
@@ -43,6 +45,14 @@ public class DetoxMatcher {
43
45
  return allOf(withText(text), withEffectiveVisibility(Visibility.VISIBLE));
44
46
  }
45
47
 
48
+ public static Matcher<View> matcherForAccessibilityLabel(String label) {
49
+ return allOf(withAccessibilityLabel(label), withEffectiveVisibility(Visibility.VISIBLE));
50
+ }
51
+
52
+ public static Matcher<View> matcherForShallowAccessibilityLabel(String label) {
53
+ return allOf(withShallowAccessibilityLabel(label), withEffectiveVisibility(Visibility.VISIBLE));
54
+ }
55
+
46
56
  public static Matcher<View> matcherForContentDescription(String contentDescription) {
47
57
  return allOf(withContentDescription(contentDescription), withEffectiveVisibility(Visibility.VISIBLE));
48
58
  }
@@ -5,7 +5,7 @@ import android.util.Log;
5
5
  import android.view.Choreographer;
6
6
 
7
7
  import com.wix.detox.common.UIThread;
8
- import com.wix.detox.espresso.common.utils.UiControllerUtils;
8
+ import com.wix.detox.espresso.action.common.utils.UiControllerUtils;
9
9
 
10
10
  import org.joor.Reflect;
11
11
  import org.joor.ReflectException;
@@ -0,0 +1,22 @@
1
+ package com.wix.detox.espresso.action
2
+
3
+ import android.view.View
4
+ import androidx.appcompat.widget.AppCompatSeekBar
5
+ import androidx.test.espresso.UiController
6
+ import androidx.test.espresso.ViewAction
7
+ import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom
8
+ import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
9
+ import com.wix.detox.espresso.common.SliderHelper
10
+ import org.hamcrest.Matcher
11
+ import org.hamcrest.Matchers
12
+
13
+ class AdjustSliderToPositionAction(private val targetPositionPct: Double) : ViewAction {
14
+ override fun getDescription() = "adjustSliderToPosition"
15
+ override fun getConstraints(): Matcher<View?>? =
16
+ Matchers.allOf( isDisplayed(), isAssignableFrom(AppCompatSeekBar::class.java) )
17
+
18
+ override fun perform(uiController: UiController?, view: View) {
19
+ val sliderHelper = SliderHelper.create(view)
20
+ sliderHelper.setProgressPct(targetPositionPct)
21
+ }
22
+ }
@@ -9,6 +9,8 @@ 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.common.SliderHelper
13
+ import com.wix.detox.reactnative.ui.getAccessibilityLabel
12
14
  import org.hamcrest.Matcher
13
15
  import org.hamcrest.Matchers
14
16
  import org.hamcrest.Matchers.allOf
@@ -46,7 +48,7 @@ private class CommonAttributes {
46
48
  fun get(json: JSONObject, view: View) {
47
49
  getId(json, view)
48
50
  getVisibility(json, view)
49
- getContentDescription(json, view)
51
+ getAccessibilityLabel(json, view)
50
52
  getAlpha(json, view)
51
53
  getElevation(json, view)
52
54
  getHeight(json, view)
@@ -65,8 +67,8 @@ private class CommonAttributes {
65
67
  json.put("visible", view.getLocalVisibleRect(Rect()))
66
68
  }
67
69
 
68
- private fun getContentDescription(json: JSONObject, view: View) =
69
- view.contentDescription?.let {
70
+ private fun getAccessibilityLabel(json: JSONObject, view: View) =
71
+ view.getAccessibilityLabel()?.let {
70
72
  json.put("label", it)
71
73
  }
72
74
 
@@ -127,13 +129,24 @@ private class CheckBoxAttributes {
127
129
  rootObject.put("value", view.isChecked)
128
130
  }
129
131
 
132
+ /**
133
+ * Note: this applies also to [androidx.appcompat.widget.AppCompatSeekBar], which
134
+ * is anything RN-slider-ish.
135
+ */
130
136
  private class ProgressBarAttributes {
131
137
  fun get(json: JSONObject, view: View) {
132
138
  if (view is ProgressBar) {
133
- getProgressBarValue(json, view)
139
+ SliderHelper.maybeCreate(view)?.let {
140
+ getRNSliderValue(json, it)
141
+ } ?:
142
+ getProgressBarValue(json, view)
134
143
  }
135
144
  }
136
145
 
146
+ private fun getRNSliderValue(rootObject: JSONObject, sliderHelper: SliderHelper) {
147
+ rootObject.put("value", sliderHelper.getCurrentProgressPct())
148
+ }
149
+
137
150
  private fun getProgressBarValue(rootObject: JSONObject, view: ProgressBar) =
138
151
  rootObject.put("value", view.progress)
139
152
  }
@@ -0,0 +1,46 @@
1
+ package com.wix.detox.espresso.action
2
+
3
+ import android.view.View
4
+ import androidx.test.espresso.UiController
5
+ import androidx.test.espresso.ViewAction
6
+ import com.facebook.react.bridge.Arguments
7
+ import com.facebook.react.bridge.ReactContext
8
+ import com.facebook.react.bridge.WritableMap
9
+ import com.facebook.react.uimanager.UIManagerHelper
10
+ import com.facebook.react.uimanager.events.Event
11
+ import com.wix.detox.espresso.DetoxMatcher
12
+ import org.hamcrest.Matcher
13
+
14
+ class RNDetoxAccessibilityAction(private val mActionName: String) : ViewAction {
15
+
16
+ override fun getConstraints(): Matcher<View?>? = DetoxMatcher.matcherForNotNull()
17
+
18
+ override fun getDescription(): String = "Dispatch an Accessibility Action"
19
+
20
+ override fun perform(uiController: UiController?, view: View?) {
21
+ val reactContext = view?.context as? ReactContext ?: return
22
+ val reactTag = view.id
23
+
24
+ UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag)
25
+ ?.dispatchEvent(
26
+ TopAccessibilityEvent(
27
+ surfaceId = UIManagerHelper.getSurfaceId(reactContext),
28
+ viewId = reactTag,
29
+ actionName = mActionName,
30
+ )
31
+ )
32
+
33
+ val waitTimeMS = 100
34
+ uiController!!.loopMainThreadForAtLeast(waitTimeMS.toLong())
35
+ }
36
+ }
37
+
38
+ class TopAccessibilityEvent(surfaceId: Int, viewId: Int, private val actionName: String) :
39
+ Event<TopAccessibilityEvent>(surfaceId, viewId) {
40
+
41
+ override fun getEventName(): String = "topAccessibilityAction"
42
+
43
+ override fun getEventData(): WritableMap? {
44
+ return Arguments.createMap().apply { putString("actionName", actionName) }
45
+ }
46
+ }
@@ -0,0 +1,75 @@
1
+ package com.wix.detox.espresso.common
2
+
3
+ import android.view.View
4
+ import androidx.appcompat.widget.AppCompatSeekBar
5
+ import com.facebook.react.bridge.JavaOnlyMap
6
+ import com.facebook.react.uimanager.ReactStylesDiffMap
7
+ import com.facebook.react.views.slider.ReactSlider
8
+ import com.wix.detox.common.DetoxErrors.DetoxIllegalStateException
9
+ import com.wix.detox.espresso.action.common.ReflectUtils
10
+ import org.joor.Reflect
11
+
12
+ private const val CLASS_REACT_SLIDER_LEGACY = "com.facebook.react.views.slider.ReactSlider"
13
+ private const val CLASS_REACT_SLIDER_COMMUNITY = "com.reactnativecommunity.slider.ReactSlider"
14
+
15
+ abstract class SliderHelper(protected val slider: AppCompatSeekBar) {
16
+ fun getCurrentProgressPct(): Double {
17
+ val nativeProgress = slider.progress.toDouble()
18
+ val nativeMax = slider.max
19
+ return nativeProgress / nativeMax
20
+ }
21
+
22
+ // TODO Make this more testable (e.g. by delegating the set action away)
23
+ fun setProgressPct(valuePct: Double) {
24
+ val maxJSProgress = calcMaxJSProgress()
25
+ val valueJS = valuePct * maxJSProgress
26
+ setProgressJS(valueJS)
27
+ }
28
+
29
+ protected abstract fun setProgressJS(valueJS: Double)
30
+
31
+ private fun calcMaxJSProgress(): Double {
32
+ val nativeProgress = slider.progress.toDouble()
33
+ val nativeMax = slider.max
34
+ val toMaxFactor = nativeMax / nativeProgress
35
+
36
+ val jsProgress = getJSProgress()
37
+ return jsProgress * toMaxFactor
38
+ }
39
+
40
+ private fun getJSProgress(): Double =
41
+ Reflect.on(slider).call("toRealProgress", slider.progress).get() as Double
42
+
43
+ companion object {
44
+ fun create(view: View) =
45
+ maybeCreate(view)
46
+ ?: throw DetoxIllegalStateException("Cannot handle this type of a seek-bar view (Class ${view.javaClass.canonicalName}). " +
47
+ "Only React Native sliders are currently supported.")
48
+
49
+ fun maybeCreate(view: View): SliderHelper? =
50
+ when {
51
+ ReflectUtils.isAssignableFrom(view, CLASS_REACT_SLIDER_LEGACY)
52
+ -> LegacySliderHelper(view as ReactSlider)
53
+ ReflectUtils.isAssignableFrom(view, CLASS_REACT_SLIDER_COMMUNITY)
54
+ -> CommunitySliderHelper(view as AppCompatSeekBar)
55
+ else
56
+ -> null
57
+ }
58
+ }
59
+ }
60
+
61
+ private class LegacySliderHelper(slider: AppCompatSeekBar): SliderHelper(slider) {
62
+ override fun setProgressJS(valueJS: Double) {
63
+ val reactSliderManager = com.facebook.react.views.slider.ReactSliderManager()
64
+ reactSliderManager.updateProperties(slider as ReactSlider, buildStyles("value", valueJS))
65
+ }
66
+
67
+ private fun buildStyles(vararg keysAndValues: Any) = ReactStylesDiffMap(JavaOnlyMap.of(*keysAndValues))
68
+ }
69
+
70
+ private class CommunitySliderHelper(slider: AppCompatSeekBar): SliderHelper(slider) {
71
+ override fun setProgressJS(valueJS: Double) {
72
+ val reactSliderManager = Class.forName("com.reactnativecommunity.slider.ReactSliderManager").newInstance()
73
+ Reflect.on(reactSliderManager).call("setValue", slider, valueJS)
74
+ }
75
+ }
@@ -0,0 +1,16 @@
1
+ package com.wix.detox.espresso.common
2
+
3
+ import com.wix.detox.espresso.action.common.utils.getUiController
4
+ import org.joor.Reflect
5
+
6
+ private const val FIELD_ASYNC_IDLE = "asyncIdle"
7
+ private const val FIELD_COMPAT_IDLE = "compatIdle"
8
+ private const val METHOD_IS_IDLE_NOW = "isIdleNow"
9
+
10
+ class UiControllerImplReflected {
11
+ fun isAsyncIdleNow(): Boolean =
12
+ Reflect.on(getUiController()).field(FIELD_ASYNC_IDLE).call(METHOD_IS_IDLE_NOW).get()
13
+
14
+ fun isCompatIdleNow(): Boolean =
15
+ Reflect.on(getUiController()).field(FIELD_COMPAT_IDLE).call(METHOD_IS_IDLE_NOW).get()
16
+ }
@@ -0,0 +1,8 @@
1
+ package com.wix.detox.espresso.idlingresources
2
+
3
+ import androidx.test.espresso.IdlingResource
4
+
5
+ interface DescriptiveIdlingResource: IdlingResource {
6
+ fun getDebugName(): String
7
+ fun getBusyHint(): Map<String, Any>?
8
+ }
@@ -3,20 +3,25 @@
3
3
  package com.wix.detox.espresso.matcher
4
4
 
5
5
  import android.view.View
6
+ import androidx.appcompat.widget.AppCompatSeekBar
6
7
  import androidx.test.espresso.matcher.BoundedMatcher
7
8
  import androidx.test.espresso.matcher.ViewMatchers
8
9
  import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
9
- import com.facebook.react.views.slider.ReactSlider
10
- import org.hamcrest.BaseMatcher
11
- import org.hamcrest.Description
12
- import org.hamcrest.Matcher
13
- import org.hamcrest.Matchers.allOf
14
- import org.hamcrest.TypeSafeMatcher
10
+ import com.wix.detox.espresso.common.SliderHelper
11
+ import org.hamcrest.*
12
+ import org.hamcrest.Matchers.*
13
+ import kotlin.math.abs
15
14
 
16
15
  /*
17
16
  * An extension of [androidx.test.espresso.matcher.ViewMatchers].
18
17
  */
19
18
 
19
+ fun withAccessibilityLabel(text: String) =
20
+ WithAccessibilityLabelMatcher(`is`(text))
21
+
22
+ fun withShallowAccessibilityLabel(label: String): Matcher<View>
23
+ = anyOf(ViewMatchers.withContentDescription(label), ViewMatchers.withText(label))
24
+
20
25
  fun isOfClassName(className: String): Matcher<View> {
21
26
  try {
22
27
  val cls = Class.forName(className)
@@ -36,6 +41,19 @@ fun isOfClassName(className: String): Matcher<View> {
36
41
  fun isMatchingAtIndex(index: Int, innerMatcher: Matcher<View>): Matcher<View> =
37
42
  ViewAtIndexMatcher(index, innerMatcher)
38
43
 
44
+ fun toHaveSliderPosition(expectedValuePct: Double, tolerance: Double): Matcher<View?> =
45
+ object: BoundedMatcher<View?, AppCompatSeekBar>(AppCompatSeekBar::class.java) {
46
+ override fun describeTo(description: Description) {
47
+ description.appendText("sliderPositionPercent($expectedValuePct)")
48
+ }
49
+
50
+ override fun matchesSafely(view: AppCompatSeekBar): Boolean {
51
+ val sliderHelper = SliderHelper.create(view)
52
+ val progressPct = sliderHelper.getCurrentProgressPct()
53
+ return (abs(progressPct - expectedValuePct) <= tolerance)
54
+ }
55
+ }
56
+
39
57
  /**
40
58
  * Same as [androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom], but accepts any class. Needed
41
59
  * in order to avoid warning when passing 'any' class.
@@ -47,25 +65,3 @@ private class IsAssignableFromMatcher(private val clazz: Class<*>) : TypeSafeMat
47
65
  description.appendText("is assignable from class: $clazz")
48
66
  }
49
67
  }
50
-
51
- fun toHaveSliderPosition(expectedValue: Double, tolerance: Double): Matcher<View?> {
52
- return object : BoundedMatcher<View?, ReactSlider>(ReactSlider::class.java) {
53
- override fun describeTo(description: Description) {
54
- description.appendText("expected: $expectedValue")
55
- }
56
-
57
- override fun matchesSafely(slider: ReactSlider?): Boolean {
58
- val currentProgress = slider?.progress
59
-
60
- if (currentProgress != null) {
61
- val realProgress = slider.toRealProgress(currentProgress)
62
- val currentPctFactor = slider.max / currentProgress.toDouble()
63
- val realTotal = realProgress * currentPctFactor
64
- val actualValue = realProgress / realTotal
65
- return Math.abs(actualValue - expectedValue) <= tolerance
66
- }
67
-
68
- return false
69
- }
70
- }
71
- }
@@ -0,0 +1,23 @@
1
+ package com.wix.detox.espresso.matcher
2
+
3
+ import android.view.View
4
+ import com.wix.detox.reactnative.ui.getAccessibilityLabel
5
+ import org.hamcrest.Description
6
+ import org.hamcrest.Matcher
7
+ import org.hamcrest.TypeSafeDiagnosingMatcher
8
+
9
+ class WithAccessibilityLabelMatcher(private val textMatcher: Matcher<String>): TypeSafeDiagnosingMatcher<View>() {
10
+ override fun matchesSafely(view: View, mismatchDescription: Description): Boolean =
11
+ view.getAccessibilityLabel().let { contentDescription ->
12
+ return textMatcher.matches(contentDescription).also { matched ->
13
+ if (!matched) {
14
+ mismatchDescription.appendText("view.getAccessibilityLabel() ")
15
+ textMatcher.describeMismatch(contentDescription, mismatchDescription)
16
+ }
17
+ }
18
+ }
19
+
20
+ override fun describeTo(description: Description) {
21
+ description.appendText("view.getAccessibilityLabel() ").appendDescriptionOf(textMatcher)
22
+ }
23
+ }
@@ -0,0 +1,48 @@
1
+ package com.wix.detox.espresso.registry
2
+
3
+ import androidx.test.espresso.Espresso
4
+ import androidx.test.espresso.base.IdlingResourceRegistry
5
+ import com.wix.detox.common.UIThread
6
+ import com.wix.detox.espresso.common.UiControllerImplReflected
7
+ import com.wix.detox.inquiry.DetoxBusyResource
8
+ import com.wix.detox.inquiry.DetoxBusyResource.BusyAsyncTasks
9
+ import com.wix.detox.inquiry.DetoxBusyResource.BusyIdlingResource
10
+ import org.joor.Reflect
11
+ import java.util.concurrent.Callable
12
+
13
+ // TODO Better to split inquiry to two separate classes running under the single `UIThread.postFirstSync()` we have here.
14
+ class BusyResourcesInquirer(
15
+ private val registry: IdlingResourceRegistry,
16
+ private val uiControllerImplReflected: UiControllerImplReflected
17
+ ) {
18
+ fun getAllBusyResources(): List<DetoxBusyResource> {
19
+ return UIThread.postFirstSync(Callable<List<DetoxBusyResource>> {
20
+ mutableListOf<DetoxBusyResource>().apply {
21
+ addAll(getBusyIdlingResources())
22
+ addAll(getAsyncTasksResource()?.let { listOf(it) } ?: emptyList())
23
+ }
24
+ })
25
+ }
26
+
27
+ private fun getBusyIdlingResources(): List<BusyIdlingResource> =
28
+ registry.resources
29
+ .filter { !it.isIdleNow }
30
+ .map { BusyIdlingResource(it) }
31
+
32
+ private fun getAsyncTasksResource(): BusyAsyncTasks? {
33
+ // Mind the implicit optimization:
34
+ // Don't inspect both resources if not necessary (async-tasks is not idle).
35
+ if (uiControllerImplReflected.isAsyncIdleNow() &&
36
+ uiControllerImplReflected.isCompatIdleNow()) {
37
+ return null
38
+ }
39
+ return BusyAsyncTasks
40
+ }
41
+
42
+ companion object {
43
+ val INSTANCE = BusyResourcesInquirer(getRegistryDefault(), UiControllerImplReflected())
44
+ }
45
+ }
46
+
47
+ private fun getRegistryDefault() =
48
+ Reflect.on(Espresso::class.java).get<IdlingResourceRegistry>("baseRegistry")