@wdio/browserstack-service 0.0.0-canary-20260722132416

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (331) hide show
  1. package/LICENSE-MIT +20 -0
  2. package/README.md +392 -0
  3. package/browserstack-service.d.ts +43 -0
  4. package/build/Percy/Percy-Handler.d.ts +32 -0
  5. package/build/Percy/Percy-Handler.d.ts.map +1 -0
  6. package/build/Percy/Percy-Handler.js +165 -0
  7. package/build/Percy/Percy-Handler.js.map +1 -0
  8. package/build/Percy/Percy.d.ts +19 -0
  9. package/build/Percy/Percy.d.ts.map +1 -0
  10. package/build/Percy/Percy.js +164 -0
  11. package/build/Percy/Percy.js.map +1 -0
  12. package/build/Percy/PercyBinary.d.ts +10 -0
  13. package/build/Percy/PercyBinary.d.ts.map +1 -0
  14. package/build/Percy/PercyBinary.js +161 -0
  15. package/build/Percy/PercyBinary.js.map +1 -0
  16. package/build/Percy/PercyCaptureMap.d.ts +9 -0
  17. package/build/Percy/PercyCaptureMap.d.ts.map +1 -0
  18. package/build/Percy/PercyCaptureMap.js +36 -0
  19. package/build/Percy/PercyCaptureMap.js.map +1 -0
  20. package/build/Percy/PercyHelper.d.ts +8 -0
  21. package/build/Percy/PercyHelper.d.ts.map +1 -0
  22. package/build/Percy/PercyHelper.js +68 -0
  23. package/build/Percy/PercyHelper.js.map +1 -0
  24. package/build/Percy/PercyLogger.d.ts +15 -0
  25. package/build/Percy/PercyLogger.d.ts.map +1 -0
  26. package/build/Percy/PercyLogger.js +68 -0
  27. package/build/Percy/PercyLogger.js.map +1 -0
  28. package/build/Percy/PercySDK.d.ts +4 -0
  29. package/build/Percy/PercySDK.d.ts.map +1 -0
  30. package/build/Percy/PercySDK.js +86 -0
  31. package/build/Percy/PercySDK.js.map +1 -0
  32. package/build/accessibility-handler.d.ts +52 -0
  33. package/build/accessibility-handler.d.ts.map +1 -0
  34. package/build/accessibility-handler.js +361 -0
  35. package/build/accessibility-handler.js.map +1 -0
  36. package/build/ai-handler.d.ts +23 -0
  37. package/build/ai-handler.d.ts.map +1 -0
  38. package/build/ai-handler.js +184 -0
  39. package/build/ai-handler.js.map +1 -0
  40. package/build/bstackLogger.d.ts +16 -0
  41. package/build/bstackLogger.d.ts.map +1 -0
  42. package/build/bstackLogger.js +71 -0
  43. package/build/bstackLogger.js.map +1 -0
  44. package/build/cleanup.d.ts +9 -0
  45. package/build/cleanup.d.ts.map +1 -0
  46. package/build/cleanup.js +101 -0
  47. package/build/cleanup.js.map +1 -0
  48. package/build/cli/apiUtils.d.ts +14 -0
  49. package/build/cli/apiUtils.d.ts.map +1 -0
  50. package/build/cli/apiUtils.js +25 -0
  51. package/build/cli/apiUtils.js.map +1 -0
  52. package/build/cli/cliLogger.d.ts +17 -0
  53. package/build/cli/cliLogger.d.ts.map +1 -0
  54. package/build/cli/cliLogger.js +82 -0
  55. package/build/cli/cliLogger.js.map +1 -0
  56. package/build/cli/cliUtils.d.ts +64 -0
  57. package/build/cli/cliUtils.d.ts.map +1 -0
  58. package/build/cli/cliUtils.js +461 -0
  59. package/build/cli/cliUtils.js.map +1 -0
  60. package/build/cli/eventDispatcher.d.ts +28 -0
  61. package/build/cli/eventDispatcher.d.ts.map +1 -0
  62. package/build/cli/eventDispatcher.js +49 -0
  63. package/build/cli/eventDispatcher.js.map +1 -0
  64. package/build/cli/frameworks/automationFramework.d.ts +89 -0
  65. package/build/cli/frameworks/automationFramework.d.ts.map +1 -0
  66. package/build/cli/frameworks/automationFramework.js +132 -0
  67. package/build/cli/frameworks/automationFramework.js.map +1 -0
  68. package/build/cli/frameworks/constants/automationFrameworkConstants.d.ts +18 -0
  69. package/build/cli/frameworks/constants/automationFrameworkConstants.d.ts.map +1 -0
  70. package/build/cli/frameworks/constants/automationFrameworkConstants.js +18 -0
  71. package/build/cli/frameworks/constants/automationFrameworkConstants.js.map +1 -0
  72. package/build/cli/frameworks/constants/testFrameworkConstants.d.ts +43 -0
  73. package/build/cli/frameworks/constants/testFrameworkConstants.d.ts.map +1 -0
  74. package/build/cli/frameworks/constants/testFrameworkConstants.js +43 -0
  75. package/build/cli/frameworks/constants/testFrameworkConstants.js.map +1 -0
  76. package/build/cli/frameworks/testFramework.d.ts +89 -0
  77. package/build/cli/frameworks/testFramework.d.ts.map +1 -0
  78. package/build/cli/frameworks/testFramework.js +126 -0
  79. package/build/cli/frameworks/testFramework.js.map +1 -0
  80. package/build/cli/frameworks/wdioAutomationFramework.d.ts +28 -0
  81. package/build/cli/frameworks/wdioAutomationFramework.d.ts.map +1 -0
  82. package/build/cli/frameworks/wdioAutomationFramework.js +67 -0
  83. package/build/cli/frameworks/wdioAutomationFramework.js.map +1 -0
  84. package/build/cli/frameworks/wdioMochaTestFramework.d.ts +82 -0
  85. package/build/cli/frameworks/wdioMochaTestFramework.d.ts.map +1 -0
  86. package/build/cli/frameworks/wdioMochaTestFramework.js +322 -0
  87. package/build/cli/frameworks/wdioMochaTestFramework.js.map +1 -0
  88. package/build/cli/grpcClient.d.ts +86 -0
  89. package/build/cli/grpcClient.d.ts.map +1 -0
  90. package/build/cli/grpcClient.js +532 -0
  91. package/build/cli/grpcClient.js.map +1 -0
  92. package/build/cli/index.d.ts +150 -0
  93. package/build/cli/index.d.ts.map +1 -0
  94. package/build/cli/index.js +464 -0
  95. package/build/cli/index.js.map +1 -0
  96. package/build/cli/instances/automationFrameworkInstance.d.ts +33 -0
  97. package/build/cli/instances/automationFrameworkInstance.d.ts.map +1 -0
  98. package/build/cli/instances/automationFrameworkInstance.js +45 -0
  99. package/build/cli/instances/automationFrameworkInstance.js.map +1 -0
  100. package/build/cli/instances/testFrameworkInstance.d.ts +62 -0
  101. package/build/cli/instances/testFrameworkInstance.d.ts.map +1 -0
  102. package/build/cli/instances/testFrameworkInstance.js +97 -0
  103. package/build/cli/instances/testFrameworkInstance.js.map +1 -0
  104. package/build/cli/instances/trackedContext.d.ts +32 -0
  105. package/build/cli/instances/trackedContext.d.ts.map +1 -0
  106. package/build/cli/instances/trackedContext.js +48 -0
  107. package/build/cli/instances/trackedContext.js.map +1 -0
  108. package/build/cli/instances/trackedInstance.d.ts +40 -0
  109. package/build/cli/instances/trackedInstance.d.ts.map +1 -0
  110. package/build/cli/instances/trackedInstance.js +64 -0
  111. package/build/cli/instances/trackedInstance.js.map +1 -0
  112. package/build/cli/modules/accessibilityModule.d.ts +46 -0
  113. package/build/cli/modules/accessibilityModule.d.ts.map +1 -0
  114. package/build/cli/modules/accessibilityModule.js +447 -0
  115. package/build/cli/modules/accessibilityModule.js.map +1 -0
  116. package/build/cli/modules/automateModule.d.ts +26 -0
  117. package/build/cli/modules/automateModule.d.ts.map +1 -0
  118. package/build/cli/modules/automateModule.js +223 -0
  119. package/build/cli/modules/automateModule.js.map +1 -0
  120. package/build/cli/modules/baseModule.d.ts +33 -0
  121. package/build/cli/modules/baseModule.d.ts.map +1 -0
  122. package/build/cli/modules/baseModule.js +52 -0
  123. package/build/cli/modules/baseModule.js.map +1 -0
  124. package/build/cli/modules/observabilityModule.d.ts +22 -0
  125. package/build/cli/modules/observabilityModule.d.ts.map +1 -0
  126. package/build/cli/modules/observabilityModule.js +46 -0
  127. package/build/cli/modules/observabilityModule.js.map +1 -0
  128. package/build/cli/modules/percyModule.d.ts +19 -0
  129. package/build/cli/modules/percyModule.d.ts.map +1 -0
  130. package/build/cli/modules/percyModule.js +78 -0
  131. package/build/cli/modules/percyModule.js.map +1 -0
  132. package/build/cli/modules/testHubModule.d.ts +30 -0
  133. package/build/cli/modules/testHubModule.d.ts.map +1 -0
  134. package/build/cli/modules/testHubModule.js +233 -0
  135. package/build/cli/modules/testHubModule.js.map +1 -0
  136. package/build/cli/modules/webdriverIOModule.d.ts +29 -0
  137. package/build/cli/modules/webdriverIOModule.d.ts.map +1 -0
  138. package/build/cli/modules/webdriverIOModule.js +129 -0
  139. package/build/cli/modules/webdriverIOModule.js.map +1 -0
  140. package/build/cli/states/automationFrameworkState.d.ts +65 -0
  141. package/build/cli/states/automationFrameworkState.d.ts.map +1 -0
  142. package/build/cli/states/automationFrameworkState.js +62 -0
  143. package/build/cli/states/automationFrameworkState.js.map +1 -0
  144. package/build/cli/states/hookState.d.ts +45 -0
  145. package/build/cli/states/hookState.d.ts.map +1 -0
  146. package/build/cli/states/hookState.js +44 -0
  147. package/build/cli/states/hookState.js.map +1 -0
  148. package/build/cli/states/testFrameworkState.d.ts +125 -0
  149. package/build/cli/states/testFrameworkState.d.ts.map +1 -0
  150. package/build/cli/states/testFrameworkState.js +116 -0
  151. package/build/cli/states/testFrameworkState.js.map +1 -0
  152. package/build/config.d.ts +29 -0
  153. package/build/config.d.ts.map +1 -0
  154. package/build/config.js +52 -0
  155. package/build/config.js.map +1 -0
  156. package/build/constants.d.ts +96 -0
  157. package/build/constants.d.ts.map +1 -0
  158. package/build/constants.js +156 -0
  159. package/build/constants.js.map +1 -0
  160. package/build/crash-reporter.d.ts +18 -0
  161. package/build/crash-reporter.d.ts.map +1 -0
  162. package/build/crash-reporter.js +134 -0
  163. package/build/crash-reporter.js.map +1 -0
  164. package/build/cucumber-types.d.ts +194 -0
  165. package/build/cucumber-types.d.ts.map +1 -0
  166. package/build/cucumber-types.js +2 -0
  167. package/build/cucumber-types.js.map +1 -0
  168. package/build/data-store.d.ts +4 -0
  169. package/build/data-store.d.ts.map +1 -0
  170. package/build/data-store.js +42 -0
  171. package/build/data-store.js.map +1 -0
  172. package/build/exitHandler.d.ts +4 -0
  173. package/build/exitHandler.d.ts.map +1 -0
  174. package/build/exitHandler.js +105 -0
  175. package/build/exitHandler.js.map +1 -0
  176. package/build/fileStream.d.ts +9 -0
  177. package/build/fileStream.d.ts.map +1 -0
  178. package/build/fileStream.js +13 -0
  179. package/build/fileStream.js.map +1 -0
  180. package/build/grpc/generated/sdk-messages-accessibility.d.ts +76 -0
  181. package/build/grpc/generated/sdk-messages-accessibility.d.ts.map +1 -0
  182. package/build/grpc/generated/sdk-messages-accessibility.js +908 -0
  183. package/build/grpc/generated/sdk-messages-accessibility.js.map +1 -0
  184. package/build/grpc/generated/sdk-messages-ai.d.ts +52 -0
  185. package/build/grpc/generated/sdk-messages-ai.d.ts.map +1 -0
  186. package/build/grpc/generated/sdk-messages-ai.js +643 -0
  187. package/build/grpc/generated/sdk-messages-ai.js.map +1 -0
  188. package/build/grpc/generated/sdk-messages-observability.d.ts +44 -0
  189. package/build/grpc/generated/sdk-messages-observability.d.ts.map +1 -0
  190. package/build/grpc/generated/sdk-messages-observability.js +505 -0
  191. package/build/grpc/generated/sdk-messages-observability.js.map +1 -0
  192. package/build/grpc/generated/sdk-messages-percy.d.ts +16 -0
  193. package/build/grpc/generated/sdk-messages-percy.d.ts.map +1 -0
  194. package/build/grpc/generated/sdk-messages-percy.js +111 -0
  195. package/build/grpc/generated/sdk-messages-percy.js.map +1 -0
  196. package/build/grpc/generated/sdk-messages-testhub.d.ts +16 -0
  197. package/build/grpc/generated/sdk-messages-testhub.d.ts.map +1 -0
  198. package/build/grpc/generated/sdk-messages-testhub.js +132 -0
  199. package/build/grpc/generated/sdk-messages-testhub.js.map +1 -0
  200. package/build/grpc/generated/sdk-messages.d.ts +288 -0
  201. package/build/grpc/generated/sdk-messages.d.ts.map +1 -0
  202. package/build/grpc/generated/sdk-messages.js +3958 -0
  203. package/build/grpc/generated/sdk-messages.js.map +1 -0
  204. package/build/grpc/generated/sdk.d.ts +282 -0
  205. package/build/grpc/generated/sdk.d.ts.map +1 -0
  206. package/build/grpc/generated/sdk.js +197 -0
  207. package/build/grpc/generated/sdk.js.map +1 -0
  208. package/build/grpc/index.d.ts +43 -0
  209. package/build/grpc/index.d.ts.map +1 -0
  210. package/build/grpc/index.js +154 -0
  211. package/build/grpc/index.js.map +1 -0
  212. package/build/index.d.ts +20 -0
  213. package/build/index.d.ts.map +1 -0
  214. package/build/index.js +13 -0
  215. package/build/index.js.map +1 -0
  216. package/build/insights-handler.d.ts +76 -0
  217. package/build/insights-handler.d.ts.map +1 -0
  218. package/build/insights-handler.js +855 -0
  219. package/build/insights-handler.js.map +1 -0
  220. package/build/instrumentation/funnelInstrumentation.d.ts +8 -0
  221. package/build/instrumentation/funnelInstrumentation.d.ts.map +1 -0
  222. package/build/instrumentation/funnelInstrumentation.js +235 -0
  223. package/build/instrumentation/funnelInstrumentation.js.map +1 -0
  224. package/build/instrumentation/performance/constants.d.ts +151 -0
  225. package/build/instrumentation/performance/constants.d.ts.map +1 -0
  226. package/build/instrumentation/performance/constants.js +158 -0
  227. package/build/instrumentation/performance/constants.js.map +1 -0
  228. package/build/instrumentation/performance/performance-tester.d.ts +55 -0
  229. package/build/instrumentation/performance/performance-tester.d.ts.map +1 -0
  230. package/build/instrumentation/performance/performance-tester.js +403 -0
  231. package/build/instrumentation/performance/performance-tester.js.map +1 -0
  232. package/build/launcher.d.ts +49 -0
  233. package/build/launcher.d.ts.map +1 -0
  234. package/build/launcher.js +1077 -0
  235. package/build/launcher.js.map +1 -0
  236. package/build/log4jsAppender.d.ts +2 -0
  237. package/build/log4jsAppender.d.ts.map +1 -0
  238. package/build/log4jsAppender.js +20 -0
  239. package/build/log4jsAppender.js.map +1 -0
  240. package/build/logPatcher.d.ts +13 -0
  241. package/build/logPatcher.d.ts.map +1 -0
  242. package/build/logPatcher.js +39 -0
  243. package/build/logPatcher.js.map +1 -0
  244. package/build/logReportingAPI.d.ts +12 -0
  245. package/build/logReportingAPI.d.ts.map +1 -0
  246. package/build/logReportingAPI.js +57 -0
  247. package/build/logReportingAPI.js.map +1 -0
  248. package/build/reporter.d.ts +40 -0
  249. package/build/reporter.d.ts.map +1 -0
  250. package/build/reporter.js +254 -0
  251. package/build/reporter.js.map +1 -0
  252. package/build/request-handler.d.ts +19 -0
  253. package/build/request-handler.d.ts.map +1 -0
  254. package/build/request-handler.js +78 -0
  255. package/build/request-handler.js.map +1 -0
  256. package/build/scripts/accessibility-scripts.d.ts +26 -0
  257. package/build/scripts/accessibility-scripts.d.ts.map +1 -0
  258. package/build/scripts/accessibility-scripts.js +91 -0
  259. package/build/scripts/accessibility-scripts.js.map +1 -0
  260. package/build/service.d.ts +68 -0
  261. package/build/service.d.ts.map +1 -0
  262. package/build/service.js +740 -0
  263. package/build/service.js.map +1 -0
  264. package/build/testHub/utils.d.ts +10 -0
  265. package/build/testHub/utils.d.ts.map +1 -0
  266. package/build/testHub/utils.js +67 -0
  267. package/build/testHub/utils.js.map +1 -0
  268. package/build/testOps/featureStats.d.ts +45 -0
  269. package/build/testOps/featureStats.d.ts.map +1 -0
  270. package/build/testOps/featureStats.js +117 -0
  271. package/build/testOps/featureStats.js.map +1 -0
  272. package/build/testOps/featureUsage.d.ts +22 -0
  273. package/build/testOps/featureUsage.d.ts.map +1 -0
  274. package/build/testOps/featureUsage.js +48 -0
  275. package/build/testOps/featureUsage.js.map +1 -0
  276. package/build/testOps/listener.d.ts +40 -0
  277. package/build/testOps/listener.d.ts.map +1 -0
  278. package/build/testOps/listener.js +269 -0
  279. package/build/testOps/listener.js.map +1 -0
  280. package/build/testOps/requestUtils.d.ts +4 -0
  281. package/build/testOps/requestUtils.d.ts.map +1 -0
  282. package/build/testOps/requestUtils.js +41 -0
  283. package/build/testOps/requestUtils.js.map +1 -0
  284. package/build/testOps/testOpsConfig.d.ts +11 -0
  285. package/build/testOps/testOpsConfig.d.ts.map +1 -0
  286. package/build/testOps/testOpsConfig.js +20 -0
  287. package/build/testOps/testOpsConfig.js.map +1 -0
  288. package/build/testOps/usageStats.d.ts +404 -0
  289. package/build/testOps/usageStats.d.ts.map +1 -0
  290. package/build/testOps/usageStats.js +115 -0
  291. package/build/testOps/usageStats.js.map +1 -0
  292. package/build/testorchestration/apply-orchestration.d.ts +7 -0
  293. package/build/testorchestration/apply-orchestration.d.ts.map +1 -0
  294. package/build/testorchestration/apply-orchestration.js +43 -0
  295. package/build/testorchestration/apply-orchestration.js.map +1 -0
  296. package/build/testorchestration/helpers.d.ts +20 -0
  297. package/build/testorchestration/helpers.d.ts.map +1 -0
  298. package/build/testorchestration/helpers.js +413 -0
  299. package/build/testorchestration/helpers.js.map +1 -0
  300. package/build/testorchestration/request-utils.d.ts +23 -0
  301. package/build/testorchestration/request-utils.d.ts.map +1 -0
  302. package/build/testorchestration/request-utils.js +82 -0
  303. package/build/testorchestration/request-utils.js.map +1 -0
  304. package/build/testorchestration/test-ordering-server.d.ts +33 -0
  305. package/build/testorchestration/test-ordering-server.d.ts.map +1 -0
  306. package/build/testorchestration/test-ordering-server.js +169 -0
  307. package/build/testorchestration/test-ordering-server.js.map +1 -0
  308. package/build/testorchestration/testorcherstrationhandler.d.ts +50 -0
  309. package/build/testorchestration/testorcherstrationhandler.d.ts.map +1 -0
  310. package/build/testorchestration/testorcherstrationhandler.js +134 -0
  311. package/build/testorchestration/testorcherstrationhandler.js.map +1 -0
  312. package/build/testorchestration/testorcherstrationutils.d.ts +86 -0
  313. package/build/testorchestration/testorcherstrationutils.d.ts.map +1 -0
  314. package/build/testorchestration/testorcherstrationutils.js +380 -0
  315. package/build/testorchestration/testorcherstrationutils.js.map +1 -0
  316. package/build/types.d.ts +413 -0
  317. package/build/types.d.ts.map +1 -0
  318. package/build/types.js +2 -0
  319. package/build/types.js.map +1 -0
  320. package/build/util.d.ts +241 -0
  321. package/build/util.d.ts.map +1 -0
  322. package/build/util.js +1665 -0
  323. package/build/util.js.map +1 -0
  324. package/package.json +96 -0
  325. package/src/proto/browserstack/sdk/v1/sdk-messages-accessibility.proto +71 -0
  326. package/src/proto/browserstack/sdk/v1/sdk-messages-ai.proto +48 -0
  327. package/src/proto/browserstack/sdk/v1/sdk-messages-observability.proto +39 -0
  328. package/src/proto/browserstack/sdk/v1/sdk-messages-percy.proto +10 -0
  329. package/src/proto/browserstack/sdk/v1/sdk-messages-testhub.proto +10 -0
  330. package/src/proto/browserstack/sdk/v1/sdk-messages.proto +276 -0
  331. package/src/proto/browserstack/sdk/v1/sdk.proto +41 -0
