@wdio/browserstack-service 9.2.8 → 9.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -9,7 +9,7 @@ import { v4 as uuidv4 } from "uuid";
9
9
  import fs11 from "node:fs";
10
10
  import { readFile } from "node:fs/promises";
11
11
  import path11 from "node:path";
12
- import { promisify as promisify2, format } from "node:util";
12
+ import { promisify as promisify2, format as format3 } from "node:util";
13
13
  import { performance as performance2, PerformanceObserver as PerformanceObserver2 } from "node:perf_hooks";
14
14
  import os5 from "node:os";
15
15
  import { SevereServiceError } from "webdriverio";
@@ -24,7 +24,7 @@ import { performance, PerformanceObserver } from "node:perf_hooks";
24
24
  import { hostname, platform, type, version, arch } from "node:os";
25
25
  import fs3 from "node:fs";
26
26
  import zlib from "node:zlib";
27
- import { promisify } from "node:util";
27
+ import { format, promisify } from "node:util";
28
28
  import path3 from "node:path";
29
29
  import util from "node:util";
30
30
  import gitRepoInfo from "git-repo-info";
@@ -78,7 +78,7 @@ var logPatcher_default = logPatcher;
78
78
  // package.json
79
79
  var package_default = {
80
80
  name: "@wdio/browserstack-service",
81
- version: "9.2.6",
81
+ version: "9.2.11",
82
82
  description: "WebdriverIO service for better Browserstack integration",
83
83
  author: "Adam Bjerstedt <abjerstedt@gmail.com>",
84
84
  homepage: "https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-browserstack-service",
@@ -174,7 +174,6 @@ var DATA_BATCH_INTERVAL = 2e3;
174
174
  var DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS = 5e3;
175
175
  var DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS = 100;
176
176
  var BSTACK_SERVICE_VERSION = bstackServiceVersion;
177
- var ACCESSIBILITY_API_URL = "https://accessibility.browserstack.com/api";
178
177
  var NOT_ALLOWED_KEYS_IN_CAPS = ["includeTagsInTestingScope", "excludeTagsInTestingScope"];
179
178
  var LOGS_FILE = "logs/bstack-wdio-service.log";
180
179
  var UPLOAD_LOGS_ADDRESS = "https://upload-observability.browserstack.com";
@@ -203,14 +202,18 @@ var TCG_INFO = {
203
202
  tcgRegion: "use",
204
203
  tcgUrl: TCG_URL
205
204
  };
206
- var TESTOPS_JWT_ENV = "BS_TESTOPS_JWT";
205
+ var BROWSERSTACK_TESTHUB_JWT = "BROWSERSTACK_TESTHUB_JWT";
207
206
  var BSTACK_TCG_AUTH_RESULT = "BSTACK_TCG_AUTH_RESULT";
208
207
  var TESTOPS_SCREENSHOT_ENV = "BS_TESTOPS_ALLOW_SCREENSHOTS";
209
- var TESTOPS_BUILD_ID_ENV = "BS_TESTOPS_BUILD_HASHED_ID";
208
+ var BROWSERSTACK_TESTHUB_UUID = "BROWSERSTACK_TESTHUB_UUID";
209
+ var TEST_ANALYTICS_ID = "TEST_ANALYTICS_ID";
210
210
  var PERF_MEASUREMENT_ENV = "BROWSERSTACK_O11Y_PERF_MEASUREMENT";
211
211
  var RERUN_TESTS_ENV = "BROWSERSTACK_RERUN_TESTS";
212
212
  var RERUN_ENV = "BROWSERSTACK_RERUN";
213
213
  var TESTOPS_BUILD_COMPLETED_ENV = "BS_TESTOPS_BUILD_COMPLETED";
214
+ var BROWSERSTACK_PERCY = "BROWSERSTACK_PERCY";
215
+ var BROWSERSTACK_ACCESSIBILITY = "BROWSERSTACK_ACCESSIBILITY";
216
+ var BROWSERSTACK_OBSERVABILITY = "BROWSERSTACK_OBSERVABILITY";
214
217
  var MAX_GIT_META_DATA_SIZE_IN_BYTES = 64 * 1024;
215
218
  var GIT_META_DATA_TRUNCATED = "...[TRUNCATED]";
216
219
 
@@ -283,6 +286,62 @@ var BStackLogger = class {
283
286
  }
284
287
  };
285
288
 
289
+ // src/testHub/utils.ts
290
+ var getProductMap = (config) => {
291
+ return {
292
+ "observability": config.testObservability.enabled,
293
+ "accessibility": config.accessibility,
294
+ "percy": config.percy,
295
+ "automate": config.automate,
296
+ "app_automate": config.appAutomate
297
+ };
298
+ };
299
+ var shouldProcessEventForTesthub = (eventType) => {
300
+ if (isTrue(process.env[BROWSERSTACK_OBSERVABILITY])) {
301
+ return true;
302
+ }
303
+ if (isTrue(process.env[BROWSERSTACK_ACCESSIBILITY])) {
304
+ return !["HookRunStarted", "HookRunFinished", "LogCreated"].includes(eventType);
305
+ }
306
+ if (isTrue(process.env[BROWSERSTACK_PERCY]) && eventType) {
307
+ return false;
308
+ }
309
+ return Boolean(process.env[BROWSERSTACK_ACCESSIBILITY] || process.env[BROWSERSTACK_OBSERVABILITY] || process.env[BROWSERSTACK_PERCY]);
310
+ };
311
+ var handleErrorForObservability = (error) => {
312
+ process.env[BROWSERSTACK_OBSERVABILITY] = "false";
313
+ logBuildError(error, "observability");
314
+ };
315
+ var handleErrorForAccessibility = (error) => {
316
+ process.env[BROWSERSTACK_ACCESSIBILITY] = "false";
317
+ logBuildError(error, "accessibility");
318
+ };
319
+ var logBuildError = (error, product = "") => {
320
+ if (!error || !error.errors) {
321
+ BStackLogger.error(`${product.toUpperCase()} Build creation failed ${error}`);
322
+ return;
323
+ }
324
+ for (const errorJson of error.errors) {
325
+ const errorType = errorJson.key;
326
+ const errorMessage = errorJson.message;
327
+ if (errorMessage) {
328
+ switch (errorType) {
329
+ case "ERROR_INVALID_CREDENTIALS":
330
+ BStackLogger.error(errorMessage);
331
+ break;
332
+ case "ERROR_ACCESS_DENIED":
333
+ BStackLogger.info(errorMessage);
334
+ break;
335
+ case "ERROR_SDK_DEPRECATED":
336
+ BStackLogger.error(errorMessage);
337
+ break;
338
+ default:
339
+ BStackLogger.error(errorMessage);
340
+ }
341
+ }
342
+ }
343
+ };
344
+
286
345
  // src/crash-reporter.ts