@@ -0,0 +1,740 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import got from 'got';
8
+ import { getBrowserDescription, getBrowserCapabilities, isBrowserstackCapability, getParentSuiteName, isBrowserstackSession, patchConsoleLogs, shouldAddServiceVersion, isTrue, normalizeTestReportingConfig, normalizeTestReportingEnvVariables } from './util.js';
9
+ import InsightsHandler from './insights-handler.js';
10
+ import TestReporter from './reporter.js';
11
+ import { DEFAULT_OPTIONS, NOT_ALLOWED_KEYS_IN_CAPS, PERF_MEASUREMENT_ENV } from './constants.js';
12
+ import CrashReporter from './crash-reporter.js';
13
+ import AccessibilityHandler from './accessibility-handler.js';
14
+ import { BStackLogger } from './bstackLogger.js';
15
+ import PercyHandler from './Percy/Percy-Handler.js';
16
+ import Listener from './testOps/listener.js';
17
+ import { saveWorkerData } from './data-store.js';
18
+ import UsageStats from './testOps/usageStats.js';
19
+ import { shouldProcessEventForTesthub } from './testHub/utils.js';
20
+ import AiHandler from './ai-handler.js';
21
+ import PerformanceTester from './instrumentation/performance/performance-tester.js';
22
+ import * as PERFORMANCE_SDK_EVENTS from './instrumentation/performance/constants.js';
23
+ import { EVENTS } from './instrumentation/performance/constants.js';
24
+ import { BrowserstackCLI } from './cli/index.js';
25
+ import { TestFrameworkState } from './cli/states/testFrameworkState.js';
26
+ import { HookState } from './cli/states/hookState.js';
27
+ import { AutomationFrameworkState } from './cli/states/automationFrameworkState.js';
28
+ import TestFramework from './cli/frameworks/testFramework.js';
29
+ import { TestFrameworkConstants } from './cli/frameworks/constants/testFrameworkConstants.js';
30
+ import { AutomationFrameworkConstants } from './cli/frameworks/constants/automationFrameworkConstants.js';
31
+ import AutomationFramework from './cli/frameworks/automationFramework.js';
32
+ import util from 'node:util';
33
+ import APIUtils from './cli/apiUtils.js';
34
+ import { CLIUtils } from './cli/cliUtils.js';
35
+ export default class BrowserstackService {
36
+ _caps;
37
+ _config;
38
+ _sessionBaseUrl = `${APIUtils.BROWSERSTACK_AUTOMATE_API_URL}/automate/sessions`;
39
+ _failReasons = [];
40
+ _hookFailReasons = [];
41
+ _pureTestFailReasons = [];
42
+ _scenariosThatRan = [];
43
+ _failureStatuses = ['failed', 'ambiguous', 'undefined', 'unknown'];
44
+ _browser;
45
+ _suiteTitle;
46
+ _suiteFile;
47
+ _fullTitle;
48
+ _options;
49
+ _specsRan = false;
50
+ _observability;
51
+ _currentTest;
52
+ _insightsHandler;
53
+ _accessibility;
54
+ _accessibilityHandler;
55
+ _percy;
56
+ _percyCaptureMode = undefined;
57
+ _percyHandler;
58
+ _turboScale;
59
+ constructor(options, _caps, _config) {
60
+ this._caps = _caps;
61
+ this._config = _config;
62
+ this._options = { ...DEFAULT_OPTIONS, ...options };
63
+ // added to maintain backward compatibility with webdriverIO v5
64
+ this._config || (this._config = this._options);
65
+ normalizeTestReportingConfig(this._options);
66
+ normalizeTestReportingEnvVariables();
67
+ this._observability = this._options.testObservability;
68
+ this._accessibility = this._options.accessibility;
69
+ this._percy = isTrue(process.env.BROWSERSTACK_PERCY);
70
+ this._percyCaptureMode = process.env.BROWSERSTACK_PERCY_CAPTURE_MODE;
71
+ this._turboScale = this._options.turboScale;
72
+ PerformanceTester.startMonitoring('performance-report-service.csv');
73
+ if (shouldProcessEventForTesthub('')) {
74
+ this._config.reporters?.push(TestReporter);
75
+ }
76
+ if (process.env.BROWSERSTACK_TURBOSCALE) {
77
+ this._turboScale = process.env.BROWSERSTACK_TURBOSCALE === 'true';
78
+ }
79
+ process.env.BROWSERSTACK_TURBOSCALE_INTERNAL = String(this._turboScale);
80
+ // Cucumber specific
81
+ const strict = Boolean(this._config.cucumberOpts && this._config.cucumberOpts.strict);
82
+ // See https://github.com/cucumber/cucumber-js/blob/master/src/runtime/index.ts#L136
83
+ if (strict) {
84
+ this._failureStatuses.push('pending');
85
+ }
86
+ if (process.env.WDIO_WORKER_ID === process.env.BEST_PLATFORM_CID) {
87
+ process.env.PERCY_SNAPSHOT = 'true';
88
+ }
89
+ }
90
+ _updateCaps(fn) {
91
+ const multiRemoteCap = this._caps;
92
+ if (multiRemoteCap.capabilities) {
93
+ return Object.entries(multiRemoteCap).forEach(([, caps]) => fn(caps.capabilities));
94
+ }
95
+ return fn(this._caps);
96
+ }
97
+ async beforeSession(config, capabilities) {
98
+ PerformanceTester.start(PERFORMANCE_SDK_EVENTS.DRIVER_EVENT.INIT);
99
+ // if no user and key is specified even though a browserstack service was
100
+ // provided set user and key with values so that the session request
101
+ // will fail
102
+ const testObservabilityOptions = this._options.testObservabilityOptions;
103
+ if (!config.user && !(testObservabilityOptions && testObservabilityOptions.user)) {
104
+ config.user = 'NotSetUser';
105
+ }
106
+ if (!config.key && !(testObservabilityOptions && testObservabilityOptions.key)) {
107
+ config.key = 'NotSetKey';
108
+ }
109
+ this._config.user = config.user;
110
+ this._config.key = config.key;
111
+ try {
112
+ // Detect if multi-remote and disable CLI for those sessions
113
+ if (CLIUtils.checkCLISupportedFrameworks(this._config.framework) && process.env.BROWSERSTACK_IS_MULTIREMOTE !== 'true') {
114
+ // Connect to Browserstack CLI from worker
115
+ await BrowserstackCLI.getInstance().bootstrap(this._options, this._config);
116
+ // Get the nearest hub and update it in config
117
+ PerformanceTester.start(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_FIND_NEAREST_HUB);
118
+ const hubUrl = BrowserstackCLI.getInstance().getConfig().hubUrl;
119
+ if (hubUrl) {
120
+ this._config.hostname = new URL(hubUrl).hostname;
121
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_FIND_NEAREST_HUB);
122
+ }
123
+ else {
124
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_FIND_NEAREST_HUB, false, 'Hub URL not found');
125
+ }
126
+ }
127
+ if (BrowserstackCLI.getInstance().isRunning()) {
128
+ await BrowserstackCLI.getInstance().getAutomationFramework().trackEvent(AutomationFrameworkState.CREATE, HookState.PRE, { caps: capabilities });
129
+ const instance = AutomationFramework.getTrackedInstance();
130
+ const caps = AutomationFramework.getState(instance, AutomationFrameworkConstants.KEY_CAPABILITIES);
131
+ Object.assign(capabilities, caps);
132
+ // Strip CLI-only options that BrowserStack hub doesn't accept
133
+ const bstackOptions = capabilities['bstack:options'];
134
+ if (bstackOptions && typeof bstackOptions === 'object') {
135
+ NOT_ALLOWED_KEYS_IN_CAPS.forEach(key => delete bstackOptions[key]);
136
+ }
137
+ NOT_ALLOWED_KEYS_IN_CAPS.forEach(key => delete capabilities[`browserstack.${key}`]);
138
+ }
139
+ }
140
+ catch (err) {
141
+ BStackLogger.error(`Error while connecting to Browserstack CLI: ${err}`);
142
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.DRIVER_EVENT.INIT, false, util.format(err));
143
+ throw err;
144
+ }
145
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.DRIVER_EVENT.INIT);
146
+ // Start tracking device allocation - this measures the gap between beforeSession end and before start
147
+ // This captures the time WebDriverIO takes to create the remote session with BrowserStack
148
+ PerformanceTester.start(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_DEVICE_ALLOCATION);
149
+ BStackLogger.debug('Device allocation tracking started - waiting for WebDriverIO to create remote session');
150
+ }
151
+ async before(caps, specs, browser) {
152
+ // End device allocation tracking - remote session is now created and browser object is available
153
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_DEVICE_ALLOCATION, true, 'Device allocated and session created');
154
+ BStackLogger.debug('Device allocation tracking ended - remote session created successfully');
155
+ PerformanceTester.start(PERFORMANCE_SDK_EVENTS.DRIVER_EVENT.PRE_INITIALIZE);
156
+ // added to maintain backward compatibility with webdriverIO v5
157
+ this._browser = browser ? browser : globalThis.browser;
158
+ PerformanceTester.browser = this._browser;
159
+ // Healing Support:
160
+ if (!shouldAddServiceVersion(this._config, this._options.testObservability, caps)) {
161
+ try {
162
+ await AiHandler.selfHeal(this._options, caps, this._browser);
163
+ }
164
+ catch (err) {
165
+ if (this._options.selfHeal === true) {
166
+ BStackLogger.warn(`Error while setting up self-healing: ${err}. Disabling healing for this session.`);
167
+ }
168
+ }
169
+ }
170
+ // Ensure capabilities are not null in case of multiremote
171
+ if (this._isAppAutomate()) {
172
+ this._sessionBaseUrl = `${APIUtils.BROWSERSTACK_AA_API_CLOUD_URL}/app-automate/sessions`;
173
+ }
174
+ if (this._turboScale) {
175
+ this._sessionBaseUrl = `${APIUtils.BROWSERSTACK_AUTOMATE_API_URL}/automate-turboscale/v1/sessions`;
176
+ }
177
+ this._scenariosThatRan = [];
178
+ PerformanceTester.scenarioThatRan = [...(this._scenariosThatRan ?? [])];
179
+ if (this._browser) {
180
+ try {
181
+ const sessionId = this._browser.sessionId;
182
+ try {
183
+ this._accessibilityHandler = new AccessibilityHandler(this._browser, this._caps, this._options, this._isAppAutomate(), this._config, this._config.framework, this._accessibility, this._turboScale, this._options.accessibilityOptions);
184
+ if (isBrowserstackSession(this._browser) && BrowserstackCLI.getInstance().isRunning()) {
185
+ BStackLogger.info(`CLI is running, tracking accessibility event for before: ${sessionId}`);
186
+ // BrowserstackCLI.getInstance().getTestFramework()!.trackEvent(AutomationFrameworkState.CREATE, HookState.POST, { sessionId })
187
+ }
188
+ else {
189
+ await this._accessibilityHandler.before(sessionId);
190
+ }
191
+ Listener.setAccessibilityOptions(this._options.accessibilityOptions);
192
+ }
193
+ catch (err) {
194
+ BStackLogger.error(`[Accessibility Test Run] Error in service class before function: ${err}`);
195
+ }
196
+ if (shouldProcessEventForTesthub('')) {
197
+ patchConsoleLogs();
198
+ this._insightsHandler = new InsightsHandler(this._browser, this._config.framework, this._caps, this._options);
199
+ if (BrowserstackCLI.getInstance().isRunning()) {
200
+ await BrowserstackCLI.getInstance().getAutomationFramework().trackEvent(AutomationFrameworkState.CREATE, HookState.POST, { browser: this._browser, hubUrl: this._config.hostname });
201
+ this._insightsHandler.setGitConfigPath();
202
+ /**
203
+ * SDK-6277: register the command/result listeners in the CLI/binary flow too,
204
+ * so the user's saveScreenshot()/takeScreenshot() command result is captured and
205
+ * forwarded for screenshot-on-failure. Without this the screenshot is dropped in v8.
206
+ * (browserCommand routes the screenshot over gRPC in CLI mode — see insights-handler.)
207
+ */
208
+ // 'client:beforeCommand' only records the command synchronously — no await needed.
209
+ this._browser.on('command', (command) => {
210
+ if (shouldProcessEventForTesthub('')) {
211
+ this._insightsHandler?.browserCommand('client:beforeCommand', Object.assign(command, { sessionId }), this._currentTest);
212
+ }
213
+ });
214
+ this._browser.on('result', (result) => {
215
+ if (shouldProcessEventForTesthub('')) {
216
+ // 'client:afterCommand' is async in CLI mode (forwards the screenshot to the
217
+ // binary over gRPC). Handle the returned promise so a failed upload is logged
218
+ // rather than dropped. (o11yClassErrorHandler also routes method errors to
219
+ // processError; this .catch makes the call-site handling explicit.)
220
+ this._insightsHandler?.browserCommand('client:afterCommand', Object.assign(result, { sessionId }), this._currentTest)?.catch((err) => BStackLogger.debug(`Error forwarding afterCommand in CLI mode: ${err}`));
221
+ }
222
+ });
223
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.DRIVER_EVENT.PRE_INITIALIZE);
224
+ return;
225
+ }
226
+ await this._insightsHandler.before();
227
+ }
228
+ if (!BrowserstackCLI.getInstance().isRunning()) {
229
+ /**
230
+ * register command event
231
+ */
232
+ this._browser.on('command', async (command) => {
233
+ if (shouldProcessEventForTesthub('')) {
234
+ this._insightsHandler?.browserCommand('client:beforeCommand', Object.assign(command, { sessionId }), this._currentTest);
235
+ }
236
+ await this._percyHandler?.browserBeforeCommand(Object.assign(command, { sessionId }));
237
+ });
238
+ /**
239
+ * register result event
240
+ */
241
+ this._browser.on('result', (result) => {
242
+ if (shouldProcessEventForTesthub('')) {
243
+ this._insightsHandler?.browserCommand('client:afterCommand', Object.assign(result, { sessionId }), this._currentTest);
244
+ }
245
+ this._percyHandler?.browserAfterCommand(Object.assign(result, { sessionId }));
246
+ });
247
+ }
248
+ }
249
+ catch (err) {
250
+ BStackLogger.error(`Error in service class before function: ${err}`);
251
+ if (shouldProcessEventForTesthub('')) {
252
+ CrashReporter.uploadCrashReport(`Error in service class before function: ${err}`, err && err.stack);
253
+ }
254
+ }
255
+ if (!BrowserstackCLI.getInstance().isRunning()) {
256
+ if (this._percy) {
257
+ this._percyHandler = new PercyHandler(this._percyCaptureMode, this._browser, this._caps, this._isAppAutomate(), this._config.framework);
258
+ this._percyHandler.before();
259
+ }
260
+ }
261
+ }
262
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.DRIVER_EVENT.PRE_INITIALIZE);
263
+ PerformanceTester.start(PERFORMANCE_SDK_EVENTS.DRIVER_EVENT.POST_INITIALIZE);
264
+ const result = await this._printSessionURL();
265
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.DRIVER_EVENT.POST_INITIALIZE);
266
+ return result;
267
+ }
268
+ /**
269
+ * Set the default job name at the suite level to make sure we account
270
+ * for the cases where there is a long running `before` function for a
271
+ * suite or one that can fail.
272
+ * Don't do this for Jasmine because `suite.title` is `Jasmine__TopLevel__Suite`
273
+ * and `suite.fullTitle` is `undefined`, so no alternative to use for the job name.
274
+ */
275
+ async beforeSuite(suite) {
276
+ this._suiteTitle = suite.title;
277
+ this._insightsHandler?.setSuiteFile(suite.file);
278
+ this._accessibilityHandler?.setSuiteFile(suite.file);
279
+ if (suite.title && suite.title !== 'Jasmine__TopLevel__Suite') {
280
+ if (!BrowserstackCLI.getInstance().isRunning() || this._config.framework !== 'mocha') {
281
+ await this._setSessionName(suite.title);
282
+ }
283
+ }
284
+ }
285
+ async beforeHook(test, context) {
286
+ if (this._config.framework !== 'cucumber') {
287
+ this._currentTest = test; // not update currentTest when this is called for cucumber step
288
+ }
289
+ await this._insightsHandler?.beforeHook(test, context);
290
+ }
291
+ async afterHook(test, context, result) {
292
+ // Track hook failures separately
293
+ if (result && !result.passed) {
294
+ const hookError = (result.error && result.error.message) || 'Hook failed';
295
+ this._hookFailReasons.push(hookError);
296
+ // Still add to main failReasons for backward compatibility if ignoreHooksStatus is not enabled
297
+ if (!this._options.testObservabilityOptions?.ignoreHooksStatus) {
298
+ this._failReasons.push(hookError);
299
+ }
300
+ }
301
+ await this._insightsHandler?.afterHook(test, result);
302
+ }
303
+ async beforeTest(test) {
304
+ this._currentTest = test;
305
+ let suiteTitle = this._suiteTitle;
306
+ if (test.fullName) {
307
+ // For Jasmine, `suite.title` is `Jasmine__TopLevel__Suite`.
308
+ // This tweak allows us to set the real suite name.
309
+ const testSuiteName = test.fullName.slice(0, test.fullName.indexOf(test.description || '') - 1);
310
+ if (this._suiteTitle === 'Jasmine__TopLevel__Suite') {
311
+ suiteTitle = testSuiteName;
312
+ }
313
+ else if (this._suiteTitle) {
314
+ suiteTitle = getParentSuiteName(this._suiteTitle, testSuiteName);
315
+ }
316
+ }
317
+ await this._setAnnotation(`Test: ${test.fullName ?? test.title}`);
318
+ if (BrowserstackCLI.getInstance().isRunning()) {
319
+ await BrowserstackCLI.getInstance().getTestFramework().trackEvent(TestFrameworkState.INIT_TEST, HookState.PRE, { test });
320
+ const uuid = TestFramework.getState(TestFramework.getTrackedInstance(), TestFrameworkConstants.KEY_TEST_UUID);
321
+ this._insightsHandler?.setTestData(test, uuid);
322
+ await BrowserstackCLI.getInstance().getTestFramework().trackEvent(TestFrameworkState.TEST, HookState.PRE, { test, suiteTitle });
323
+ return;
324
+ }
325
+ await this._setSessionName(suiteTitle, test);
326
+ await this._accessibilityHandler?.beforeTest(suiteTitle, test);
327
+ await this._insightsHandler?.beforeTest(test);
328
+ }
329
+ async afterTest(test, context, results) {
330
+ this._specsRan = true;
331
+ const { error, passed } = results;
332
+ if (!passed) {
333
+ const testError = (error && error.message) || 'Unknown Error';
334
+ this._failReasons.push(testError);
335
+ // Track this as a pure test failure (not hook-related)
336
+ this._pureTestFailReasons.push(testError);
337
+ }
338
+ if (BrowserstackCLI.getInstance().isRunning()) {
339
+ await BrowserstackCLI.getInstance().getTestFramework().trackEvent(TestFrameworkState.LOG_REPORT, HookState.POST, { test, result: results });
340
+ await BrowserstackCLI.getInstance().getTestFramework().trackEvent(TestFrameworkState.TEST, HookState.POST, { test, result: results, suiteTite: this._suiteTitle });
341
+ return;
342
+ }
343
+ await this._accessibilityHandler?.afterTest(this._suiteTitle, test);
344
+ await this._insightsHandler?.afterTest(test, results);
345
+ await this._percyHandler?.afterTest();
346
+ }
347
+ async after(result) {
348
+ PerformanceTester.start(PERFORMANCE_SDK_EVENTS.HOOK_EVENTS.AFTER);
349
+ PerformanceTester.start(PERFORMANCE_SDK_EVENTS.DRIVER_EVENT.QUIT);
350
+ try {
351
+ if (BrowserstackCLI.getInstance().isRunning()) {
352
+ await BrowserstackCLI.getInstance().getAutomationFramework().trackEvent(AutomationFrameworkState.EXECUTE, HookState.POST, {});
353
+ }
354
+ const { preferScenarioName, setSessionName, setSessionStatus } = this._options;
355
+ // For Cucumber: Checks scenarios that ran (i.e. not skipped) on the session
356
+ // Only 1 Scenario ran and option enabled => Redefine session name to Scenario's name
357
+ if (preferScenarioName && this._scenariosThatRan.length === 1) {
358
+ this._fullTitle = this._scenariosThatRan.pop();
359
+ }
360
+ await PerformanceTester.measureWrapper(PERFORMANCE_SDK_EVENTS.AUTOMATE_EVENTS.SESSION_STATUS, async () => {
361
+ if (setSessionStatus && !BrowserstackCLI.getInstance().isRunning()) {
362
+ const ignoreHooksStatus = this._options.testObservabilityOptions?.ignoreHooksStatus === true;
363
+ let sessionStatus;
364
+ let failureReason;
365
+ if (result === 0 && this._specsRan) {
366
+ // Test runner reported success and tests ran
367
+ if (ignoreHooksStatus) {
368
+ // Only consider pure test failures, ignore hook failures
369
+ const hasPureTestFailures = this._pureTestFailReasons.length > 0;
370
+ sessionStatus = hasPureTestFailures ? 'failed' : 'passed';
371
+ failureReason = hasPureTestFailures ? this._pureTestFailReasons.join('\n') : undefined;
372
+ }
373
+ else {
374
+ // Default behavior: consider all failures including hooks
375
+ const hasReasons = this._failReasons.length > 0;
376
+ sessionStatus = hasReasons ? 'failed' : 'passed';
377
+ failureReason = hasReasons ? this._failReasons.join('\n') : undefined;
378
+ }
379
+ }
380
+ else if (ignoreHooksStatus && this._specsRan) {
381
+ // Test runner reported failure but ignoreHooksStatus is enabled
382
+ // Check if we only have hook failures and no pure test failures
383
+ const hasPureTestFailures = this._pureTestFailReasons.length > 0;
384
+ const hasOnlyHookFailures = this._failReasons.length === 0 && this._hookFailReasons.length > 0;
385
+ if (hasOnlyHookFailures && !hasPureTestFailures) {
386
+ // Only hook failures exist - mark as passed when ignoreHooksStatus is true
387
+ sessionStatus = 'passed';
388
+ failureReason = undefined;
389
+ }
390
+ else {
391
+ // Pure test failures exist - mark as failed
392
+ sessionStatus = 'failed';
393
+ failureReason = hasPureTestFailures ? this._pureTestFailReasons.join('\n') : undefined;
394
+ }
395
+ }
396
+ else {
397
+ // Default behavior: mark as failed (test runner reported failure or no tests ran)
398
+ sessionStatus = 'failed';
399
+ if (ignoreHooksStatus && this._pureTestFailReasons.length > 0) {
400
+ failureReason = this._pureTestFailReasons.join('\n');
401
+ }
402
+ else if (this._failReasons.length > 0) {
403
+ failureReason = this._failReasons.join('\n');
404
+ }
405
+ else {
406
+ failureReason = undefined;
407
+ }
408
+ }
409
+ BStackLogger.debug(`Setting session status to ${sessionStatus} for sessionId ${this._browser?.sessionId}, failure reason: ${failureReason}`);
410
+ await this._updateJob({
411
+ status: sessionStatus,
412
+ ...(setSessionName ? { name: this._fullTitle } : {}),
413
+ ...(failureReason ? { reason: failureReason } : {})
414
+ });
415
+ }
416
+ })();
417
+ // Track Listener cleanup
418
+ PerformanceTester.start(EVENTS.SDK_LISTENER_WORKER_END);
419
+ await Listener.getInstance().onWorkerEnd();
420
+ PerformanceTester.end(EVENTS.SDK_LISTENER_WORKER_END, true);
421
+ // Track Percy teardown (only if CLI is not running)
422
+ if (!BrowserstackCLI.getInstance().isRunning()) {
423
+ PerformanceTester.start(EVENTS.SDK_PERCY_TEARDOWN);
424
+ try {
425
+ await this._percyHandler?.teardown();
426
+ PerformanceTester.end(EVENTS.SDK_PERCY_TEARDOWN, true);
427
+ }
428
+ catch (error) {
429
+ PerformanceTester.end(EVENTS.SDK_PERCY_TEARDOWN, false, util.format(error));
430
+ }
431
+ }
432
+ // Track worker data save
433
+ PerformanceTester.start(EVENTS.SDK_WORKER_SAVE_DATA);
434
+ this.saveWorkerData();
435
+ PerformanceTester.end(EVENTS.SDK_WORKER_SAVE_DATA, true);
436
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.DRIVER_EVENT.QUIT);
437
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.HOOK_EVENTS.AFTER);
438
+ // Give the performance observer time to process the last few events
439
+ // before disconnecting in stopAndGenerate()
440
+ // await new Promise(resolve => setTimeout(resolve, 100))
441
+ // Track performance report generation (this is the big operation!)
442
+ await PerformanceTester.stopAndGenerate('performance-service.html');
443
+ if (process.env[PERF_MEASUREMENT_ENV]) {
444
+ PerformanceTester.calculateTimes([
445
+ 'onRunnerStart', 'onSuiteStart', 'onSuiteEnd',
446
+ 'onTestStart', 'onTestEnd', 'onTestSkip', 'before',
447
+ 'beforeHook', 'afterHook', 'beforeTest', 'afterTest',
448
+ 'uploadPending', 'teardown', 'browserCommand'
449
+ ]);
450
+ }
451
+ // Override process exit when we have only hook failures and ignoreHooksStatus is true
452
+ const ignoreHooksStatus = this._options.testObservabilityOptions?.ignoreHooksStatus === true;
453
+ const hasOnlyHookFailures = this._failReasons.length === 0 && this._hookFailReasons.length > 0;
454
+ const shouldOverrideResult = ignoreHooksStatus && this._specsRan && hasOnlyHookFailures;
455
+ if (shouldOverrideResult && result !== 0) {
456
+ return;
457
+ }
458
+ }
459
+ catch (error) {
460
+ BStackLogger.error(`Error in after hook: ${error}`);
461
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.DRIVER_EVENT.QUIT, false, util.format(error));
462
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.HOOK_EVENTS.AFTER, false, util.format(error));
463
+ await PerformanceTester.stopAndGenerate('performance-service.html');
464
+ }
465
+ }
466
+ /**
467
+ * For CucumberJS
468
+ */
469
+ async beforeFeature(uri, feature) {
470
+ this._suiteTitle = feature.name;
471
+ await this._setSessionName(feature.name);
472
+ await this._setAnnotation(`Feature: ${feature.name}`);
473
+ await this._insightsHandler?.beforeFeature(uri, feature);
474
+ }
475
+ /**
476
+ * Runs before a Cucumber Scenario.
477
+ * @param world world object containing information on pickle and test step
478
+ */
479
+ async beforeScenario(world) {
480
+ this._currentTest = world;
481
+ await this._accessibilityHandler?.beforeScenario(world);
482
+ await this._insightsHandler?.beforeScenario(world);
483
+ const scenarioName = world.pickle.name || 'unknown scenario';
484
+ await this._setAnnotation(`Scenario: ${scenarioName}`);
485
+ }
486
+ async afterScenario(world) {
487
+ this._specsRan = true;
488
+ const status = world.result?.status.toLowerCase();
489
+ if (status !== 'skipped') {
490
+ this._scenariosThatRan.push(world.pickle.name || 'unknown pickle name');
491
+ }
492
+ if (status && this._failureStatuses.includes(status)) {
493
+ const exception = ((world.result && world.result.message) ||
494
+ (status === 'pending'
495
+ ? `Some steps/hooks are pending for scenario "${world.pickle.name}"`
496
+ : 'Unknown Error'));
497
+ // For Cucumber with ignoreHooksStatus, check if failure is due to test steps or hooks
498
+ const ignoreHooksStatus = this._options.testObservabilityOptions?.ignoreHooksStatus === true;
499
+ if (ignoreHooksStatus && this._insightsHandler) {
500
+ // Check if any test steps failed (excluding hook failures)
501
+ const hasTestStepFailures = this._insightsHandler.hasTestStepFailures(world);
502
+ if (hasTestStepFailures) {
503
+ // Test steps failed - this is a pure test failure, add to both arrays
504
+ this._failReasons.push(exception);
505
+ this._pureTestFailReasons.push(exception);
506
+ }
507
+ // If no test steps failed, this is likely a hook-only failure - don't add to main failure arrays
508
+ }
509
+ else {
510
+ // Default behavior: treat all scenario failures as test failures
511
+ this._failReasons.push(exception);
512
+ this._pureTestFailReasons.push(exception);
513
+ }
514
+ }
515
+ await this._accessibilityHandler?.afterScenario(world);
516
+ await this._insightsHandler?.afterScenario(world);
517
+ if (!BrowserstackCLI.getInstance().isRunning()) {
518
+ await this._percyHandler?.afterScenario();
519
+ }
520
+ }
521
+ async beforeStep(step, scenario) {
522
+ await this._insightsHandler?.beforeStep(step, scenario);
523
+ await this._setAnnotation(`Step: ${step.keyword}${step.text}`);
524
+ }
525
+ async afterStep(step, scenario, result) {
526
+ await this._insightsHandler?.afterStep(step, scenario, result);
527
+ }
528
+ async onReload(oldSessionId, newSessionId) {
529
+ if (!this._browser) {
530
+ return Promise.resolve();
531
+ }
532
+ const { setSessionName, setSessionStatus } = this._options;
533
+ const ignoreHooksStatus = this._options.testObservabilityOptions?.ignoreHooksStatus === true;
534
+ let sessionStatus;
535
+ let failureReason;
536
+ if (ignoreHooksStatus) {
537
+ // Only consider pure test failures, ignore hook failures
538
+ const hasPureTestFailures = this._pureTestFailReasons.length > 0;
539
+ sessionStatus = hasPureTestFailures ? 'failed' : 'passed';
540
+ failureReason = hasPureTestFailures ? this._pureTestFailReasons.join('\n') : undefined;
541
+ }
542
+ else {
543
+ // Default behavior: consider all failures including hooks
544
+ const hasReasons = this._failReasons.length > 0;
545
+ sessionStatus = hasReasons ? 'failed' : 'passed';
546
+ failureReason = hasReasons ? this._failReasons.join('\n') : undefined;
547
+ }
548
+ if (!this._browser.isMultiremote) {
549
+ BStackLogger.info(`Update (reloaded) job with sessionId ${oldSessionId}, ${sessionStatus}`);
550
+ }
551
+ else {
552
+ const browserName = this._browser.instances.filter((browserName) => this._browser && this._browser.getInstance(browserName).sessionId === newSessionId)[0];
553
+ BStackLogger.info(`Update (reloaded) multiremote job for browser "${browserName}" and sessionId ${oldSessionId}, ${sessionStatus}`);
554
+ }
555
+ if (setSessionStatus) {
556
+ await this._update(oldSessionId, {
557
+ status: sessionStatus,
558
+ ...(setSessionName ? { name: this._fullTitle } : {}),
559
+ ...(failureReason ? { reason: failureReason } : {})
560
+ });
561
+ }
562
+ BStackLogger.warn(`Session Reloaded: Old Session Id: ${oldSessionId}, New Session Id: ${newSessionId}`);
563
+ await this._insightsHandler?.sendCBTInfo();
564
+ this._scenariosThatRan = [];
565
+ delete this._fullTitle;
566
+ delete this._suiteFile;
567
+ this._failReasons = [];
568
+ this._hookFailReasons = [];
569
+ this._pureTestFailReasons = [];
570
+ await this._printSessionURL();
571
+ }
572
+ _isAppAutomate() {
573
+ const browserDesiredCapabilities = (this._browser?.capabilities ?? {});
574
+ const desiredCapabilities = (this._caps ?? {});
575
+ return !!browserDesiredCapabilities['appium:app'] || !!desiredCapabilities['appium:app'] || !!(desiredCapabilities['appium:options']?.app);
576
+ }
577
+ _updateJob(requestBody) {
578
+ return this._multiRemoteAction((sessionId, browserName) => {
579
+ BStackLogger.info(browserName
580
+ ? `Update multiremote job for browser "${browserName}" and sessionId ${sessionId}`
581
+ : `Update job with sessionId ${sessionId}`);
582
+ return this._update(sessionId, requestBody);
583
+ });
584
+ }
585
+ _multiRemoteAction(action) {
586
+ if (!this._browser) {
587
+ return Promise.resolve();
588
+ }
589
+ if (!this._browser.isMultiremote) {
590
+ return action(this._browser.sessionId);
591
+ }
592
+ const multiremotebrowser = this._browser;
593
+ return Promise.all(multiremotebrowser.instances
594
+ .filter((browserName) => {
595
+ const cap = getBrowserCapabilities(multiremotebrowser, this._caps, browserName);
596
+ return isBrowserstackCapability(cap);
597
+ })
598
+ .map((browserName) => (action(multiremotebrowser.getInstance(browserName).sessionId, browserName))));
599
+ }
600
+ _update(sessionId, requestBody) {
601
+ if (!isBrowserstackSession(this._browser)) {
602
+ return Promise.resolve();
603
+ }
604
+ const sessionUrl = `${this._sessionBaseUrl}/${sessionId}.json`;
605
+ BStackLogger.debug(`Updating Browserstack session at ${sessionUrl} with request body: `, requestBody);
606
+ if (this._turboScale) {
607
+ return got.patch(sessionUrl, {
608
+ json: requestBody,
609
+ username: this._config.user,
610
+ password: this._config.key
611
+ });
612
+ }
613
+ return got.put(sessionUrl, {
614
+ json: requestBody,
615
+ username: this._config.user,
616
+ password: this._config.key
617
+ });
618
+ }
619
+ async _printSessionURL() {
620
+ if (!this._browser || !isBrowserstackSession(this._browser)) {
621
+ return Promise.resolve();
622
+ }
623
+ await this._multiRemoteAction(async (sessionId, browserName) => {
624
+ const sessionUrl = `${this._sessionBaseUrl}/${sessionId}.json`;
625
+ BStackLogger.debug(`Requesting Browserstack session URL at ${sessionUrl}`);
626
+ let browserUrl;
627
+ const reqOpts = {
628
+ username: this._config.user,
629
+ password: this._config.key,
630
+ responseType: 'json'
631
+ };
632
+ if (this._turboScale) {
633
+ const response = await got(sessionUrl, reqOpts);
634
+ browserUrl = response.body.url;
635
+ }
636
+ else {
637
+ const response = await got(sessionUrl, reqOpts);
638
+ browserUrl = response.body.automation_session.browser_url;
639
+ }
640
+ if (!this._browser) {
641
+ return;
642
+ }
643
+ const capabilities = getBrowserCapabilities(this._browser, this._caps, browserName);
644
+ const browserString = getBrowserDescription(capabilities);
645
+ BStackLogger.info(`${browserString} session: ${browserUrl}`);
646
+ });
647
+ }
648
+ async _setSessionName(suiteTitle, test) {
649
+ if (!this._options.setSessionName || !suiteTitle) {
650
+ return;
651
+ }
652
+ let name = suiteTitle;
653
+ if (this._options.sessionNameFormat) {
654
+ name = this._options.sessionNameFormat(this._config, this._caps, suiteTitle, test?.title);
655
+ }
656
+ else if (test && !test.fullName && this._config.framework !== 'jasmine') {
657
+ // Mocha
658
+ const pre = this._options.sessionNamePrependTopLevelSuiteTitle ? `${suiteTitle} - ` : '';
659
+ const post = !this._options.sessionNameOmitTestTitle ? ` - ${test.title}` : '';
660
+ name = `${pre}${test.parent}${post}`;
661
+ }
662
+ else if (this._config.framework === 'jasmine') {
663
+ // Jasmine
664
+ name = this._caps?.['bstack:options']?.sessionName;
665
+ }
666
+ if (!BrowserstackCLI.getInstance().isRunning()) {
667
+ this._percyHandler?._setSessionName(name);
668
+ }
669
+ if (name !== this._fullTitle) {
670
+ this._fullTitle = name;
671
+ await this._updateJob({ name });
672
+ }
673
+ }
674
+ _setAnnotation(data) {
675
+ return this._executeCommand('annotate', { data, level: 'info' });
676
+ }
677
+ async _executeCommand(action, args) {
678
+ if (!this._browser || !isBrowserstackSession(this._browser)) {
679
+ return Promise.resolve();
680
+ }
681
+ const cmd = { action, ...(args ? { arguments: args } : {}) };
682
+ const script = `browserstack_executor: ${JSON.stringify(cmd)}`;
683
+ if (this._browser.isMultiremote) {
684
+ const multiRemoteBrowser = this._browser;
685
+ return Promise.all(Object.keys(this._caps).map(async (browserName) => {
686
+ const browser = multiRemoteBrowser.getInstance(browserName);
687
+ return (await browser.execute(script));
688
+ }));
689
+ }
690
+ return (await this._browser.execute(script));
691
+ }
692
+ saveWorkerData() {
693
+ saveWorkerData({
694
+ usageStats: UsageStats.getInstance().getDataToSave()
695
+ });
696
+ }
697
+ }
698
+ __decorate([
699
+ PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_HOOK, { hookType: 'beforeSession' })
700
+ ], BrowserstackService.prototype, "beforeSession", null);
701
+ __decorate([
702
+ PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_HOOK, { hookType: 'before' })
703
+ ], BrowserstackService.prototype, "before", null);
704
+ __decorate([
705
+ PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_HOOK, { hookType: 'beforeSuite' })
706
+ ], BrowserstackService.prototype, "beforeSuite", null);
707
+ __decorate([
708
+ PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_HOOK, { hookType: 'beforeHook' })
709
+ ], BrowserstackService.prototype, "beforeHook", null);
710
+ __decorate([
711
+ PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_HOOK, { hookType: 'afterHook' })
712
+ ], BrowserstackService.prototype, "afterHook", null);
713
+ __decorate([
714
+ PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_HOOK, { hookType: 'beforeTest' })
715
+ ], BrowserstackService.prototype, "beforeTest", null);
716
+ __decorate([
717
+ PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_HOOK, { hookType: 'afterTest' })
718
+ ], BrowserstackService.prototype, "afterTest", null);
719
+ __decorate([
720
+ PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_HOOK, { hookType: 'beforeFeature' })
721
+ ], BrowserstackService.prototype, "beforeFeature", null);
722
+ __decorate([
723
+ PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_HOOK, { hookType: 'beforeScenario' })
724
+ ], BrowserstackService.prototype, "beforeScenario", null);
725
+ __decorate([
726
+ PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_HOOK, { hookType: 'afterScenario' })
727
+ ], BrowserstackService.prototype, "afterScenario", null);
728
+ __decorate([
729
+ PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_HOOK, { hookType: 'beforeStep' })
730
+ ], BrowserstackService.prototype, "beforeStep", null);
731
+ __decorate([
732
+ PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_HOOK, { hookType: 'afterStep' })
733
+ ], BrowserstackService.prototype, "afterStep", null);
734
+ __decorate([
735
+ PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_HOOK, { hookType: 'onReload' })
736
+ ], BrowserstackService.prototype, "onReload", null);
737
+ __decorate([
738
+ PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.AUTOMATE_EVENTS.PRINT_BUILDLINK)
739
+ ], BrowserstackService.prototype, "_printSessionURL", null);
740
+ //# sourceMappingURL=service.js.map