287
346
  var CrashReporter = class {
288
347
  /* User test config for build run minus PII */
@@ -332,7 +391,7 @@ var CrashReporter = class {
332
391
  this.userConfigForReporting = {};
333
392
  }
334
393
  const data = {
335
- hashed_id: process.env[TESTOPS_BUILD_ID_ENV],
394
+ hashed_id: process.env[BROWSERSTACK_TESTHUB_UUID],
336
395
  observability_version: {
337
396
  frameworkName: "WebdriverIO-" + (this.userConfigForReporting.framework || "null"),
338
397
  sdkVersion: BSTACK_SERVICE_VERSION
@@ -859,20 +918,6 @@ function o11yErrorHandler(fn) {
859
918
  }
860
919
  };
861
920
  }
862
- function errorHandler(fn) {
863
- return function(...args) {
864
- try {
865
- const functionToHandle = fn;
866
- const result = functionToHandle(...args);
867
- if (result instanceof Promise) {
868
- return result.catch((error) => BStackLogger.error(`Error in executing ${fn.name} with args ${args}: ${error}`));
869
- }
870
- return result;
871
- } catch (error) {
872
- BStackLogger.error(`Error in executing ${fn.name} with args ${args}: ${error}`);
873
- }
874
- };
875
- }
876
921
  async function nodeRequest(requestType, apiEndpoint, options, apiUrl, timeout = 12e4) {
877
922
  try {
878
923
  const controller = new AbortController();
@@ -885,6 +930,7 @@ async function nodeRequest(requestType, apiEndpoint, options, apiUrl, timeout =
885
930
  clearTimeout(timeoutId);
886
931
  return await response.json();
887
932
  } catch (error) {
933
+ BStackLogger.debug(`Error in firing request ${apiUrl}/${apiEndpoint}: ${format(error)}`);
888
934
  const isLogUpload = apiEndpoint === UPLOAD_LOGS_ENDPOINT;
889
935
  if (error && error.response) {
890
936
  const errorMessageJson = error.response.body ? JSON.parse(error.response.body.toString()) : null;
@@ -934,7 +980,65 @@ function o11yClassErrorHandler(errorClass) {
934
980
  });
935
981
  return errorClass;
936
982
  }
937
- var launchTestSession = o11yErrorHandler(async function launchTestSession2(options, config, bsConfig) {
983
+ var processTestObservabilityResponse = (response) => {
984
+ if (!response.observability) {
985
+ handleErrorForObservability(null);
986
+ return;
987
+ }
988
+ if (!response.observability.success) {
989
+ handleErrorForObservability(response.observability);
990
+ return;
991
+ }
992
+ process.env[BROWSERSTACK_OBSERVABILITY] = "true";
993
+ if (response.observability.options.allow_screenshots) {
994
+ process.env[TESTOPS_SCREENSHOT_ENV] = response.observability.options.allow_screenshots.toString();
995
+ }
996
+ };
997
+ var jsonifyAccessibilityArray = (dataArray, keyName, valueName) => {
998
+ const result = {};
999
+ dataArray.forEach((element) => {
1000
+ result[element[keyName]] = element[valueName];
1001
+ });
1002
+ return result;
1003
+ };
1004
+ var processAccessibilityResponse = (response) => {
1005
+ if (!response.accessibility) {
1006
+ handleErrorForAccessibility(null);
1007
+ return;
1008
+ }
1009
+ if (!response.accessibility.success) {
1010
+ handleErrorForAccessibility(response.accessibility);
1011
+ return;
1012
+ }
1013
+ if (response.accessibility.options) {
1014
+ const { accessibilityToken, scannerVersion } = jsonifyAccessibilityArray(response.accessibility.options.capabilities, "name", "value");
1015
+ const scriptsJson = {
1016
+ "scripts": jsonifyAccessibilityArray(response.accessibility.options.scripts, "name", "command"),
1017
+ "commands": response.accessibility.options.commandsToWrap.commands
1018
+ };
1019
+ if (scannerVersion) {
1020
+ process.env.BSTACK_A11Y_SCANNER_VERSION = scannerVersion;
1021
+ }
1022
+ BStackLogger.debug(`Accessibility scannerVersion ${scannerVersion}`);
1023
+ if (accessibilityToken) {
1024
+ process.env.BSTACK_A11Y_JWT = accessibilityToken;
1025
+ process.env[BROWSERSTACK_ACCESSIBILITY] = "true";
1026
+ }
1027
+ if (scriptsJson) {
1028
+ accessibility_scripts_default.update(scriptsJson);
1029
+ accessibility_scripts_default.store();
1030
+ }
1031
+ }
1032
+ };
1033
+ var processLaunchBuildResponse = (response, options) => {
1034
+ if (options.testObservability) {
1035
+ processTestObservabilityResponse(response);
1036
+ }
1037
+ if (options.accessibility) {
1038
+ processAccessibilityResponse(response);
1039
+ }
1040
+ };
1041
+ var launchTestSession = o11yErrorHandler(async function launchTestSession2(options, config, bsConfig, bStackConfig) {
938
1042
  const launchBuildUsage = usageStats_default.getInstance().launchBuildUsage;
939
1043
  launchBuildUsage.triggered();
940
1044
  const data = {
@@ -942,7 +1046,7 @@ var launchTestSession = o11yErrorHandler(async function launchTestSession2(optio
942
1046
  project_name: getObservabilityProject(options, bsConfig.projectName),
943
1047
  name: getObservabilityBuild(options, bsConfig.buildName),
944
1048
  build_identifier: bsConfig.buildIdentifier,
945
- start_time: (/* @__PURE__ */ new Date()).toISOString(),
1049
+ started_at: (/* @__PURE__ */ new Date()).toISOString(),
946
1050
  tags: getObservabilityBuildTags(options, bsConfig.buildTag),
947
1051
  host_info: {
948
1052
  hostname: hostname(),
@@ -955,10 +1059,21 @@ var launchTestSession = o11yErrorHandler(async function launchTestSession2(optio
955
1059
  build_run_identifier: process.env.BROWSERSTACK_BUILD_RUN_IDENTIFIER,
956
1060
  failed_tests_rerun: process.env[RERUN_ENV] || false,
957
1061
  version_control: await getGitMetaData(),
958
- observability_version: {
1062
+ accessibility: {
1063
+ settings: options.accessibilityOptions
1064
+ },
1065
+ browserstackAutomation: shouldAddServiceVersion(config, options.testObservability),
1066
+ framework_details: {
959
1067
  frameworkName: "WebdriverIO-" + config.framework,
960
- sdkVersion: bsConfig.bstackServiceVersion
1068
+ frameworkVersion: bsConfig.bstackServiceVersion,
1069
+ sdkVersion: bsConfig.bstackServiceVersion,
1070
+ language: "ECMAScript",
1071
+ testFramework: {
1072
+ name: "WebdriverIO",
1073
+ version: bsConfig.bstackServiceVersion
1074
+ }
961
1075
  },
1076
+ product_map: getProductMap(bStackConfig),
962
1077
  config: {}
963
1078
  };
964
1079
  try {
@@ -970,7 +1085,7 @@ var launchTestSession = o11yErrorHandler(async function launchTestSession2(optio
970
1085
  }
971
1086
  data.config = CrashReporter.userConfigForReporting;
972
1087
  try {
973
- const url3 = `${DATA_ENDPOINT}/api/v1/builds`;
1088
+ const url3 = `${DATA_ENDPOINT}/api/v2/builds`;
974
1089
  const encodedAuth = Buffer.from(`${getObservabilityUser(options, config)}:${getObservabilityKey(options, config)}`, "utf8").toString("base64");
975
1090
  const headers = {
976
1091
  ...DEFAULT_REQUEST_CONFIG.headers,
@@ -985,36 +1100,20 @@ var launchTestSession = o11yErrorHandler(async function launchTestSession2(optio
985
1100
  BStackLogger.debug(`[Start_Build] Success response: ${JSON.stringify(jsonResponse)}`);
986
1101
  process.env[TESTOPS_BUILD_COMPLETED_ENV] = "true";
987
1102
  if (jsonResponse.jwt) {
988
- process.env[TESTOPS_JWT_ENV] = jsonResponse.jwt;
989
- launchBuildUsage.success();
1103
+ process.env[BROWSERSTACK_TESTHUB_JWT] = jsonResponse.jwt;
990
1104
  }
991
1105
  if (jsonResponse.build_hashed_id) {
992
- process.env[TESTOPS_BUILD_ID_ENV] = jsonResponse.build_hashed_id;
1106
+ process.env[BROWSERSTACK_TESTHUB_UUID] = jsonResponse.build_hashed_id;
993
1107
  testOpsConfig_default.getInstance().buildHashedId = jsonResponse.build_hashed_id;
994
1108
  }
995
- if (jsonResponse.allow_screenshots) {
996
- process.env[TESTOPS_SCREENSHOT_ENV] = jsonResponse.allow_screenshots.toString();
997
- }
1109
+ processLaunchBuildResponse(jsonResponse, options);
1110
+ launchBuildUsage.success();
998
1111
  } catch (error) {
999
- launchBuildUsage.failed(error);
1000
- if (error && error.response) {
1001
- const errorMessageJson = error.response.body ? JSON.parse(error.response.body.toString()) : null;
1002
- const errorMessage = errorMessageJson ? errorMessageJson.message : null, errorType = errorMessageJson ? errorMessageJson.errorType : null;
1003
- switch (errorType) {
1004
- case "ERROR_INVALID_CREDENTIALS":
1005
- BStackLogger.error(errorMessage);
1006
- break;
1007
- case "ERROR_ACCESS_DENIED":
1008
- BStackLogger.info(errorMessage);
1009
- break;
1010
- case "ERROR_SDK_DEPRECATED":
1011
- BStackLogger.error(errorMessage);
1012
- break;
1013
- default:
1014
- BStackLogger.error(errorMessage);
1015
- }
1016
- } else {
1017
- BStackLogger.error(`Data upload to BrowserStack Test Observability failed due to ${error}. Cause : ${error.cause}`);
1112
+ BStackLogger.debug(`TestHub build start failed: ${format(error)}`);
1113
+ if (!error.success) {
1114
+ launchBuildUsage.failed(error);
1115
+ logBuildError(error);
1116
+ return;
1018
1117
  }
1019
1118
  }
1020
1119
  });
@@ -1072,90 +1171,6 @@ var isAccessibilityAutomationSession = (accessibilityFlag) => {
1072
1171
  }
1073
1172
  return false;
1074
1173
  };
1075
- var createAccessibilityTestRun = errorHandler(async function createAccessibilityTestRun2(options, config, bsConfig) {
1076
- const userName = getBrowserStackUser(config);
1077
- const accessKey = getBrowserStackKey(config);
1078
- if (isUndefined(userName) || isUndefined(accessKey)) {
1079
- BStackLogger.error("Exception while creating test run for BrowserStack Accessibility Automation: Missing BrowserStack credentials");
1080
- return null;
1081
- }
1082
- const data = {
1083
- "projectName": bsConfig.projectName,
1084
- "buildName": bsConfig.buildName || path3.basename(path3.resolve(process.cwd())),
1085
- "startTime": (/* @__PURE__ */ new Date()).toISOString(),
1086
- "description": "",
1087
- "source": {
1088
- frameworkName: "WebdriverIO-" + config.framework,
1089
- frameworkVersion: bsConfig.bstackServiceVersion,
1090
- sdkVersion: bsConfig.bstackServiceVersion,
1091
- language: "ECMAScript",
1092
- testFramework: "webdriverIO",
1093
- testFrameworkVersion: bsConfig.bstackServiceVersion
1094
- },
1095
- "settings": bsConfig.accessibilityOptions || {},
1096
- "versionControl": await getGitMetaData(),
1097
- "ciInfo": getCiInfo(),
1098
- "hostInfo": {
1099
- hostname: hostname(),
1100
- platform: platform(),
1101
- type: type(),
1102
- version: version(),
1103
- arch: arch()
1104
- },
1105
- "browserstackAutomation": true
1106
- };
1107
- const encodedAuth = Buffer.from(`${getBrowserStackUser(config)}:${getBrowserStackKey(config)}`, "utf8").toString("base64");
1108
- const headers = {
1109
- "Content-Type": "application/json; charset=utf-8",
1110
- Authorization: `Basic ${encodedAuth}`
1111
- };
1112
- const requestOptions = {
1113
- body: JSON.stringify(data),
1114
- headers
1115
- };
1116
- try {
1117
- const response = await nodeRequest(
1118
- "POST",
1119
- "v2/test_runs",
1120
- requestOptions,
1121
- ACCESSIBILITY_API_URL
1122
- );
1123
- BStackLogger.debug(`[Create Accessibility Test Run] Success response: ${JSON.stringify(response)}`);
1124
- if (response.data.accessibilityToken) {
1125
- process.env.BSTACK_A11Y_JWT = response.data.accessibilityToken;
1126
- }
1127
- if (response.data.id) {
1128
- process.env.BS_A11Y_TEST_RUN_ID = response.data.id;
1129
- }
1130
- BStackLogger.debug(`BrowserStack Accessibility Automation Test Run ID: ${response.data.id}`);
1131
- if (response.data) {
1132
- accessibility_scripts_default.update(response.data);
1133
- accessibility_scripts_default.store();
1134
- }
1135
- return response.data.scannerVersion;
1136
- } catch (error) {
1137
- if (error.response) {
1138
- BStackLogger.error(
1139
- `Exception while creating test run for BrowserStack Accessibility Automation: ${error.response.status} ${error.response.statusText} ${JSON.stringify(error.response.data)}`
1140
- );
1141
- } else {
1142
- const errorMessage = error.message;
1143
- if (errorMessage === "Invalid configuration passed.") {
1144
- BStackLogger.error(
1145
- `Exception while creating test run for BrowserStack Accessibility Automation: ${errorMessage || error.stack}`
1146
- );
1147
- for (const errorkey of error.errors) {
1148
- BStackLogger.error(errorkey.message);
1149
- }
1150
- } else {
1151
- BStackLogger.error(
1152
- `Exception while creating test run for BrowserStack Accessibility Automation: ${errorMessage || error.stack}`
1153
- );
1154
- }
1155
- }
1156
- return null;
1157
- }
1158
- });
1159
1174
  var performA11yScan = async (browser, isBrowserStackSession, isAccessibility, commandName) => {
1160
1175
  if (!isBrowserStackSession) {
1161
1176
  BStackLogger.warn("Not a BrowserStack Automate session, cannot perform Accessibility scan.");
@@ -1211,50 +1226,6 @@ var getA11yResultsSummary = async (browser, isBrowserStackSession, isAccessibili
1211
1226
  return {};
1212
1227
  }
1213
1228
  };
1214
- var stopAccessibilityTestRun = errorHandler(async function stopAccessibilityTestRun2() {
1215
- const hasA11yJwtToken = typeof process.env.BSTACK_A11Y_JWT === "string" && process.env.BSTACK_A11Y_JWT.length > 0 && process.env.BSTACK_A11Y_JWT !== "null" && process.env.BSTACK_A11Y_JWT !== "undefined";
1216
- if (!hasA11yJwtToken) {
1217
- return {
1218
- status: "error",
1219
- message: "Build creation had failed."
1220
- };
1221
- }
1222
- const data = {
1223
- "endTime": (/* @__PURE__ */ new Date()).toISOString()
1224
- };
1225
- const requestOptions = { ...{
1226
- json: data,
1227
- headers: {
1228
- "Authorization": `Bearer ${process.env.BSTACK_A11Y_JWT}`
1229
- }
1230
- } };
1231
- try {
1232
- const response = await nodeRequest(
1233
- "PUT",
1234
- "test_runs/stop",
1235
- requestOptions,
1236
- ACCESSIBILITY_API_URL
1237
- );
1238
- if (response.data && response.data.error) {
1239
- throw new Error("Invalid request: " + response.data.error);
1240
- } else if (response.error) {
1241
- throw new Error("Invalid request: " + response.error);
1242
- } else {
1243
- BStackLogger.info(`BrowserStack Accessibility Automation Test Run marked as completed at ${(/* @__PURE__ */ new Date()).toISOString()}`);
1244
- return { status: "success", message: "" };
1245
- }
1246
- } catch (error) {
1247
- if (error.response && error.response.status && error.response.statusText && error.response.data) {
1248
- BStackLogger.error(`Exception while marking completion of BrowserStack Accessibility Automation Test Run: ${error.response.status} ${error.response.statusText} ${JSON.stringify(error.response.data)}`);
1249
- } else {
1250
- BStackLogger.error(`Exception while marking completion of BrowserStack Accessibility Automation Test Run: ${error.message || util.format(error)}`);
1251
- }
1252
- return {
1253
- status: "error",
1254
- message: error.message || (error.response ? `${error.response.status}:${error.response.statusText}` : error)
1255
- };
1256
- }
1257
- });
1258
1229
  var stopBuildUpstream = o11yErrorHandler(async function stopBuildUpstream2() {
1259
1230
  const stopBuildUsage = usageStats_default.getInstance().stopBuildUsage;
1260
1231
  stopBuildUsage.triggered();
@@ -1265,7 +1236,7 @@ var stopBuildUpstream = o11yErrorHandler(async function stopBuildUpstream2() {
1265
1236
  message: "Build is not completed yet"
1266
1237
  };
1267
1238
  }
1268
- if (!process.env[TESTOPS_JWT_ENV]) {
1239
+ if (!process.env[BROWSERSTACK_TESTHUB_JWT]) {
1269
1240
  stopBuildUsage.failed("Token/buildID is undefined, build creation might have failed");
1270
1241
  BStackLogger.debug("[STOP_BUILD] Missing Authentication Token/ Build ID");
1271
1242
  return {
@@ -1277,12 +1248,12 @@ var stopBuildUpstream = o11yErrorHandler(async function stopBuildUpstream2() {
1277
1248
  "stop_time": (/* @__PURE__ */ new Date()).toISOString()
1278
1249
  };
1279
1250
  try {
1280
- const url3 = `${DATA_ENDPOINT}/api/v1/builds/${process.env[TESTOPS_BUILD_ID_ENV]}/stop`;
1251
+ const url3 = `${DATA_ENDPOINT}/api/v1/builds/${process.env[BROWSERSTACK_TESTHUB_UUID]}/stop`;
1281
1252
  const response = await fetch(url3, {
1282
1253
  method: "PUT",
1283
1254
  headers: {
1284
1255
  ...DEFAULT_REQUEST_CONFIG.headers,
1285
- "Authorization": `Bearer ${process.env[TESTOPS_JWT_ENV]}`
1256
+ "Authorization": `Bearer ${process.env[BROWSERSTACK_TESTHUB_JWT]}`
1286
1257
  },
1287
1258
  body: JSON.stringify(data)
1288
1259
  });
@@ -1669,7 +1640,7 @@ async function batchAndPostEvents(eventUrl, kind, data) {
1669
1640
  if (!process.env[TESTOPS_BUILD_COMPLETED_ENV]) {
1670
1641
  throw new Error("Build not completed yet");
1671
1642
  }
1672
- const jwtToken = process.env[TESTOPS_JWT_ENV];
1643
+ const jwtToken = process.env[BROWSERSTACK_TESTHUB_JWT];
1673
1644
  if (!jwtToken) {
1674
1645
  throw new Error("Missing authentication Token");
1675
1646
  }
@@ -1750,7 +1721,11 @@ function getBrowserStackKey(config) {
1750
1721
  return config.key;
1751
1722
  }
1752
1723
  function isUndefined(value) {
1753
- return value === void 0 || value === null;
1724
+ let res = value === void 0 || value === null;
1725
+ if (typeof value === "string") {
1726
+ res = res || value === "";
1727
+ }
1728
+ return res;
1754
1729
  }
1755
1730
  function isTrue(value) {
1756
1731
  return (value + "").toLowerCase() === "true";
@@ -2271,7 +2246,7 @@ var Percy = class {
2271
2246
  this.#proc = spawn2(
2272
2247
  binaryPath,
2273
2248
  commandArgs,
2274
- { env: { ...process.env, PERCY_TOKEN: token } }
2249
+ { env: { ...process.env, PERCY_TOKEN: token, TH_BUILD_UUID: process.env[BROWSERSTACK_TESTHUB_UUID] } }
2275
2250
  );
2276
2251
  this.#proc.stdout.pipe(logStream);
2277
2252
  this.#proc.stderr.pipe(logStream);
@@ -2480,7 +2455,7 @@ import path9 from "node:path";
2480
2455
 
2481
2456
  // src/instrumentation/funnelInstrumentation.ts
2482
2457
  import os4 from "node:os";
2483
- import util2 from "node:util";
2458
+ import util2, { format as format2 } from "node:util";
2484
2459
  import path8 from "node:path";
2485
2460
  import fs9 from "node:fs";
2486
2461
 
@@ -2552,7 +2527,7 @@ async function fireFunnelTestEvent(eventType, config) {
2552
2527
  BStackLogger.debug("Funnel event success");
2553
2528
  config.sentFunnelData();
2554
2529
  } catch (error) {
2555
- BStackLogger.debug("Exception in sending funnel data: " + error);
2530
+ BStackLogger.debug(`Exception in sending funnel data: ${format2(error)}`);
2556
2531
  }
2557
2532
  }
2558
2533
  async function sendStart(config) {
@@ -2568,9 +2543,22 @@ function saveFunnelData(eventType, config) {
2568
2543
  fs9.writeFileSync(filePath, JSON.stringify(data));
2569
2544
  return filePath;
2570
2545
  }
2546
+ function redactCredentialsFromFunnelData(data) {
2547
+ if (data) {
2548
+ if (data.userName) {
2549
+ data.userName = "[REDACTED]";
2550
+ }
2551
+ if (data.accessKey) {
2552
+ data.accessKey = "[REDACTED]";
2553
+ }
2554
+ }
2555
+ return data;
2556
+ }
2571
2557
  async function fireFunnelRequest(data) {
2558
+ const { userName, accessKey } = data;
2559
+ redactCredentialsFromFunnelData(data);
2572
2560
  BStackLogger.debug("Sending SDK event with data " + util2.inspect(data, { depth: 6 }));
2573
- const encodedAuth = Buffer.from(`${data.userName}:${data.accessKey}`, "utf8").toString("base64");
2561
+ const encodedAuth = Buffer.from(`${userName}:${accessKey}`, "utf8").toString("base64");
2574
2562
  const response = await fetchWrap(FUNNEL_INSTRUMENTATION_URL, {
2575
2563
  method: "POST",
2576
2564
  headers: {
@@ -2600,15 +2588,6 @@ function getProductList(config) {
2600
2588
  }
2601
2589
  return products;
2602
2590
  }
2603
- function getProductMap(config) {
2604
- return {
2605
- "observability": config.testObservability.enabled,
2606
- "accessibility": config.accessibility,
2607
- "percy": config.percy,
2608
- "automate": config.automate,
2609
- "app_automate": config.appAutomate
2610
- };
2611
- }
2612
2591
  function buildEventData(eventType, config) {
2613
2592
  const eventProperties = {
2614
2593
  // Framework Details
@@ -2746,7 +2725,7 @@ function setupExitHandlers() {
2746
2725
  }
2747
2726
  function shouldCallCleanup(config) {
2748
2727
  const args = [];
2749
- if (!!process.env[TESTOPS_JWT_ENV] && !config.testObservability.buildStopped) {
2728
+ if (!!process.env[BROWSERSTACK_TESTHUB_JWT] && !config.testObservability.buildStopped) {
2750
2729
  args.push("--observability");
2751
2730
  }
2752
2731
  if (config.userName && config.accessKey && !config.funnelDataSent) {
@@ -3086,21 +3065,18 @@ var BrowserstackLauncherService = class {
3086
3065
  }
3087
3066
  this._handleBuildIdentifier(capabilities);
3088
3067
  this._updateObjectTypeCaps(capabilities, "accessibilityOptions");
3089
- if (this._accessibilityAutomation) {
3090
- const scannerVersion = await createAccessibilityTestRun(this._options, this._config, {
3068
+ const shouldSetupPercy = this._options.percy || isUndefined(this._options.percy) && this._options.app;
3069
+ if (this._options.testObservability || this._accessibilityAutomation || shouldSetupPercy) {
3070
+ BStackLogger.debug("Sending launch start event");
3071
+ await launchTestSession(this._options, this._config, {
3091
3072
  projectName: this._projectName,
3092
3073
  buildName: this._buildName,
3093
3074
  buildTag: this._buildTag,
3094
3075
  bstackServiceVersion: BSTACK_SERVICE_VERSION,
3095
- buildIdentifier: this._buildIdentifier,
3096
- accessibilityOptions: this._options.accessibilityOptions
3097
- });
3098
- if (scannerVersion) {
3099
- process.env.BSTACK_A11Y_SCANNER_VERSION = scannerVersion;
3100
- }
3101
- BStackLogger.debug(`Accessibility scannerVersion ${scannerVersion}`);
3076
+ buildIdentifier: this._buildIdentifier
3077
+ }, this.browserStackConfig);
3102
3078
  }
3103
- if (this._options.accessibilityOptions) {
3079
+ if (this._accessibilityAutomation && this._options.accessibilityOptions) {
3104
3080
  const filteredOpts = Object.keys(this._options.accessibilityOptions).filter((key) => !NOT_ALLOWED_KEYS_IN_CAPS.includes(key)).reduce((opts2, key) => {
3105
3081
  return {
3106
3082
  ...opts2,
@@ -3111,21 +3087,11 @@ var BrowserstackLauncherService = class {
3111
3087
  } else if (isAccessibilityAutomationSession(this._accessibilityAutomation)) {
3112
3088
  this._updateObjectTypeCaps(capabilities, "accessibilityOptions", {});
3113
3089
  }
3114
- if (this._options.testObservability) {
3115
- BStackLogger.debug("Sending launch start event");
3116
- await launchTestSession(this._options, this._config, {
3117
- projectName: this._projectName,
3118
- buildName: this._buildName,
3119
- buildTag: this._buildTag,
3120
- bstackServiceVersion: BSTACK_SERVICE_VERSION,
3121
- buildIdentifier: this._buildIdentifier
3122
- });
3123
- }
3124
- const shouldSetupPercy = this._options.percy || isUndefined(this._options.percy) && this._options.app;
3125
3090
  if (shouldSetupPercy) {
3126
3091
  try {
3127
3092
  const bestPlatformPercyCaps = getBestPlatformForPercySnapshot(capabilities);
3128
3093
  this._percyBestPlatformCaps = bestPlatformPercyCaps;
3094
+ process.env[BROWSERSTACK_PERCY] = "false";
3129
3095
  await this.setupPercy(this._options, this._config, {
3130
3096
  projectName: this._projectName
3131
3097
  });
@@ -3174,29 +3140,22 @@ var BrowserstackLauncherService = class {
3174
3140
  }
3175
3141
  async onComplete() {
3176
3142
  BStackLogger.debug("Inside OnComplete hook..");
3177
- if (isAccessibilityAutomationSession(this._accessibilityAutomation)) {
3178
- await stopAccessibilityTestRun().catch((error) => {
3179
- BStackLogger.error(`Exception in stop accessibility test run: ${error}`);
3180
- });
3181
- }
3182
- if (this._options.testObservability) {
3183
- BStackLogger.debug("Sending stop launch event");
3184
- await stopBuildUpstream();
3185
- if (process.env[TESTOPS_BUILD_ID_ENV]) {
3186
- console.log(`
3187
- Visit https://observability.browserstack.com/builds/${process.env[TESTOPS_BUILD_ID_ENV]} to view build report, insights, and many more debugging information all at one place!
3143
+ BStackLogger.debug("Sending stop launch event");
3144
+ await stopBuildUpstream();
3145
+ if (process.env[BROWSERSTACK_OBSERVABILITY] && process.env[BROWSERSTACK_TESTHUB_UUID]) {
3146
+ console.log(`
3147
+ Visit https://observability.browserstack.com/builds/${process.env[BROWSERSTACK_TESTHUB_UUID]} to view build report, insights, and many more debugging information all at one place!
3188
3148
  `);
3149
+ }
3150
+ this.browserStackConfig.testObservability.buildStopped = true;
3151
+ if (process.env[PERF_MEASUREMENT_ENV]) {
3152
+ await PerformanceTester.stopAndGenerate("performance-launcher.html");
3153
+ PerformanceTester.calculateTimes(["launchTestSession", "stopBuildUpstream"]);
3154
+ if (!process.env.START_TIME) {
3155
+ return;
3189
3156
  }
3190
- this.browserStackConfig.testObservability.buildStopped = true;
3191
- if (process.env[PERF_MEASUREMENT_ENV]) {
3192
- await PerformanceTester.stopAndGenerate("performance-launcher.html");
3193
- PerformanceTester.calculateTimes(["launchTestSession", "stopBuildUpstream"]);
3194
- if (!process.env.START_TIME) {
3195
- return;
3196
- }
3197
- const duration = (/* @__PURE__ */ new Date()).getTime() - new Date(process.env.START_TIME).getTime();
3198
- BStackLogger.info(`Total duration is ${duration / 1e3} s`);
3199
- }
3157
+ const duration = (/* @__PURE__ */ new Date()).getTime() - new Date(process.env.START_TIME).getTime();
3158
+ BStackLogger.info(`Total duration is ${duration / 1e3} s`);
3200
3159
  }
3201
3160
  await sendFinish(this.browserStackConfig);
3202
3161
  try {
@@ -3243,6 +3202,7 @@ Visit https://observability.browserstack.com/builds/${process.env[TESTOPS_BUILD_
3243
3202
  }
3244
3203
  async setupPercy(options, config, bsConfig) {
3245
3204
  if (this._percy?.isRunning()) {
3205
+ process.env[BROWSERSTACK_PERCY] = "true";
3246
3206
  return;
3247
3207
  }
3248
3208
  try {
@@ -3251,6 +3211,7 @@ Visit https://observability.browserstack.com/builds/${process.env[TESTOPS_BUILD_
3251
3211
  throw new Error("Could not start percy, check percy logs for info.");
3252
3212
  }
3253
3213
  PercyLogger.info("Percy started successfully");
3214
+ process.env[BROWSERSTACK_PERCY] = "true";
3254
3215
  let signal = 0;
3255
3216
  const handler = async () => {
3256
3217
  signal++;
@@ -3260,7 +3221,8 @@ Visit https://observability.browserstack.com/builds/${process.env[TESTOPS_BUILD_
3260
3221
  process.on("SIGINT", handler);
3261
3222
  process.on("SIGTERM", handler);
3262
3223
  } catch (err) {
3263
- PercyLogger.debug(`Error in percy setup ${err}`);
3224
+ PercyLogger.debug(`Error in percy setup ${format3(err)}`);
3225
+ process.env[BROWSERSTACK_PERCY] = "false";
3264
3226
  }
3265
3227
  }
3266
3228
  async stopPercy() {
@@ -3325,7 +3287,7 @@ Visit https://observability.browserstack.com/builds/${process.env[TESTOPS_BUILD_
3325
3287
  async _uploadServiceLogs() {
3326
3288
  const clientBuildUuid = this._getClientBuildUuid();
3327
3289
  const response = await uploadLogs(getBrowserStackUser(this._config), getBrowserStackKey(this._config), clientBuildUuid);
3328
- BStackLogger.logToFile(`Response - ${format(response)}`, "debug");
3290
+ BStackLogger.logToFile(`Response - ${format3(response)}`, "debug");
3329
3291
  }
3330
3292
  _updateObjectTypeCaps(capabilities, capType, value) {
3331
3293
  try {
@@ -3581,8 +3543,8 @@ Visit https://observability.browserstack.com/builds/${process.env[TESTOPS_BUILD_
3581
3543
  fs11.writeFileSync(filePath, JSON.stringify(jsonContent));
3582
3544
  }
3583
3545
  _getClientBuildUuid() {
3584
- if (process.env[TESTOPS_BUILD_ID_ENV]) {
3585
- return process.env[TESTOPS_BUILD_ID_ENV];
3546
+ if (process.env[BROWSERSTACK_TESTHUB_UUID]) {
3547
+ return process.env[BROWSERSTACK_TESTHUB_UUID];
3586
3548
  }
3587
3549
  const uuid = uuidv4();
3588
3550
  BStackLogger.logToFile(`If facing any issues, please contact BrowserStack support with the Build Run Id - ${uuid}`, "info");
@@ -3675,6 +3637,7 @@ var RequestQueueHandler = class _RequestQueueHandler {
3675
3637
  };
3676
3638
 
3677
3639
  // src/testOps/requestUtils.ts
3640
+ import { format as format4 } from "node:util";
3678
3641
  async function uploadEventData(eventData, eventUrl = DATA_EVENT_ENDPOINT) {
3679
3642
  let logTag = "BATCH_UPLOAD";
3680
3643
  if (!Array.isArray(eventData)) {
@@ -3686,7 +3649,7 @@ async function uploadEventData(eventData, eventUrl = DATA_EVENT_ENDPOINT) {
3686
3649
  if (!process.env[TESTOPS_BUILD_COMPLETED_ENV]) {
3687
3650
  throw new Error("Build start not completed yet");
3688
3651
  }
3689
- if (!process.env[TESTOPS_JWT_ENV]) {
3652
+ if (!process.env[BROWSERSTACK_TESTHUB_JWT]) {
3690
3653
  BStackLogger.debug(`[${logTag}] Missing Authentication Token/ Build ID`);
3691
3654
  throw new Error("Token/buildID is undefined, build creation might have failed");
3692
3655
  }
@@ -3696,13 +3659,13 @@ async function uploadEventData(eventData, eventUrl = DATA_EVENT_ENDPOINT) {
3696
3659
  method: "POST",
3697
3660
  headers: {
3698
3661
  ...DEFAULT_REQUEST_CONFIG.headers,
3699
- "Authorization": `Bearer ${process.env[TESTOPS_JWT_ENV]}`
3662
+ "Authorization": `Bearer ${process.env[BROWSERSTACK_TESTHUB_JWT]}`
3700
3663
  },
3701
3664
  body: JSON.stringify(eventData)
3702
3665
  });
3703
3666
  BStackLogger.debug(`[${logTag}] Success response: ${JSON.stringify(await data.json())}`);
3704
3667
  } catch (error) {
3705
- BStackLogger.debug(`[${logTag}] Failed. Error: ${error}`);
3668
+ BStackLogger.debug(`[${logTag}] Failed. Error: ${format4(error)}`);
3706
3669
  throw error;
3707
3670
  }
3708
3671
  }
@@ -3722,6 +3685,8 @@ var Listener = class _Listener {
3722
3685
  logEvents = this.usageStats.logStats;
3723
3686
  requestBatcher;
3724
3687
  pendingUploads = 0;
3688
+ static _accessibilityOptions;
3689
+ static _testRunAccessibilityVar = false;
3725
3690
  // Making the constructor private to use singleton pattern
3726
3691
  constructor() {
3727
3692
  }
@@ -3731,6 +3696,12 @@ var Listener = class _Listener {
3731
3696
  }
3732
3697
  return _Listener.instance;
3733
3698
  }
3699
+ static setAccessibilityOptions(options) {
3700
+ _Listener._accessibilityOptions = options;
3701
+ }
3702
+ static setTestRunAccessibilityVar(accessibility) {
3703
+ _Listener._testRunAccessibilityVar = accessibility;
3704
+ }
3734
3705
  async onWorkerEnd() {
3735
3706
  try {
3736
3707
  await this.uploadPending();
@@ -3754,6 +3725,9 @@ var Listener = class _Listener {
3754
3725
  }
3755
3726
  hookStarted(hookData) {
3756
3727
  try {
3728
+ if (!shouldProcessEventForTesthub("HookRunStarted")) {
3729
+ return;
3730
+ }
3757
3731
  this.hookStartedStats.triggered();
3758
3732
  this.sendBatchEvents(this.getEventForHook("HookRunStarted", hookData));
3759
3733
  } catch (e) {
@@ -3763,6 +3737,9 @@ var Listener = class _Listener {
3763
3737
  }
3764
3738
  hookFinished(hookData) {
3765
3739
  try {
3740
+ if (!shouldProcessEventForTesthub("HookRunFinished")) {
3741
+ return;
3742
+ }
3766
3743
  this.hookFinishedStats.triggered(hookData.result);
3767
3744
  this.sendBatchEvents(this.getEventForHook("HookRunFinished", hookData));
3768
3745
  } catch (e) {
@@ -3772,7 +3749,14 @@ var Listener = class _Listener {
3772
3749
  }
3773
3750
  testStarted(testData) {
3774
3751
  try {
3752
+ if (!shouldProcessEventForTesthub("TestRunStarted")) {
3753
+ return;
3754
+ }
3755
+ process.env[TEST_ANALYTICS_ID] = testData.uuid;
3775
3756
  this.testStartedStats.triggered();
3757
+ testData.product_map = {
3758
+ accessibility: _Listener._testRunAccessibilityVar
3759
+ };
3776
3760
  this.sendBatchEvents(this.getEventForHook("TestRunStarted", testData));
3777
3761
  } catch (e) {
3778
3762
  this.testStartedStats.failed();
@@ -3781,6 +3765,12 @@ var Listener = class _Listener {
3781
3765
  }
3782
3766
  testFinished(testData) {
3783
3767
  try {
3768
+ if (!shouldProcessEventForTesthub("TestRunFinished")) {
3769
+ return;
3770
+ }
3771
+ testData.product_map = {
3772
+ accessibility: _Listener._testRunAccessibilityVar
3773
+ };
3784
3774
  this.testFinishedStats.triggered(testData.result);
3785
3775
  this.sendBatchEvents(this.getEventForHook("TestRunFinished", testData));
3786
3776
  } catch (e) {
@@ -3790,6 +3780,9 @@ var Listener = class _Listener {
3790
3780
  }
3791
3781
  logCreated(logs) {
3792
3782
  try {
3783
+ if (!shouldProcessEventForTesthub("LogCreated")) {
3784
+ return;
3785
+ }
3793
3786
  this.markLogs("triggered", logs);
3794
3787
  this.sendBatchEvents({
3795
3788
  event_type: "LogCreated",
@@ -3805,6 +3798,9 @@ var Listener = class _Listener {
3805
3798
  return;
3806
3799
  }
3807
3800
  try {
3801
+ if (!shouldProcessEventForTesthub("LogCreated")) {
3802
+ return;
3803
+ }
3808
3804
  this.markLogs("triggered", jsonArray);
3809
3805
  this.pendingUploads += 1;
3810
3806
  await sendScreenshots([{
@@ -3821,6 +3817,9 @@ var Listener = class _Listener {
3821
3817
  }
3822
3818
  cbtSessionCreated(data) {
3823
3819
  try {
3820
+ if (!shouldProcessEventForTesthub("CBTSessionCreated")) {
3821
+ return;
3822
+ }
3824
3823
  this.cbtSessionStats.triggered();
3825
3824
  this.sendBatchEvents({ event_type: "CBTSessionCreated", test_run: data });
3826
3825
  } catch (e) {
@@ -3930,7 +3929,7 @@ var _TestReporter = class __TestReporter extends WDIOReporter {
3930
3929
  _gitConfigPath;
3931
3930
  _gitConfigured = false;
3932
3931
  _currentHook = {};
3933
- _currentTest = {};
3932
+ static currentTest = {};
3934
3933
  _userCaps = {};
3935
3934
  listener = listener_default.getInstance();
3936
3935
  async onRunnerStart(runnerStats) {
@@ -3957,8 +3956,8 @@ var _TestReporter = class __TestReporter extends WDIOReporter {
3957
3956
  async appendTestItemLog(stdLog) {
3958
3957
  if (this._currentHook.uuid && !this._currentHook.finished) {
3959
3958
  stdLog.hook_run_uuid = this._currentHook.uuid;
3960
- } else if (this._currentTest.uuid) {
3961
- stdLog.test_run_uuid = this._currentTest.uuid;
3959
+ } else if (__TestReporter.currentTest.uuid) {
3960
+ stdLog.test_run_uuid = __TestReporter.currentTest.uuid;
3962
3961
  }
3963
3962
  if (stdLog.hook_run_uuid || stdLog.test_run_uuid) {
3964
3963
  this.listener.logCreated([stdLog]);
@@ -4042,7 +4041,7 @@ var _TestReporter = class __TestReporter extends WDIOReporter {
4042
4041
  return;
4043
4042
  }
4044
4043
  const uuid = uuidv42();
4045
- this._currentTest.uuid = uuid;
4044
+ __TestReporter.currentTest.uuid = uuid;
4046
4045
  __TestReporter._tests[testStats.fullTitle] = {
4047
4046
  uuid
4048
4047
  };
@@ -4097,6 +4096,9 @@ var _TestReporter = class __TestReporter extends WDIOReporter {
4097
4096
  const testMetaData = __TestReporter._tests[identifier];
4098
4097
  const scope = testStats.type === "test" ? testStats.fullTitle : `${this._suites[0].title} - ${testStats.title}`;
4099
4098
  const suiteFileName = this._suiteName || (this.specs?.length > 0 ? this.specs[this.specs.length - 1]?.replace("file:", "") : void 0);
4099
+ if (eventType === "TestRunStarted") {
4100
+ __TestReporter.currentTest.name = testStats.title;
4101
+ }
4100
4102
  await this.configureGit();
4101
4103
  const testData = {
4102
4104
  uuid: testMetaData ? testMetaData.uuid : uuidv42(),
@@ -4139,7 +4141,7 @@ var _TestReporter = class __TestReporter extends WDIOReporter {
4139
4141
  if (failed) {
4140
4142
  testData.result = error && error.message && error.message.includes("sync skip; aborting execution") ? "ignore" : "failed";
4141
4143
  if (error && testData.result !== "skipped") {
4142
- testData.failure = [{ backtrace: [removeAnsiColors(error.message)] }];
4144
+ testData.failure = [{ backtrace: [removeAnsiColors(error.message), removeAnsiColors(error.stack || "")] }];
4143
4145
  testData.failure_reason = removeAnsiColors(error.message);
4144
4146
  testData.failure_type = error.message === null ? null : error.message.toString().match(/AssertionError/) ? "AssertionError" : "UnhandledError";
4145
4147
  }
@@ -4181,7 +4183,7 @@ var _InsightsHandler = class {
4181
4183
  _commands = {};
4182
4184
  _gitConfigPath;
4183
4185
  _suiteFile;
4184
- _currentTest = {};
4186
+ static currentTest = {};
4185
4187
  _currentHook = {};
4186
4188
  _cucumberData = {
4187
4189
  stepsStarted: false,
@@ -4190,8 +4192,8 @@ var _InsightsHandler = class {
4190
4192
  };
4191
4193
  _userCaps = {};
4192
4194
  listener = listener_default.getInstance();
4193
- _currentTestId;
4194
- _cbtQueue = [];
4195
+ currentTestId;
4196
+ cbtQueue = [];
4195
4197
  _isAppAutomate() {
4196
4198
  const browserDesiredCapabilities = this._browser?.capabilities ?? {};
4197
4199
  const desiredCapabilities = this._userCaps ?? {};
@@ -4311,7 +4313,7 @@ var _InsightsHandler = class {
4311
4313
  const hookMetaData = {
4312
4314
  uuid: hookUUID,
4313
4315
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
4314
- testRunId: this._currentTest.uuid,
4316
+ testRunId: InsightsHandler.currentTest.uuid,
4315
4317
  hookType
4316
4318
  };
4317
4319
  this._tests[hookId] = hookMetaData;
@@ -4443,7 +4445,7 @@ var _InsightsHandler = class {
4443
4445
  }
4444
4446
  async beforeTest(test) {
4445
4447
  const uuid = uuidv43();
4446
- this._currentTest = {
4448
+ InsightsHandler.currentTest = {
4447
4449
  test,
4448
4450
  uuid
4449
4451
  };
@@ -4479,7 +4481,7 @@ var _InsightsHandler = class {
4479
4481
  }
4480
4482
  async beforeScenario(world) {
4481
4483
  const uuid = uuidv43();
4482
- this._currentTest = {
4484
+ InsightsHandler.currentTest = {
4483
4485
  uuid
4484
4486
  };
4485
4487
  this._cucumberData.scenario = world.pickle;
@@ -4560,8 +4562,8 @@ var _InsightsHandler = class {
4560
4562
  try {
4561
4563
  if (this._currentHook.uuid && !this._currentHook.finished && (this._framework === "mocha" || this._framework === "cucumber")) {
4562
4564
  stdLog.hook_run_uuid = this._currentHook.uuid;
4563
- } else if (this._currentTest.uuid && (this._framework === "mocha" || this._framework === "cucumber")) {
4564
- stdLog.test_run_uuid = this._currentTest.uuid;
4565
+ } else if (InsightsHandler.currentTest.uuid && (this._framework === "mocha" || this._framework === "cucumber")) {
4566
+ stdLog.test_run_uuid = InsightsHandler.currentTest.uuid;
4565
4567
  }
4566
4568
  if (stdLog.hook_run_uuid || stdLog.test_run_uuid) {
4567
4569
  this.listener.logCreated([stdLog]);
@@ -4668,7 +4670,10 @@ var _InsightsHandler = class {
4668
4670
  const fullTitle = getUniqueIdentifier(test, this._framework);
4669
4671
  const testMetaData = this._tests[fullTitle];
4670
4672
  const filename = test.file || this._suiteFile;
4671
- this._currentTestId = testMetaData.uuid;
4673
+ this.currentTestId = testMetaData.uuid;
4674
+ if (eventType === "TestRunStarted") {
4675
+ InsightsHandler.currentTest.name = test.title || test.description;
4676
+ }
4672
4677
  const testData = {
4673
4678
  uuid: testMetaData.uuid,
4674
4679
  type: test.type || "test",
@@ -4693,7 +4698,7 @@ var _InsightsHandler = class {
4693
4698
  if (!passed) {
4694
4699
  testData.result = error && error.message && error.message.includes("sync skip; aborting execution") ? "ignore" : "failed";
4695
4700
  if (error && testData.result !== "skipped") {
4696
- testData.failure = [{ backtrace: [removeAnsiColors(error.message)] }];
4701
+ testData.failure = [{ backtrace: [removeAnsiColors(error.message), removeAnsiColors(error.stack || "")] }];
4697
4702
  testData.failure_reason = removeAnsiColors(error.message);
4698
4703
  testData.failure_type = isUndefined(error.message) ? null : error.message.toString().match(/AssertionError/) ? "AssertionError" : "UnhandledError";
4699
4704
  }
@@ -4765,7 +4770,10 @@ var _InsightsHandler = class {
4765
4770
  } else {
4766
4771
  fullNameWithExamples = scenario?.name || "";
4767
4772
  }
4768
- this._currentTestId = uuid;
4773
+ this.currentTestId = uuid;
4774
+ if (eventType === "TestRunStarted") {
4775
+ InsightsHandler.currentTest.name = fullNameWithExamples;
4776
+ }
4769
4777
  const testData = {
4770
4778
  uuid,
4771
4779
  started_at: startedAt,
@@ -4827,14 +4835,14 @@ var _InsightsHandler = class {
4827
4835
  return testData;
4828
4836
  }
4829
4837
  async flushCBTDataQueue() {
4830
- if (isUndefined(this._currentTestId)) {
4838
+ if (isUndefined(this.currentTestId)) {
4831
4839
  return;
4832
4840
  }
4833
- this._cbtQueue.forEach((cbtData) => {
4834
- cbtData.uuid = this._currentTestId;
4841
+ this.cbtQueue.forEach((cbtData) => {
4842
+ cbtData.uuid = this.currentTestId;
4835
4843
  this.listener.cbtSessionCreated(cbtData);
4836
4844
  });
4837
- this._currentTestId = void 0;
4845
+ this.currentTestId = void 0;
4838
4846
  }
4839
4847
  async sendCBTInfo() {
4840
4848
  const integrationsData = {};
@@ -4846,11 +4854,11 @@ var _InsightsHandler = class {
4846
4854
  uuid: "",
4847
4855
  integrations: integrationsData
4848
4856
  };
4849
- if (this._currentTestId !== void 0) {
4850
- cbtData.uuid = this._currentTestId;
4857
+ if (this.currentTestId !== void 0) {
4858
+ cbtData.uuid = this.currentTestId;
4851
4859
  this.listener.cbtSessionCreated(cbtData);
4852
4860
  } else {
4853
- this._cbtQueue.push(cbtData);
4861
+ this.cbtQueue.push(cbtData);
4854
4862
  }
4855
4863
  }
4856
4864
  getIntegrationsObject() {
@@ -4905,6 +4913,7 @@ var _AccessibilityHandler = class {
4905
4913
  _testMetadata = {};
4906
4914
  static _a11yScanSessionMap = {};
4907
4915
  _sessionId = null;
4916
+ listener = listener_default.getInstance();
4908
4917
  setSuiteFile(filename) {
4909
4918
  this._suiteFile = filename;
4910
4919
  }
@@ -4967,6 +4976,7 @@ var _AccessibilityHandler = class {
4967
4976
  async beforeTest(suiteTitle, test) {
4968
4977
  try {
4969
4978
  if (this._framework !== "mocha" || !this.shouldRunTestHooks(this._browser, this._accessibility)) {
4979
+ listener_default.setTestRunAccessibilityVar(false);
4970
4980
  return;
4971
4981
  }
4972
4982
  const shouldScanTest = shouldScanTestForAccessibility(suiteTitle, test.title, this._accessibilityOptions);
@@ -4975,6 +4985,7 @@ var _AccessibilityHandler = class {
4975
4985
  if (this._sessionId) {
4976
4986
  AccessibilityHandler._a11yScanSessionMap[this._sessionId] = shouldScanTest;
4977
4987
  }
4988
+ listener_default.setTestRunAccessibilityVar(this._accessibility && shouldScanTest);
4978
4989
  if (!isPageOpened) {
4979
4990
  return;
4980
4991
  }
@@ -5000,19 +5011,12 @@ var _AccessibilityHandler = class {
5000
5011
  }
5001
5012
  if (shouldScanTestForAccessibility2) {
5002
5013
  BStackLogger.info("Automate test case execution has ended. Processing for accessibility testing is underway. ");
5003
- }
5004
- const dataForExtension = {
5005
- saveResults: shouldScanTestForAccessibility2,
5006
- testDetails: {
5007
- "name": test.title,
5008
- "testRunId": process.env.BS_A11Y_TEST_RUN_ID,
5009
- "filePath": this._suiteFile,
5010
- "scopeList": [suiteTitle, test.title]
5011
- },
5012
- platform: this._platformA11yMeta
5013
- };
5014
- await this.sendTestStopEvent(this._browser, dataForExtension);
5015
- if (shouldScanTestForAccessibility2) {
5014
+ const dataForExtension = {
5015
+ "thTestRunUuid": process.env.TEST_ANALYTICS_ID,
5016
+ "thBuildUuid": process.env.BROWSERSTACK_TESTHUB_UUID,
5017
+ "thJwtToken": process.env.BROWSERSTACK_TESTHUB_JWT
5018
+ };
5019
+ await this.sendTestStopEvent(this._browser, dataForExtension);
5016
5020
  BStackLogger.info("Accessibility testing for this test case has ended.");
5017
5021
  }
5018
5022
  } catch (error) {
@@ -5028,6 +5032,7 @@ var _AccessibilityHandler = class {
5028
5032
  const featureData = gherkinDocument.feature;
5029
5033
  const uniqueId = getUniqueIdentifierForCucumber(world);
5030
5034
  if (!this.shouldRunTestHooks(this._browser, this._accessibility)) {
5035
+ listener_default.setTestRunAccessibilityVar(false);
5031
5036
  return;
5032
5037
  }
5033
5038
  try {
@@ -5036,6 +5041,7 @@ var _AccessibilityHandler = class {
5036
5041
  if (this._sessionId) {
5037
5042
  AccessibilityHandler._a11yScanSessionMap[this._sessionId] = shouldScanScenario;
5038
5043
  }
5044
+ listener_default.setTestRunAccessibilityVar(this._accessibility && shouldScanScenario);
5039
5045
  if (!isPageOpened) {
5040
5046
  return;
5041
5047
  }
@@ -5054,8 +5060,6 @@ var _AccessibilityHandler = class {
5054
5060
  }
5055
5061
  const pickleData = world.pickle;
5056
5062
  try {
5057
- const gherkinDocument = world.gherkinDocument;
5058
- const featureData = gherkinDocument.feature;
5059
5063
  const uniqueId = getUniqueIdentifierForCucumber(world);
5060
5064
  const accessibilityScanStarted = this._testMetadata[uniqueId]?.accessibilityScanStarted;
5061
5065
  const shouldScanTestForAccessibility2 = this._testMetadata[uniqueId]?.scanTestForAccessibility;
@@ -5064,19 +5068,12 @@ var _AccessibilityHandler = class {
5064
5068
  }
5065
5069
  if (shouldScanTestForAccessibility2) {
5066
5070
  BStackLogger.info("Automate test case execution has ended. Processing for accessibility testing is underway. ");
5067
- }
5068
- const dataForExtension = {
5069
- saveResults: shouldScanTestForAccessibility2,
5070
- testDetails: {
5071
- "name": pickleData.name,
5072
- "testRunId": process.env.BS_A11Y_TEST_RUN_ID,
5073
- "filePath": gherkinDocument.uri,
5074
- "scopeList": [featureData?.name, pickleData.name]
5075
- },
5076
- platform: this._platformA11yMeta
5077
- };
5078
- await this.sendTestStopEvent(this._browser, dataForExtension);
5079
- if (shouldScanTestForAccessibility2) {
5071
+ const dataForExtension = {
5072
+ "thTestRunUuid": process.env.TEST_ANALYTICS_ID,
5073
+ "thBuildUuid": process.env.BROWSERSTACK_TESTHUB_UUID,
5074
+ "thJwtToken": process.env.BROWSERSTACK_TESTHUB_JWT
5075
+ };
5076
+ await this.sendTestStopEvent(this._browser, dataForExtension);
5080
5077
  BStackLogger.info("Accessibility testing for this test case has ended.");
5081
5078
  }
5082
5079
  } catch (error) {
@@ -5189,25 +5186,66 @@ var snapshotHandler = (...args) => {
5189
5186
  PercyLogger.error("Unsupported driver for percy");
5190
5187
  };
5191
5188
  if (percySnapshot) {
5192
- snapshotHandler = (browser, name) => {
5189
+ snapshotHandler = (browser, snapshotName, options) => {
5193
5190
  if (process.env.PERCY_SNAPSHOT === "true") {
5194
- return percySnapshot(browser, name);
5191
+ let { name, uuid } = insights_handler_default.currentTest;
5192
+ if (isUndefined(name)) {
5193
+ ({ name, uuid } = reporter_default.currentTest);
5194
+ }
5195
+ options ||= {};
5196
+ options = {
5197
+ ...options,
5198
+ testCase: name || "",
5199
+ thTestCaseExecutionId: uuid || ""
5200
+ };
5201
+ return percySnapshot(browser, snapshotName, options);
5195
5202
  }
5196
5203
  };
5197
5204
  }
5198
5205
  var snapshot = snapshotHandler;
5206
+ var screenshotHelper = (type2, driverOrName, nameOrOptions, options) => {
5207
+ let { name, uuid } = insights_handler_default.currentTest;
5208
+ if (isUndefined(name)) {
5209
+ ({ name, uuid } = reporter_default.currentTest);
5210
+ }
5211
+ if (!driverOrName || typeof driverOrName === "string") {
5212
+ nameOrOptions ||= {};
5213
+ if (typeof nameOrOptions === "object") {
5214
+ nameOrOptions = {
5215
+ ...nameOrOptions,
5216
+ testCase: name || "",
5217
+ thTestCaseExecutionId: uuid || ""
5218
+ };
5219
+ }
5220
+ } else {
5221
+ options ||= {};
5222
+ options = {
5223
+ ...options,
5224
+ testCase: name || "",
5225
+ thTestCaseExecutionId: uuid || ""
5226
+ };
5227
+ }
5228
+ if (type2 === "app") {
5229
+ return percyAppScreenshot(driverOrName, nameOrOptions, options);
5230
+ }
5231
+ return percySnapshot.percyScreenshot(driverOrName, nameOrOptions, options);
5232
+ };
5199
5233
  var screenshotHandler = async (...args) => {
5200
5234
  PercyLogger.error("Unsupported driver for percy");
5201
5235
  };
5202
5236
  if (percySnapshot && percySnapshot.percyScreenshot) {
5203
- screenshotHandler = percySnapshot.percyScreenshot;
5237
+ screenshotHandler = (browser, screenshotName, options) => {
5238
+ return screenshotHelper("web", browser, screenshotName, options);
5239
+ };
5204
5240
  }
5205
5241
  var screenshot = screenshotHandler;
5206
5242
  var screenshotAppHandler = async (...args) => {
5207
5243
  PercyLogger.error("Unsupported driver for percy");
5208
5244
  };
5209
5245
  if (percyAppScreenshot) {
5210
- screenshotAppHandler = percyAppScreenshot;
5246
+ screenshotAppHandler = (driverOrName, nameOrOptions, options) => {
5247
+ return screenshotHelper("app", driverOrName, nameOrOptions, options);
5248
+ };
5211
5249
  }
5212
5250
  var screenshotApp = screenshotAppHandler;
5213
5251
 
@@ -5346,10 +5384,10 @@ var BrowserstackService = class {
5346
5384
  this._config || (this._config = this._options);
5347
5385
  this._observability = this._options.testObservability;
5348
5386
  this._accessibility = this._options.accessibility;
5349
- this._percy = process.env.BROWSERSTACK_PERCY === "true";
5387
+ this._percy = isTrue(process.env.BROWSERSTACK_PERCY);
5350
5388
  this._percyCaptureMode = process.env.BROWSERSTACK_PERCY_CAPTURE_MODE;
5351
5389
  this._turboScale = this._options.turboScale;
5352
- if (this._observability) {
5390
+ if (shouldProcessEventForTesthub("")) {
5353
5391
  this._config.reporters?.push(reporter_default);
5354
5392
  if (process.env[PERF_MEASUREMENT_ENV]) {
5355
5393
  PerformanceTester.startMonitoring("performance-report-service.csv");
@@ -5423,28 +5461,8 @@ var BrowserstackService = class {
5423
5461
  }
5424
5462
  this._scenariosThatRan = [];
5425
5463
  if (this._browser) {
5426
- if (this._percy) {
5427
- this._percyHandler = new Percy_Handler_default(
5428
- this._percyCaptureMode,
5429
- this._browser,
5430
- this._caps,
5431
- this._isAppAutomate(),
5432
- this._config.framework
5433
- );
5434
- this._percyHandler.before();
5435
- }
5436
5464
  try {
5437
5465
  const sessionId = this._browser.sessionId;
5438
- if (this._observability) {
5439
- patchConsoleLogs();
5440
- this._insightsHandler = new insights_handler_default(
5441
- this._browser,
5442
- this._config.framework,
5443
- this._caps,
5444
- this._options
5445
- );
5446
- await this._insightsHandler.before();
5447
- }
5448
5466
  if (isBrowserstackSession(this._browser)) {
5449
5467
  try {
5450
5468
  this._accessibilityHandler = new accessibility_handler_default(
@@ -5456,12 +5474,23 @@ var BrowserstackService = class {
5456
5474
  this._options.accessibilityOptions
5457
5475
  );
5458
5476
  await this._accessibilityHandler.before(sessionId);
5477
+ listener_default.setAccessibilityOptions(this._options.accessibilityOptions);
5459
5478
  } catch (err) {
5460
5479
  BStackLogger.error(`[Accessibility Test Run] Error in service class before function: ${err}`);
5461
5480
  }
5462
5481
  }
5482
+ if (shouldProcessEventForTesthub("")) {
5483
+ patchConsoleLogs();
5484
+ this._insightsHandler = new insights_handler_default(
5485
+ this._browser,
5486
+ this._config.framework,
5487
+ this._caps,
5488
+ this._options
5489
+ );
5490
+ await this._insightsHandler.before();
5491
+ }
5463
5492
  this._browser.on("command", async (command) => {
5464
- if (this._observability) {
5493
+ if (shouldProcessEventForTesthub("")) {
5465
5494
  this._insightsHandler?.browserCommand(
5466
5495
  "client:beforeCommand",
5467
5496
  Object.assign(command, { sessionId }),
@@ -5473,7 +5502,7 @@ var BrowserstackService = class {
5473
5502
  );
5474
5503
  });
5475
5504
  this._browser.on("result", (result) => {
5476
- if (this._observability) {
5505
+ if (shouldProcessEventForTesthub("")) {
5477
5506
  this._insightsHandler?.browserCommand(
5478
5507
  "client:afterCommand",
5479
5508
  Object.assign(result, { sessionId }),
@@ -5486,10 +5515,20 @@ var BrowserstackService = class {
5486
5515
  });
5487
5516
  } catch (err) {
5488
5517
  BStackLogger.error(`Error in service class before function: ${err}`);
5489
- if (this._observability) {
5518
+ if (shouldProcessEventForTesthub("")) {
5490
5519
  CrashReporter.uploadCrashReport(`Error in service class before function: ${err}`, err && err.stack);
5491
5520
  }
5492
5521
  }
5522
+ if (this._percy) {
5523
+ this._percyHandler = new Percy_Handler_default(
5524
+ this._percyCaptureMode,
5525
+ this._browser,
5526
+ this._caps,
5527
+ this._isAppAutomate(),
5528
+ this._config.framework
5529
+ );
5530
+ this._percyHandler.before();
5531
+ }
5493
5532
  }
5494
5533
  return await this._printSessionURL();
5495
5534
  }
@@ -5530,8 +5569,8 @@ var BrowserstackService = class {
5530
5569
  }
5531
5570
  await this._setSessionName(suiteTitle, test);
5532
5571
  await this._setAnnotation(`Test: ${test.fullName ?? test.title}`);
5533
- await this._insightsHandler?.beforeTest(test);
5534
5572
  await this._accessibilityHandler?.beforeTest(suiteTitle, test);
5573
+ await this._insightsHandler?.beforeTest(test);
5535
5574
  }
5536
5575
  async afterTest(test, context, results) {
5537
5576
  this._specsRan = true;
@@ -5539,9 +5578,9 @@ var BrowserstackService = class {
5539
5578
  if (!passed) {
5540
5579
  this._failReasons.push(error && error.message || "Unknown Error");
5541
5580
  }
5581
+ await this._accessibilityHandler?.afterTest(this._suiteTitle, test);
5542
5582
  await this._insightsHandler?.afterTest(test, results);
5543
5583
  await this._percyHandler?.afterTest();
5544
- await this._accessibilityHandler?.afterTest(this._suiteTitle, test);
5545
5584
  }
5546
5585
  async after(result) {
5547
5586
  const { preferScenarioName, setSessionName, setSessionStatus } = this._options;
@@ -5594,8 +5633,8 @@ var BrowserstackService = class {
5594
5633
  */
5595
5634
  async beforeScenario(world) {
5596
5635
  this._currentTest = world;
5597
- await this._insightsHandler?.beforeScenario(world);
5598
5636
  await this._accessibilityHandler?.beforeScenario(world);
5637
+ await this._insightsHandler?.beforeScenario(world);
5599
5638
  const scenarioName = world.pickle.name || "unknown scenario";
5600
5639
  await this._setAnnotation(`Scenario: ${scenarioName}`);
5601
5640
  }
@@ -5609,9 +5648,9 @@ var BrowserstackService = class {
5609
5648
  const exception = world.result && world.result.message || (status === "pending" ? `Some steps/hooks are pending for scenario "${world.pickle.name}"` : "Unknown Error");
5610
5649
  this._failReasons.push(exception);
5611
5650
  }
5651
+ await this._accessibilityHandler?.afterScenario(world);
5612
5652
  await this._insightsHandler?.afterScenario(world);
5613
5653
  await this._percyHandler?.afterScenario();
5614
- await this._accessibilityHandler?.afterScenario(world);
5615
5654
  }
5616
5655
  async beforeStep(step, scenario) {
5617
5656
  await this._insightsHandler?.beforeStep(step, scenario);