@wdio/browserstack-service 9.27.2 → 9.29.0
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/caCert.d.ts +7 -0
- package/build/caCert.d.ts.map +1 -0
- package/build/cleanup.js +237 -118
- package/build/cli/cliUtils.d.ts +7 -0
- package/build/cli/cliUtils.d.ts.map +1 -1
- package/build/cli/index.d.ts +8 -0
- package/build/cli/index.d.ts.map +1 -1
- package/build/config.d.ts +3 -3
- package/build/config.d.ts.map +1 -1
- package/build/constants.d.ts +11 -0
- package/build/constants.d.ts.map +1 -1
- package/build/fetchWrapper.d.ts +18 -2
- package/build/fetchWrapper.d.ts.map +1 -1
- package/build/index.js +994 -645
- package/build/insights-handler.d.ts.map +1 -1
- package/build/instrumentation/funnelInstrumentation.d.ts.map +1 -1
- package/build/launcher.d.ts.map +1 -1
- package/build/reporter.d.ts.map +1 -1
- package/build/service.d.ts +1 -0
- package/build/service.d.ts.map +1 -1
- package/build/types.d.ts +11 -0
- package/build/types.d.ts.map +1 -1
- package/build/util.d.ts +22 -0
- package/build/util.d.ts.map +1 -1
- package/package.json +6 -6
package/build/index.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
-
var __esm = (fn, res) => function __init() {
|
|
5
|
-
|
|
4
|
+
var __esm = (fn, res, err) => function __init() {
|
|
5
|
+
if (err) throw err[0];
|
|
6
|
+
try {
|
|
7
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
8
|
+
} catch (e) {
|
|
9
|
+
throw err = [e], e;
|
|
10
|
+
}
|
|
6
11
|
};
|
|
7
12
|
var __export = (target, all) => {
|
|
8
13
|
for (var name in all)
|
|
@@ -23,7 +28,7 @@ var init_package = __esm({
|
|
|
23
28
|
"package.json"() {
|
|
24
29
|
package_default = {
|
|
25
30
|
name: "@wdio/browserstack-service",
|
|
26
|
-
version: "9.
|
|
31
|
+
version: "9.28.0",
|
|
27
32
|
description: "WebdriverIO service for better Browserstack integration",
|
|
28
33
|
author: "Adam Bjerstedt <abjerstedt@gmail.com>",
|
|
29
34
|
homepage: "https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-browserstack-service",
|
|
@@ -97,7 +102,7 @@ var init_package = __esm({
|
|
|
97
102
|
});
|
|
98
103
|
|
|
99
104
|
// src/constants.ts
|
|
100
|
-
var bstackServiceVersion, BROWSER_DESCRIPTION, VALID_APP_EXTENSION, DEFAULT_OPTIONS, consoleHolder, APP_ALLY_ISSUES_ENDPOINT, APP_ALLY_ISSUES_SUMMARY_ENDPOINT, DATA_EVENT_ENDPOINT, DATA_BATCH_ENDPOINT, DATA_SCREENSHOT_ENDPOINT, DATA_BATCH_SIZE, DATA_BATCH_INTERVAL, DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS, DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS, BSTACK_SERVICE_VERSION, NOT_ALLOWED_KEYS_IN_CAPS, BROWSERSTACK_TEST_PLAN_ID, LOGS_FILE, CLI_DEBUG_LOGS_FILE, UPLOAD_LOGS_ENDPOINT, PERCY_LOGS_FILE, PERCY_DOM_CHANGING_COMMANDS_ENDPOINTS, CAPTURE_MODES, LOG_KIND_USAGE_MAP, SUPPORTED_BROWSERS_FOR_AI, TCG_URL, TCG_INFO, SMART_SELECTION_MODE_RELEVANT_FIRST, SMART_SELECTION_MODE_RELEVANT_ONLY, BROWSERSTACK_TESTHUB_JWT, BSTACK_TCG_AUTH_RESULT, TESTOPS_SCREENSHOT_ENV, BROWSERSTACK_TESTHUB_UUID, TEST_ANALYTICS_ID, PERF_MEASUREMENT_ENV, RERUN_TESTS_ENV, RERUN_ENV, TESTOPS_BUILD_COMPLETED_ENV, BROWSERSTACK_PERCY, BROWSERSTACK_ACCESSIBILITY, BROWSERSTACK_OBSERVABILITY, BROWSERSTACK_TEST_REPORTING, TEST_REPORTING_PROJECT_NAME, MAX_GIT_META_DATA_SIZE_IN_BYTES, GIT_META_DATA_TRUNCATED, CLI_STOP_TIMEOUT, BINARY_BUSY_ERROR_CODES, MAX_SPAWN_RETRIES, SPAWN_RETRY_DELAY_MS, WDIO_NAMING_PREFIX, UPDATED_CLI_ENDPOINT;
|
|
105
|
+
var bstackServiceVersion, BROWSER_DESCRIPTION, VALID_APP_EXTENSION, DEFAULT_OPTIONS, consoleHolder, APP_ALLY_ISSUES_ENDPOINT, APP_ALLY_ISSUES_SUMMARY_ENDPOINT, DATA_EVENT_ENDPOINT, DATA_BATCH_ENDPOINT, DATA_SCREENSHOT_ENDPOINT, DATA_BATCH_SIZE, DATA_BATCH_INTERVAL, DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS, DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS, BSTACK_SERVICE_VERSION, NOT_ALLOWED_KEYS_IN_CAPS, BROWSERSTACK_TEST_PLAN_ID, LOGS_FILE, CLI_DEBUG_LOGS_FILE, UPLOAD_LOGS_ENDPOINT, PERCY_LOGS_FILE, PERCY_DOM_CHANGING_COMMANDS_ENDPOINTS, CAPTURE_MODES, LOG_KIND_USAGE_MAP, SUPPORTED_BROWSERS_FOR_AI, SUPPORTED_BROWSERS_FOR_ACCESSIBILITY, MIN_BROWSER_VERSIONS_A11Y, MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK, TCG_URL, TCG_INFO, SMART_SELECTION_MODE_RELEVANT_FIRST, SMART_SELECTION_MODE_RELEVANT_ONLY, BROWSERSTACK_TESTHUB_JWT, BSTACK_TCG_AUTH_RESULT, TESTOPS_SCREENSHOT_ENV, BROWSERSTACK_TESTHUB_UUID, TEST_ANALYTICS_ID, PERF_MEASUREMENT_ENV, RERUN_TESTS_ENV, RERUN_ENV, TESTOPS_BUILD_COMPLETED_ENV, BROWSERSTACK_PERCY, BROWSERSTACK_ACCESSIBILITY, BROWSERSTACK_OBSERVABILITY, BROWSERSTACK_TEST_REPORTING, TEST_REPORTING_PROJECT_NAME, MAX_GIT_META_DATA_SIZE_IN_BYTES, GIT_META_DATA_TRUNCATED, CLI_STOP_TIMEOUT, BINARY_BUSY_ERROR_CODES, MAX_SPAWN_RETRIES, SPAWN_RETRY_DELAY_MS, WDIO_NAMING_PREFIX, UPDATED_CLI_ENDPOINT;
|
|
101
106
|
var init_constants = __esm({
|
|
102
107
|
"src/constants.ts"() {
|
|
103
108
|
"use strict";
|
|
@@ -157,6 +162,17 @@ var init_constants = __esm({
|
|
|
157
162
|
"HTTP": "http"
|
|
158
163
|
};
|
|
159
164
|
SUPPORTED_BROWSERS_FOR_AI = ["chrome", "microsoftedge", "firefox"];
|
|
165
|
+
SUPPORTED_BROWSERS_FOR_ACCESSIBILITY = ["chrome", "chromefortesting", "safari"];
|
|
166
|
+
MIN_BROWSER_VERSIONS_A11Y = {
|
|
167
|
+
chrome: 95,
|
|
168
|
+
chromefortesting: 141,
|
|
169
|
+
safari: 18.4
|
|
170
|
+
};
|
|
171
|
+
MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK = {
|
|
172
|
+
chrome: 100,
|
|
173
|
+
chromefortesting: 141,
|
|
174
|
+
safari: 18.4
|
|
175
|
+
};
|
|
160
176
|
TCG_URL = "https://tcg.browserstack.com";
|
|
161
177
|
TCG_INFO = {
|
|
162
178
|
tcgRegion: "use",
|
|
@@ -268,34 +284,155 @@ var init_apiUtils = __esm({
|
|
|
268
284
|
}
|
|
269
285
|
});
|
|
270
286
|
|
|
287
|
+
// src/caCert.ts
|
|
288
|
+
import { setGlobalDispatcher, Agent } from "undici";
|
|
289
|
+
import tls from "node:tls";
|
|
290
|
+
import fs from "node:fs";
|
|
291
|
+
import os from "node:os";
|
|
292
|
+
import path from "node:path";
|
|
293
|
+
function derToPem(der) {
|
|
294
|
+
const b64 = der.toString("base64").replace(/(.{64})/g, "$1\n");
|
|
295
|
+
return `-----BEGIN CERTIFICATE-----
|
|
296
|
+
${b64}${b64.endsWith("\n") ? "" : "\n"}-----END CERTIFICATE-----
|
|
297
|
+
`;
|
|
298
|
+
}
|
|
299
|
+
function loadCaCertsAsPem(buf) {
|
|
300
|
+
if (buf.includes("-----BEGIN CERTIFICATE-----")) {
|
|
301
|
+
return buf.toString("utf8").match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g) || [];
|
|
302
|
+
}
|
|
303
|
+
return [derToPem(buf)];
|
|
304
|
+
}
|
|
305
|
+
function resolveCaCertPath(options) {
|
|
306
|
+
let p = process.env.BROWSERSTACK_EXTRA_CA_CERTS;
|
|
307
|
+
if ((!p || !p.trim()) && options?.proxyCaCertificate) {
|
|
308
|
+
p = options.proxyCaCertificate;
|
|
309
|
+
}
|
|
310
|
+
if (!p || !String(p).trim()) {
|
|
311
|
+
return void 0;
|
|
312
|
+
}
|
|
313
|
+
p = String(p).trim();
|
|
314
|
+
try {
|
|
315
|
+
if (fs.existsSync(p) && fs.statSync(p).isFile()) {
|
|
316
|
+
return p;
|
|
317
|
+
}
|
|
318
|
+
BStackLogger.warn(`proxyCaCertificate: path does not exist or is not a file, falling back to system trust store: ${p}`);
|
|
319
|
+
} catch (e) {
|
|
320
|
+
BStackLogger.warn(`proxyCaCertificate: failed to stat cert path ${p}: ${e.message}`);
|
|
321
|
+
}
|
|
322
|
+
return void 0;
|
|
323
|
+
}
|
|
324
|
+
function getMergedCa() {
|
|
325
|
+
return mergedCa;
|
|
326
|
+
}
|
|
327
|
+
function configureCaCertificate(options) {
|
|
328
|
+
if (configured) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
try {
|
|
332
|
+
const certPath = resolveCaCertPath(options);
|
|
333
|
+
if (!certPath) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const buf = fs.readFileSync(certPath);
|
|
337
|
+
const isPem = buf.includes("-----BEGIN CERTIFICATE-----");
|
|
338
|
+
const pemCerts = loadCaCertsAsPem(buf);
|
|
339
|
+
if (!pemCerts.length) {
|
|
340
|
+
BStackLogger.warn(`proxyCaCertificate: no certificate found in ${certPath}; falling back to system trust store.`);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
mergedCa = [...tls.rootCertificates, ...pemCerts];
|
|
344
|
+
setGlobalDispatcher(new Agent({ connect: { ca: mergedCa } }));
|
|
345
|
+
configured = true;
|
|
346
|
+
BStackLogger.info(`proxyCaCertificate: trusting custom CA from ${certPath} (merged with system roots).`);
|
|
347
|
+
try {
|
|
348
|
+
if (!process.env.NODE_EXTRA_CA_CERTS) {
|
|
349
|
+
let nodeExtra = certPath;
|
|
350
|
+
if (!isPem) {
|
|
351
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "browserstack_sdk_ca_"));
|
|
352
|
+
nodeExtra = path.join(tmpDir, "ca.pem");
|
|
353
|
+
const fd = fs.openSync(nodeExtra, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL | (fs.constants.O_NOFOLLOW || 0), 384);
|
|
354
|
+
try {
|
|
355
|
+
fs.writeFileSync(fd, pemCerts.join(""));
|
|
356
|
+
} finally {
|
|
357
|
+
fs.closeSync(fd);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
process.env.NODE_EXTRA_CA_CERTS = nodeExtra;
|
|
361
|
+
}
|
|
362
|
+
} catch (e) {
|
|
363
|
+
BStackLogger.warn(`proxyCaCertificate: CA is trusted for this process, but exporting NODE_EXTRA_CA_CERTS for detached child processes failed (children may not trust the custom CA): ${e.message}`);
|
|
364
|
+
}
|
|
365
|
+
} catch (e) {
|
|
366
|
+
BStackLogger.warn(`proxyCaCertificate: setup failed, falling back to system trust store: ${e.message}`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
var mergedCa, configured;
|
|
370
|
+
var init_caCert = __esm({
|
|
371
|
+
"src/caCert.ts"() {
|
|
372
|
+
"use strict";
|
|
373
|
+
init_bstackLogger();
|
|
374
|
+
configured = false;
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
|
|
271
378
|
// src/fetchWrapper.ts
|
|
272
|
-
import { fetch as undiciFetch, ProxyAgent } from "undici";
|
|
273
|
-
|
|
274
|
-
const
|
|
379
|
+
import { fetch as undiciFetch, ProxyAgent, Agent as Agent2 } from "undici";
|
|
380
|
+
function getDispatcher(proxyUrl, connectTimeoutMs) {
|
|
381
|
+
const ca = getMergedCa();
|
|
382
|
+
const key = `${proxyUrl ?? "direct"}:${connectTimeoutMs ?? "default"}:${ca ? "ca" : "noca"}`;
|
|
383
|
+
let dispatcher = dispatcherCache.get(key);
|
|
384
|
+
if (!dispatcher) {
|
|
385
|
+
const connect = {};
|
|
386
|
+
if (connectTimeoutMs) {
|
|
387
|
+
connect.timeout = connectTimeoutMs;
|
|
388
|
+
}
|
|
389
|
+
if (proxyUrl) {
|
|
390
|
+
dispatcher = new ProxyAgent({ uri: proxyUrl, connect, ...ca ? { requestTls: { ca } } : {} });
|
|
391
|
+
} else {
|
|
392
|
+
if (ca) {
|
|
393
|
+
connect.ca = ca;
|
|
394
|
+
}
|
|
395
|
+
dispatcher = new Agent2({ connect });
|
|
396
|
+
}
|
|
397
|
+
dispatcherCache.set(key, dispatcher);
|
|
398
|
+
}
|
|
399
|
+
return dispatcher;
|
|
400
|
+
}
|
|
401
|
+
async function fetchWrap(input, init, options) {
|
|
402
|
+
const res = await _fetch(input, init, options);
|
|
275
403
|
if (!res.ok) {
|
|
276
404
|
throw new ResponseError(`Error response from server ${res.status}: ${await res.text()}`, res);
|
|
277
405
|
}
|
|
278
406
|
return res;
|
|
279
407
|
}
|
|
280
|
-
function _fetch(input, init) {
|
|
408
|
+
function _fetch(input, init, options) {
|
|
409
|
+
const connectTimeoutMs = options?.connectTimeoutMs;
|
|
281
410
|
const proxyUrl = process.env.HTTP_PROXY || process.env.HTTPS_PROXY;
|
|
282
411
|
if (proxyUrl) {
|
|
283
412
|
const noProxy = process.env.NO_PROXY && process.env.NO_PROXY.trim() ? process.env.NO_PROXY.trim().split(/[\s,;]+/) : [];
|
|
284
413
|
const request = new Request(input);
|
|
285
414
|
const url3 = new URL(request.url);
|
|
286
415
|
if (!noProxy.some((str) => url3.hostname.endsWith(str))) {
|
|
416
|
+
const dispatcher = getDispatcher(proxyUrl, connectTimeoutMs);
|
|
287
417
|
return undiciFetch(
|
|
288
418
|
request.url,
|
|
289
|
-
{ ...init, dispatcher
|
|
419
|
+
{ ...init, dispatcher }
|
|
290
420
|
);
|
|
291
421
|
}
|
|
292
422
|
}
|
|
423
|
+
if (connectTimeoutMs) {
|
|
424
|
+
return undiciFetch(
|
|
425
|
+
new Request(input).url,
|
|
426
|
+
{ ...init, dispatcher: getDispatcher(void 0, connectTimeoutMs) }
|
|
427
|
+
);
|
|
428
|
+
}
|
|
293
429
|
return fetch(input, init);
|
|
294
430
|
}
|
|
295
|
-
var ResponseError;
|
|
431
|
+
var ResponseError, dispatcherCache;
|
|
296
432
|
var init_fetchWrapper = __esm({
|
|
297
433
|
"src/fetchWrapper.ts"() {
|
|
298
434
|
"use strict";
|
|
435
|
+
init_caCert();
|
|
299
436
|
ResponseError = class extends Error {
|
|
300
437
|
response;
|
|
301
438
|
constructor(message, res) {
|
|
@@ -303,6 +440,7 @@ var init_fetchWrapper = __esm({
|
|
|
303
440
|
this.response = res;
|
|
304
441
|
}
|
|
305
442
|
};
|
|
443
|
+
dispatcherCache = /* @__PURE__ */ new Map();
|
|
306
444
|
}
|
|
307
445
|
});
|
|
308
446
|
|
|
@@ -460,26 +598,26 @@ var init_constants2 = __esm({
|
|
|
460
598
|
});
|
|
461
599
|
|
|
462
600
|
// src/cli/cliLogger.ts
|
|
463
|
-
import
|
|
464
|
-
import
|
|
601
|
+
import path2 from "node:path";
|
|
602
|
+
import fs2 from "node:fs";
|
|
465
603
|
import chalk from "chalk";
|
|
466
604
|
import logger from "@wdio/logger";
|
|
467
|
-
var log,
|
|
605
|
+
var log, BStackLogger2;
|
|
468
606
|
var init_cliLogger = __esm({
|
|
469
607
|
"src/cli/cliLogger.ts"() {
|
|
470
608
|
"use strict";
|
|
471
609
|
init_constants();
|
|
472
610
|
init_util();
|
|
473
611
|
log = logger("@wdio/browserstack-service/cli");
|
|
474
|
-
|
|
475
|
-
static logFilePath =
|
|
476
|
-
static logFolderPath =
|
|
612
|
+
BStackLogger2 = class {
|
|
613
|
+
static logFilePath = path2.join(process.cwd(), LOGS_FILE);
|
|
614
|
+
static logFolderPath = path2.join(process.cwd(), "logs");
|
|
477
615
|
static logFileStream;
|
|
478
616
|
static logToFile(logMessage, logLevel) {
|
|
479
617
|
try {
|
|
480
618
|
if (!this.logFileStream) {
|
|
481
619
|
this.ensureLogsFolder();
|
|
482
|
-
this.logFileStream =
|
|
620
|
+
this.logFileStream = fs2.createWriteStream(this.logFilePath, { flags: "a" });
|
|
483
621
|
}
|
|
484
622
|
if (this.logFileStream && this.logFileStream.writable) {
|
|
485
623
|
this.logFileStream.write(this.formatLog(logMessage, logLevel));
|
|
@@ -523,13 +661,13 @@ var init_cliLogger = __esm({
|
|
|
523
661
|
this.logFileStream = null;
|
|
524
662
|
}
|
|
525
663
|
static clearLogFile() {
|
|
526
|
-
if (
|
|
527
|
-
|
|
664
|
+
if (fs2.existsSync(this.logFilePath)) {
|
|
665
|
+
fs2.truncateSync(this.logFilePath);
|
|
528
666
|
}
|
|
529
667
|
}
|
|
530
668
|
static ensureLogsFolder() {
|
|
531
|
-
if (!
|
|
532
|
-
|
|
669
|
+
if (!fs2.existsSync(this.logFolderPath)) {
|
|
670
|
+
fs2.mkdirSync(this.logFolderPath);
|
|
533
671
|
}
|
|
534
672
|
}
|
|
535
673
|
};
|
|
@@ -587,16 +725,16 @@ var init_testFrameworkConstants = __esm({
|
|
|
587
725
|
});
|
|
588
726
|
|
|
589
727
|
// src/cli/cliUtils.ts
|
|
590
|
-
import
|
|
728
|
+
import fs3 from "node:fs";
|
|
591
729
|
import fsp from "node:fs/promises";
|
|
592
730
|
import { platform, arch, homedir } from "node:os";
|
|
593
|
-
import
|
|
731
|
+
import path3 from "node:path";
|
|
594
732
|
import util, { promisify } from "node:util";
|
|
595
733
|
import { exec } from "node:child_process";
|
|
596
734
|
import { Readable } from "node:stream";
|
|
597
735
|
import yauzl from "yauzl";
|
|
598
736
|
import { threadId } from "node:worker_threads";
|
|
599
|
-
var CLI_LOCK_TIMEOUT_MS, CLI_LOCK_POLL_MS, CLI_DOWNLOAD_TIMEOUT_MS, CLI_DOWNLOAD_TMP_PREFIX, CLI_DOWNLOAD_TMP_SUFFIX, CLIUtils;
|
|
737
|
+
var CLI_LOCK_TIMEOUT_MS, CLI_LOCK_POLL_MS, CLI_DOWNLOAD_TIMEOUT_MS, CLI_DOWNLOAD_TMP_PREFIX, CLI_DOWNLOAD_TMP_SUFFIX, CLI_CONNECT_TIMEOUT_MS, CLI_FETCH_MAX_ATTEMPTS, CLI_FETCH_RETRY_BASE_DELAY_MS, CLIUtils;
|
|
600
738
|
var init_cliUtils = __esm({
|
|
601
739
|
"src/cli/cliUtils.ts"() {
|
|
602
740
|
"use strict";
|
|
@@ -613,6 +751,9 @@ var init_cliUtils = __esm({
|
|
|
613
751
|
CLI_DOWNLOAD_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
614
752
|
CLI_DOWNLOAD_TMP_PREFIX = "downloaded_file_";
|
|
615
753
|
CLI_DOWNLOAD_TMP_SUFFIX = ".zip";
|
|
754
|
+
CLI_CONNECT_TIMEOUT_MS = Number(process.env.BROWSERSTACK_CLI_CONNECT_TIMEOUT_MS) || 60 * 1e3;
|
|
755
|
+
CLI_FETCH_MAX_ATTEMPTS = 3;
|
|
756
|
+
CLI_FETCH_RETRY_BASE_DELAY_MS = 500;
|
|
616
757
|
CLIUtils = class _CLIUtils {
|
|
617
758
|
static automationFrameworkDetail = {};
|
|
618
759
|
static testFrameworkDetail = {};
|
|
@@ -699,10 +840,10 @@ var init_cliUtils = __esm({
|
|
|
699
840
|
return "ECMAScript";
|
|
700
841
|
}
|
|
701
842
|
static async setupCliPath(config) {
|
|
702
|
-
|
|
843
|
+
BStackLogger2.debug("Configuring Cli path.");
|
|
703
844
|
const developmentBinaryPath = process.env.SDK_CLI_BIN_PATH || null;
|
|
704
845
|
if (!isNullOrEmpty(developmentBinaryPath)) {
|
|
705
|
-
|
|
846
|
+
BStackLogger2.debug(`Development Cli Path: ${developmentBinaryPath}`);
|
|
706
847
|
return developmentBinaryPath;
|
|
707
848
|
}
|
|
708
849
|
try {
|
|
@@ -716,10 +857,10 @@ var init_cliUtils = __esm({
|
|
|
716
857
|
cliDir,
|
|
717
858
|
config
|
|
718
859
|
);
|
|
719
|
-
|
|
860
|
+
BStackLogger2.debug(`Resolved binary path: ${finalBinaryPath}`);
|
|
720
861
|
return finalBinaryPath;
|
|
721
862
|
} catch (err) {
|
|
722
|
-
|
|
863
|
+
BStackLogger2.warn(
|
|
723
864
|
`Error in setting up cli path directory, Exception: ${util.format(err)}`
|
|
724
865
|
);
|
|
725
866
|
}
|
|
@@ -727,18 +868,18 @@ var init_cliUtils = __esm({
|
|
|
727
868
|
}
|
|
728
869
|
static async checkAndUpdateCli(existingCliPath, cliDir, config) {
|
|
729
870
|
if (process.env.BROWSERSTACK_TESTHUB_JWT) {
|
|
730
|
-
|
|
871
|
+
BStackLogger2.debug(
|
|
731
872
|
`Worker process detected, skipping CLI update. Using existing: ${existingCliPath}`
|
|
732
873
|
);
|
|
733
|
-
if (existingCliPath &&
|
|
874
|
+
if (existingCliPath && fs3.existsSync(existingCliPath)) {
|
|
734
875
|
return existingCliPath;
|
|
735
876
|
}
|
|
736
|
-
|
|
877
|
+
BStackLogger2.warn(
|
|
737
878
|
"Worker process has no existing CLI binary, attempting download as fallback."
|
|
738
879
|
);
|
|
739
880
|
}
|
|
740
881
|
PerformanceTester.start(EVENTS.SDK_CLI_CHECK_UPDATE);
|
|
741
|
-
|
|
882
|
+
BStackLogger2.info(`Current CLI Path Found: ${existingCliPath}`);
|
|
742
883
|
const queryParams = {
|
|
743
884
|
sdk_version: _CLIUtils.getSdkVersion(),
|
|
744
885
|
os: platform(),
|
|
@@ -748,7 +889,7 @@ var init_cliUtils = __esm({
|
|
|
748
889
|
};
|
|
749
890
|
if (!isNullOrEmpty(existingCliPath)) {
|
|
750
891
|
if (this.isBinaryBusy(existingCliPath)) {
|
|
751
|
-
|
|
892
|
+
BStackLogger2.warn(`Existing binary is currently in use, skipping update: ${existingCliPath}`);
|
|
752
893
|
PerformanceTester.end(EVENTS.SDK_CLI_CHECK_UPDATE);
|
|
753
894
|
return existingCliPath;
|
|
754
895
|
}
|
|
@@ -756,7 +897,7 @@ var init_cliUtils = __esm({
|
|
|
756
897
|
`${existingCliPath} version`
|
|
757
898
|
);
|
|
758
899
|
if (version3.toLowerCase().includes("text file busy")) {
|
|
759
|
-
|
|
900
|
+
BStackLogger2.warn(`Binary busy during version check, skipping update: ${existingCliPath}`);
|
|
760
901
|
PerformanceTester.end(EVENTS.SDK_CLI_CHECK_UPDATE);
|
|
761
902
|
return existingCliPath;
|
|
762
903
|
}
|
|
@@ -764,12 +905,12 @@ var init_cliUtils = __esm({
|
|
|
764
905
|
}
|
|
765
906
|
const response = await this.requestToUpdateCLI(queryParams, config);
|
|
766
907
|
if (nestedKeyValue(response, ["updated_cli_version"])) {
|
|
767
|
-
|
|
908
|
+
BStackLogger2.debug(
|
|
768
909
|
`Need to update binary, current binary version: ${queryParams.cli_version}`
|
|
769
910
|
);
|
|
770
911
|
const browserStackBinaryUrl = process.env.BROWSERSTACK_BINARY_URL || null;
|
|
771
912
|
if (!isNullOrEmpty(browserStackBinaryUrl)) {
|
|
772
|
-
|
|
913
|
+
BStackLogger2.debug(
|
|
773
914
|
`Using BROWSERSTACK_BINARY_URL: ${browserStackBinaryUrl}`
|
|
774
915
|
);
|
|
775
916
|
response.url = browserStackBinaryUrl;
|
|
@@ -790,13 +931,13 @@ var init_cliUtils = __esm({
|
|
|
790
931
|
if (isNullOrEmpty(writableDir)) {
|
|
791
932
|
throw new Error("No writable directory available for the CLI");
|
|
792
933
|
}
|
|
793
|
-
const cliDirPath =
|
|
794
|
-
if (!
|
|
934
|
+
const cliDirPath = path3.join(writableDir, "cli");
|
|
935
|
+
if (!fs3.existsSync(cliDirPath)) {
|
|
795
936
|
createDir(cliDirPath);
|
|
796
937
|
}
|
|
797
938
|
return cliDirPath;
|
|
798
939
|
} catch (err) {
|
|
799
|
-
|
|
940
|
+
BStackLogger2.error(
|
|
800
941
|
`Error in getting writable directory, writableDir=${util.format(err)}`
|
|
801
942
|
);
|
|
802
943
|
return "";
|
|
@@ -805,39 +946,39 @@ var init_cliUtils = __esm({
|
|
|
805
946
|
static getWritableDir() {
|
|
806
947
|
const writableDirOptions = [
|
|
807
948
|
process.env.BROWSERSTACK_FILES_DIR,
|
|
808
|
-
|
|
809
|
-
|
|
949
|
+
path3.join(homedir(), ".browserstack"),
|
|
950
|
+
path3.join("tmp", ".browserstack")
|
|
810
951
|
];
|
|
811
|
-
for (const
|
|
812
|
-
if (isNullOrEmpty(
|
|
952
|
+
for (const path22 of writableDirOptions) {
|
|
953
|
+
if (isNullOrEmpty(path22)) {
|
|
813
954
|
continue;
|
|
814
955
|
}
|
|
815
956
|
try {
|
|
816
|
-
if (
|
|
817
|
-
|
|
818
|
-
if (!isWritable(
|
|
819
|
-
|
|
820
|
-
const success = setReadWriteAccess(
|
|
957
|
+
if (fs3.existsSync(path22)) {
|
|
958
|
+
BStackLogger2.debug(`File ${path22} already exist`);
|
|
959
|
+
if (!isWritable(path22)) {
|
|
960
|
+
BStackLogger2.debug(`Giving write permission to ${path22}`);
|
|
961
|
+
const success = setReadWriteAccess(path22);
|
|
821
962
|
if (!isTrue(success)) {
|
|
822
|
-
|
|
823
|
-
`Unable to provide write permission to ${
|
|
963
|
+
BStackLogger2.warn(
|
|
964
|
+
`Unable to provide write permission to ${path22}`
|
|
824
965
|
);
|
|
825
966
|
}
|
|
826
967
|
}
|
|
827
968
|
} else {
|
|
828
|
-
|
|
829
|
-
createDir(
|
|
830
|
-
|
|
831
|
-
const success = setReadWriteAccess(
|
|
969
|
+
BStackLogger2.debug(`File does not exist: ${path22}`);
|
|
970
|
+
createDir(path22);
|
|
971
|
+
BStackLogger2.debug(`Giving write permission to ${path22}`);
|
|
972
|
+
const success = setReadWriteAccess(path22);
|
|
832
973
|
if (!isTrue(success)) {
|
|
833
|
-
|
|
834
|
-
`Unable to provide write permission to ${
|
|
974
|
+
BStackLogger2.warn(
|
|
975
|
+
`Unable to provide write permission to ${path22}`
|
|
835
976
|
);
|
|
836
977
|
}
|
|
837
978
|
}
|
|
838
|
-
return
|
|
979
|
+
return path22;
|
|
839
980
|
} catch (err) {
|
|
840
|
-
|
|
981
|
+
BStackLogger2.error(
|
|
841
982
|
`Unable to get writable directory, exception ${util.format(err)}`
|
|
842
983
|
);
|
|
843
984
|
}
|
|
@@ -846,16 +987,16 @@ var init_cliUtils = __esm({
|
|
|
846
987
|
}
|
|
847
988
|
static getExistingCliPath(cliDir) {
|
|
848
989
|
try {
|
|
849
|
-
if (!
|
|
990
|
+
if (!fs3.existsSync(cliDir) || !fs3.statSync(cliDir).isDirectory()) {
|
|
850
991
|
return "";
|
|
851
992
|
}
|
|
852
|
-
const allBinaries =
|
|
853
|
-
(filePath) =>
|
|
993
|
+
const allBinaries = fs3.readdirSync(cliDir).map((file) => path3.join(cliDir, file)).filter(
|
|
994
|
+
(filePath) => fs3.statSync(filePath).isFile() && path3.basename(filePath).startsWith("binary-")
|
|
854
995
|
);
|
|
855
996
|
if (allBinaries.length > 0) {
|
|
856
997
|
const latestBinary = allBinaries.map((filePath) => ({
|
|
857
998
|
filePath,
|
|
858
|
-
mtime:
|
|
999
|
+
mtime: fs3.statSync(filePath).mtime
|
|
859
1000
|
})).reduce(
|
|
860
1001
|
(latest, current) => {
|
|
861
1002
|
if (!latest || !latest.mtime) {
|
|
@@ -872,7 +1013,7 @@ var init_cliUtils = __esm({
|
|
|
872
1013
|
}
|
|
873
1014
|
return "";
|
|
874
1015
|
} catch (err) {
|
|
875
|
-
|
|
1016
|
+
BStackLogger2.error(`Error while reading CLI path: ${util.format(err)}`);
|
|
876
1017
|
return "";
|
|
877
1018
|
}
|
|
878
1019
|
}
|
|
@@ -883,22 +1024,51 @@ var init_cliUtils = __esm({
|
|
|
883
1024
|
if (platform() === "darwin") {
|
|
884
1025
|
return false;
|
|
885
1026
|
}
|
|
886
|
-
if (!
|
|
1027
|
+
if (!fs3.existsSync(binaryPath)) {
|
|
887
1028
|
return false;
|
|
888
1029
|
}
|
|
889
1030
|
try {
|
|
890
|
-
const fd =
|
|
891
|
-
|
|
1031
|
+
const fd = fs3.openSync(binaryPath, "r+");
|
|
1032
|
+
fs3.closeSync(fd);
|
|
892
1033
|
return false;
|
|
893
1034
|
} catch (err) {
|
|
894
1035
|
if (BINARY_BUSY_ERROR_CODES.includes(err.code)) {
|
|
895
|
-
|
|
1036
|
+
BStackLogger2.debug(`Binary is busy: ${binaryPath}`);
|
|
896
1037
|
return true;
|
|
897
1038
|
}
|
|
898
|
-
|
|
1039
|
+
BStackLogger2.debug(`Error checking if binary is busy: ${err.message}`);
|
|
899
1040
|
return false;
|
|
900
1041
|
}
|
|
901
1042
|
}
|
|
1043
|
+
/**
|
|
1044
|
+
* fetch wrapper for CLI network calls that (a) raises undici's connect timeout
|
|
1045
|
+
* above the non-overridable 10s default of global fetch and (b) retries a few
|
|
1046
|
+
* times with linear backoff on transient connection failures. Both are needed
|
|
1047
|
+
* for reliability in constrained CI/containerised networks (SDK-6152).
|
|
1048
|
+
*/
|
|
1049
|
+
static fetchWithRetry = async (input, init, label) => {
|
|
1050
|
+
let lastError;
|
|
1051
|
+
for (let attempt = 1; attempt <= CLI_FETCH_MAX_ATTEMPTS; attempt++) {
|
|
1052
|
+
try {
|
|
1053
|
+
return await _fetch(input, init, { connectTimeoutMs: CLI_CONNECT_TIMEOUT_MS });
|
|
1054
|
+
} catch (err) {
|
|
1055
|
+
lastError = err;
|
|
1056
|
+
const reason = (
|
|
1057
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1058
|
+
err?.cause?.code || err?.code || err?.message
|
|
1059
|
+
);
|
|
1060
|
+
BStackLogger2.warn(
|
|
1061
|
+
`${label} attempt ${attempt}/${CLI_FETCH_MAX_ATTEMPTS} failed: ${reason}`
|
|
1062
|
+
);
|
|
1063
|
+
if (attempt < CLI_FETCH_MAX_ATTEMPTS) {
|
|
1064
|
+
await new Promise(
|
|
1065
|
+
(resolve) => setTimeout(resolve, CLI_FETCH_RETRY_BASE_DELAY_MS * attempt)
|
|
1066
|
+
);
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
throw lastError;
|
|
1071
|
+
};
|
|
902
1072
|
static requestToUpdateCLI = async (queryParams, config) => {
|
|
903
1073
|
const params = new URLSearchParams(queryParams);
|
|
904
1074
|
const requestInit = {
|
|
@@ -907,12 +1077,13 @@ var init_cliUtils = __esm({
|
|
|
907
1077
|
Authorization: `Basic ${Buffer.from(`${getBrowserStackUser(config)}:${getBrowserStackKey(config)}`).toString("base64")}`
|
|
908
1078
|
}
|
|
909
1079
|
};
|
|
910
|
-
const response = await
|
|
1080
|
+
const response = await this.fetchWithRetry(
|
|
911
1081
|
`${APIUtils.BROWSERSTACK_AUTOMATE_API_URL}/${UPDATED_CLI_ENDPOINT}?${params.toString()}`,
|
|
912
|
-
requestInit
|
|
1082
|
+
requestInit,
|
|
1083
|
+
"update_cli request"
|
|
913
1084
|
);
|
|
914
1085
|
const jsonResponse = await response.json();
|
|
915
|
-
|
|
1086
|
+
BStackLogger2.debug(`response ${JSON.stringify(jsonResponse)}`);
|
|
916
1087
|
return jsonResponse;
|
|
917
1088
|
};
|
|
918
1089
|
static runShellCommand(cmdCommand, workingDir = "") {
|
|
@@ -934,11 +1105,11 @@ var init_cliUtils = __esm({
|
|
|
934
1105
|
});
|
|
935
1106
|
}
|
|
936
1107
|
static downloadLatestBinary = async (binDownloadUrl, cliDir) => {
|
|
937
|
-
const lockPath =
|
|
1108
|
+
const lockPath = path3.join(cliDir, "download.lock");
|
|
938
1109
|
const sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
939
1110
|
const parseLockFile = () => {
|
|
940
1111
|
try {
|
|
941
|
-
const content =
|
|
1112
|
+
const content = fs3.readFileSync(lockPath, "utf8").trim();
|
|
942
1113
|
const [pidLine, timestampLine] = content.split("\n");
|
|
943
1114
|
const pid = Number.parseInt(pidLine, 10);
|
|
944
1115
|
const timestamp = Number.parseInt(timestampLine, 10);
|
|
@@ -962,20 +1133,20 @@ var init_cliUtils = __esm({
|
|
|
962
1133
|
const start = Date.now();
|
|
963
1134
|
while (true) {
|
|
964
1135
|
try {
|
|
965
|
-
const fd =
|
|
1136
|
+
const fd = fs3.openSync(lockPath, "wx");
|
|
966
1137
|
try {
|
|
967
|
-
|
|
1138
|
+
fs3.writeFileSync(fd, `${process.pid}
|
|
968
1139
|
${Date.now()}
|
|
969
1140
|
`);
|
|
970
1141
|
} catch {
|
|
971
1142
|
}
|
|
972
1143
|
return () => {
|
|
973
1144
|
try {
|
|
974
|
-
|
|
1145
|
+
fs3.closeSync(fd);
|
|
975
1146
|
} catch {
|
|
976
1147
|
}
|
|
977
1148
|
try {
|
|
978
|
-
|
|
1149
|
+
fs3.unlinkSync(lockPath);
|
|
979
1150
|
} catch {
|
|
980
1151
|
}
|
|
981
1152
|
};
|
|
@@ -987,19 +1158,19 @@ ${Date.now()}
|
|
|
987
1158
|
const lockAge = Date.now() - lockMeta.timestamp;
|
|
988
1159
|
const running = isProcessRunning(lockMeta.pid);
|
|
989
1160
|
if (!running || lockAge > timeoutMs) {
|
|
990
|
-
|
|
1161
|
+
BStackLogger2.warn(
|
|
991
1162
|
`Stale CLI download lock detected (pid=${lockMeta.pid}, age=${lockAge}ms). Removing lock.`
|
|
992
1163
|
);
|
|
993
1164
|
try {
|
|
994
|
-
|
|
1165
|
+
fs3.unlinkSync(lockPath);
|
|
995
1166
|
} catch {
|
|
996
1167
|
}
|
|
997
1168
|
continue;
|
|
998
1169
|
}
|
|
999
1170
|
}
|
|
1000
1171
|
const existingBinary = _CLIUtils.getExistingCliPath(cliDir);
|
|
1001
|
-
if (existingBinary &&
|
|
1002
|
-
|
|
1172
|
+
if (existingBinary && fs3.existsSync(existingBinary) && fs3.statSync(existingBinary).size > 0) {
|
|
1173
|
+
BStackLogger2.debug(
|
|
1003
1174
|
`Binary appeared while waiting for lock: ${existingBinary}`
|
|
1004
1175
|
);
|
|
1005
1176
|
return { alreadyExists: existingBinary };
|
|
@@ -1020,16 +1191,16 @@ ${Date.now()}
|
|
|
1020
1191
|
try {
|
|
1021
1192
|
const now2 = Date.now();
|
|
1022
1193
|
const tmpExtractRe = /\.tmp\.\d+$/;
|
|
1023
|
-
for (const entry of
|
|
1194
|
+
for (const entry of fs3.readdirSync(cliDir)) {
|
|
1024
1195
|
const isDownloadZip = entry.startsWith(CLI_DOWNLOAD_TMP_PREFIX) && entry.endsWith(CLI_DOWNLOAD_TMP_SUFFIX);
|
|
1025
1196
|
const isExtractTmp = tmpExtractRe.test(entry);
|
|
1026
1197
|
if (!isDownloadZip && !isExtractTmp) {
|
|
1027
1198
|
continue;
|
|
1028
1199
|
}
|
|
1029
|
-
const filePath =
|
|
1200
|
+
const filePath = path3.join(cliDir, entry);
|
|
1030
1201
|
let stats;
|
|
1031
1202
|
try {
|
|
1032
|
-
stats =
|
|
1203
|
+
stats = fs3.statSync(filePath);
|
|
1033
1204
|
} catch {
|
|
1034
1205
|
continue;
|
|
1035
1206
|
}
|
|
@@ -1037,21 +1208,21 @@ ${Date.now()}
|
|
|
1037
1208
|
continue;
|
|
1038
1209
|
}
|
|
1039
1210
|
try {
|
|
1040
|
-
|
|
1211
|
+
fs3.unlinkSync(filePath);
|
|
1041
1212
|
} catch (err) {
|
|
1042
|
-
|
|
1213
|
+
BStackLogger2.debug(
|
|
1043
1214
|
`Failed to delete temp CLI file ${filePath}: ${util.format(err)}`
|
|
1044
1215
|
);
|
|
1045
1216
|
}
|
|
1046
1217
|
}
|
|
1047
1218
|
} catch (err) {
|
|
1048
|
-
|
|
1219
|
+
BStackLogger2.debug(
|
|
1049
1220
|
`Failed to scan temp CLI files in ${cliDir}: ${util.format(err)}`
|
|
1050
1221
|
);
|
|
1051
1222
|
}
|
|
1052
1223
|
};
|
|
1053
1224
|
PerformanceTester.start(EVENTS.SDK_CLI_DOWNLOAD);
|
|
1054
|
-
|
|
1225
|
+
BStackLogger2.debug(`Downloading SDK binary from: ${binDownloadUrl}`);
|
|
1055
1226
|
let downloadEnded = false;
|
|
1056
1227
|
const endDownload = (success = true, errMsg) => {
|
|
1057
1228
|
if (downloadEnded) {
|
|
@@ -1077,8 +1248,8 @@ ${Date.now()}
|
|
|
1077
1248
|
}
|
|
1078
1249
|
releaseLock = lockResult;
|
|
1079
1250
|
const existingBinary = _CLIUtils.getExistingCliPath(cliDir);
|
|
1080
|
-
if (existingBinary &&
|
|
1081
|
-
|
|
1251
|
+
if (existingBinary && fs3.existsSync(existingBinary) && fs3.statSync(existingBinary).size > 0) {
|
|
1252
|
+
BStackLogger2.debug(
|
|
1082
1253
|
`Binary already exists after acquiring lock: ${existingBinary}`
|
|
1083
1254
|
);
|
|
1084
1255
|
endDownload();
|
|
@@ -1086,11 +1257,11 @@ ${Date.now()}
|
|
|
1086
1257
|
return existingBinary;
|
|
1087
1258
|
}
|
|
1088
1259
|
cleanupTemporaryDownloads();
|
|
1089
|
-
const zipFilePath =
|
|
1260
|
+
const zipFilePath = path3.join(
|
|
1090
1261
|
cliDir,
|
|
1091
1262
|
`${CLI_DOWNLOAD_TMP_PREFIX}${process.pid}_${Date.now()}${CLI_DOWNLOAD_TMP_SUFFIX}`
|
|
1092
1263
|
);
|
|
1093
|
-
const downloadedFileStream =
|
|
1264
|
+
const downloadedFileStream = fs3.createWriteStream(zipFilePath);
|
|
1094
1265
|
return new Promise((resolve, reject) => {
|
|
1095
1266
|
const processDownload = async () => {
|
|
1096
1267
|
const abortController = new AbortController();
|
|
@@ -1100,9 +1271,11 @@ ${Date.now()}
|
|
|
1100
1271
|
);
|
|
1101
1272
|
let response;
|
|
1102
1273
|
try {
|
|
1103
|
-
response = await _fetch(
|
|
1104
|
-
|
|
1105
|
-
|
|
1274
|
+
response = await _fetch(
|
|
1275
|
+
binDownloadUrl,
|
|
1276
|
+
{ signal: abortController.signal },
|
|
1277
|
+
{ connectTimeoutMs: CLI_CONNECT_TIMEOUT_MS }
|
|
1278
|
+
);
|
|
1106
1279
|
} finally {
|
|
1107
1280
|
clearTimeout(timeout);
|
|
1108
1281
|
}
|
|
@@ -1110,7 +1283,7 @@ ${Date.now()}
|
|
|
1110
1283
|
throw new Error("No response body received");
|
|
1111
1284
|
}
|
|
1112
1285
|
downloadedFileStream.on("error", function(err) {
|
|
1113
|
-
|
|
1286
|
+
BStackLogger2.error(
|
|
1114
1287
|
`Got Error while downloading cli binary file: ${err}`
|
|
1115
1288
|
);
|
|
1116
1289
|
endDownload(false, util.format(err));
|
|
@@ -1139,7 +1312,7 @@ ${Date.now()}
|
|
|
1139
1312
|
}
|
|
1140
1313
|
);
|
|
1141
1314
|
} catch (err) {
|
|
1142
|
-
|
|
1315
|
+
BStackLogger2.error(
|
|
1143
1316
|
`Got Error in cli binary downloading request ${util.format(err)}`
|
|
1144
1317
|
);
|
|
1145
1318
|
endDownload(false, util.format(err));
|
|
@@ -1152,7 +1325,7 @@ ${Date.now()}
|
|
|
1152
1325
|
} catch (err) {
|
|
1153
1326
|
releaseLock?.();
|
|
1154
1327
|
endDownload(false, util.format(err));
|
|
1155
|
-
|
|
1328
|
+
BStackLogger2.debug(
|
|
1156
1329
|
`Failed to download binary, Exception: ${util.format(err)}`
|
|
1157
1330
|
);
|
|
1158
1331
|
return null;
|
|
@@ -1172,17 +1345,17 @@ ${Date.now()}
|
|
|
1172
1345
|
zipfile.readEntry();
|
|
1173
1346
|
return;
|
|
1174
1347
|
}
|
|
1175
|
-
const candidatePath =
|
|
1176
|
-
const resolvedCandidate =
|
|
1177
|
-
const resolvedDir =
|
|
1348
|
+
const candidatePath = path3.join(cliDir, entry.fileName);
|
|
1349
|
+
const resolvedCandidate = path3.resolve(candidatePath);
|
|
1350
|
+
const resolvedDir = path3.resolve(cliDir) + path3.sep;
|
|
1178
1351
|
if (!resolvedCandidate.startsWith(resolvedDir)) {
|
|
1179
1352
|
zipfile.close();
|
|
1180
1353
|
reject(new Error(`Zip-slip detected: entry "${entry.fileName}" resolves outside ${cliDir}`));
|
|
1181
1354
|
return;
|
|
1182
1355
|
}
|
|
1183
|
-
const isBinaryEntry =
|
|
1356
|
+
const isBinaryEntry = path3.basename(entry.fileName).startsWith("binary-");
|
|
1184
1357
|
if (!isBinaryEntry) {
|
|
1185
|
-
const directStream =
|
|
1358
|
+
const directStream = fs3.createWriteStream(candidatePath);
|
|
1186
1359
|
directStream.on("error", (writeErr) => {
|
|
1187
1360
|
zipfile.close();
|
|
1188
1361
|
reject(writeErr);
|
|
@@ -1204,8 +1377,8 @@ ${Date.now()}
|
|
|
1204
1377
|
return;
|
|
1205
1378
|
}
|
|
1206
1379
|
const finalPath = candidatePath;
|
|
1207
|
-
const tempPath =
|
|
1208
|
-
const writeStream =
|
|
1380
|
+
const tempPath = path3.join(cliDir, `${entry.fileName}.tmp.${process.pid}`);
|
|
1381
|
+
const writeStream = fs3.createWriteStream(tempPath);
|
|
1209
1382
|
let writeStreamErrored = false;
|
|
1210
1383
|
writeStream.on("error", (writeErr) => {
|
|
1211
1384
|
writeStreamErrored = true;
|
|
@@ -1226,7 +1399,7 @@ ${Date.now()}
|
|
|
1226
1399
|
if (renameErr.code !== "EXDEV") {
|
|
1227
1400
|
throw renameErr;
|
|
1228
1401
|
}
|
|
1229
|
-
|
|
1402
|
+
BStackLogger2.warn(`Atomic rename failed (cross-device), falling back to copy: ${renameErr.message}`);
|
|
1230
1403
|
await fsp.copyFile(tempPath, finalPath);
|
|
1231
1404
|
await fsp.unlink(tempPath).catch(() => {
|
|
1232
1405
|
});
|
|
@@ -1263,7 +1436,7 @@ ${Date.now()}
|
|
|
1263
1436
|
});
|
|
1264
1437
|
zipfile.once("end", () => {
|
|
1265
1438
|
fsp.unlink(zipFilePath).catch(() => {
|
|
1266
|
-
|
|
1439
|
+
BStackLogger2.warn(`Failed to delete zip file: ${zipFilePath}`);
|
|
1267
1440
|
});
|
|
1268
1441
|
if (!resolvedBinaryPath) {
|
|
1269
1442
|
zipfile.close();
|
|
@@ -1294,7 +1467,7 @@ ${Date.now()}
|
|
|
1294
1467
|
}
|
|
1295
1468
|
static setFrameworkDetail(testFramework, automationFramework) {
|
|
1296
1469
|
if (!testFramework || !automationFramework) {
|
|
1297
|
-
|
|
1470
|
+
BStackLogger2.debug(
|
|
1298
1471
|
`Test or Automation framework not provided testFramework=${testFramework}, automationFramework=${automationFramework}`
|
|
1299
1472
|
);
|
|
1300
1473
|
}
|
|
@@ -1376,12 +1549,12 @@ ${Date.now()}
|
|
|
1376
1549
|
|
|
1377
1550
|
// src/instrumentation/performance/performance-tester.ts
|
|
1378
1551
|
import { createObjectCsvWriter } from "csv-writer";
|
|
1379
|
-
import
|
|
1552
|
+
import fs4 from "node:fs";
|
|
1380
1553
|
import fsPromise from "node:fs/promises";
|
|
1381
1554
|
import { performance, PerformanceObserver } from "node:perf_hooks";
|
|
1382
1555
|
import util2 from "node:util";
|
|
1383
1556
|
import worker from "node:worker_threads";
|
|
1384
|
-
import
|
|
1557
|
+
import path4 from "node:path";
|
|
1385
1558
|
import { arch as arch2, hostname, platform as platform2, type, version } from "node:os";
|
|
1386
1559
|
var PerformanceTester;
|
|
1387
1560
|
var init_performance_tester = __esm({
|
|
@@ -1406,11 +1579,11 @@ var init_performance_tester = __esm({
|
|
|
1406
1579
|
static browser;
|
|
1407
1580
|
static scenarioThatRan;
|
|
1408
1581
|
static jsonReportDirName = "performance-report";
|
|
1409
|
-
static jsonReportDirPath =
|
|
1582
|
+
static jsonReportDirPath = path4.join(process.cwd(), "logs", this.jsonReportDirName);
|
|
1410
1583
|
static jsonReportFileName = `${this.jsonReportDirPath}/performance-report-${_PerformanceTester.getProcessId()}.json`;
|
|
1411
1584
|
static startMonitoring(csvName = "performance-report.csv") {
|
|
1412
|
-
if (!
|
|
1413
|
-
|
|
1585
|
+
if (!fs4.existsSync(this.jsonReportDirPath)) {
|
|
1586
|
+
fs4.mkdirSync(this.jsonReportDirPath, { recursive: true });
|
|
1414
1587
|
}
|
|
1415
1588
|
this._observer = new PerformanceObserver((list) => {
|
|
1416
1589
|
list.getEntries().filter((entry) => entry.entryType === "measure").forEach(
|
|
@@ -1420,10 +1593,10 @@ var init_performance_tester = __esm({
|
|
|
1420
1593
|
if (typeof finalEntry.startTime === "number" && typeof performance.timeOrigin === "number") {
|
|
1421
1594
|
const originalStartTime = finalEntry.startTime;
|
|
1422
1595
|
finalEntry.startTime = performance.timeOrigin + finalEntry.startTime;
|
|
1423
|
-
|
|
1596
|
+
BStackLogger.debug(`Timestamp conversion for ${entry.name}: ${originalStartTime} -> ${finalEntry.startTime} (timeOrigin: ${performance.timeOrigin})`);
|
|
1424
1597
|
}
|
|
1425
1598
|
} catch (e) {
|
|
1426
|
-
|
|
1599
|
+
BStackLogger.debug(`Error converting startTime to epoch: ${util2.format(e)}`);
|
|
1427
1600
|
}
|
|
1428
1601
|
if (this.details[entry.name]) {
|
|
1429
1602
|
finalEntry = Object.assign(finalEntry, this.details[entry.name]);
|
|
@@ -1463,7 +1636,7 @@ var init_performance_tester = __esm({
|
|
|
1463
1636
|
const timeTaken = methods.reduce((a, c) => {
|
|
1464
1637
|
return times[c] + (a || 0);
|
|
1465
1638
|
}, 0);
|
|
1466
|
-
|
|
1639
|
+
BStackLogger.debug(`Time for ${methods} is ${timeTaken}`);
|
|
1467
1640
|
return timeTaken;
|
|
1468
1641
|
}
|
|
1469
1642
|
static async stopAndGenerate(filename = "performance-own.html") {
|
|
@@ -1475,7 +1648,7 @@ var init_performance_tester = __esm({
|
|
|
1475
1648
|
const finalJSONStr = eventsJson.slice(1, -1) + ",";
|
|
1476
1649
|
await fsPromise.appendFile(this.jsonReportFileName, finalJSONStr);
|
|
1477
1650
|
} catch (er) {
|
|
1478
|
-
|
|
1651
|
+
BStackLogger.debug(`Failed to write events of the worker to ${this.jsonReportFileName}: ${util2.format(er)}`);
|
|
1479
1652
|
}
|
|
1480
1653
|
this._observer.disconnect();
|
|
1481
1654
|
if (!process.env[PERF_MEASUREMENT_ENV]) {
|
|
@@ -1484,12 +1657,12 @@ var init_performance_tester = __esm({
|
|
|
1484
1657
|
this.started = false;
|
|
1485
1658
|
this.generateCSV(this._events);
|
|
1486
1659
|
const content = this.generateReport(this._events);
|
|
1487
|
-
const dir =
|
|
1660
|
+
const dir = path4.join(process.cwd(), filename);
|
|
1488
1661
|
try {
|
|
1489
1662
|
await fsPromise.writeFile(dir, content);
|
|
1490
|
-
|
|
1663
|
+
BStackLogger.info(`Performance report is at ${path4}`);
|
|
1491
1664
|
} catch (err) {
|
|
1492
|
-
|
|
1665
|
+
BStackLogger.error(`Error in writing html ${util2.format(err)}`);
|
|
1493
1666
|
}
|
|
1494
1667
|
}
|
|
1495
1668
|
static generateReport(entries) {
|
|
@@ -1520,7 +1693,7 @@ var init_performance_tester = __esm({
|
|
|
1520
1693
|
time: value
|
|
1521
1694
|
};
|
|
1522
1695
|
});
|
|
1523
|
-
this._csvWriter.writeRecords(dat).then(() =>
|
|
1696
|
+
this._csvWriter.writeRecords(dat).then(() => BStackLogger.info("Performance CSV report generated successfully")).catch((error) => console.error(error));
|
|
1524
1697
|
}
|
|
1525
1698
|
static Measure(label, details = {}) {
|
|
1526
1699
|
const self = this;
|
|
@@ -1654,16 +1827,16 @@ var init_performance_tester = __esm({
|
|
|
1654
1827
|
this.start(EVENTS.SDK_SEND_KEY_METRICS);
|
|
1655
1828
|
try {
|
|
1656
1829
|
const workerId = `${process.pid}`;
|
|
1657
|
-
|
|
1830
|
+
BStackLogger.debug(`[Performance Upload] Starting upload for worker ${workerId}`);
|
|
1658
1831
|
this.start(EVENTS.SDK_KEY_METRICS_PREPARATION);
|
|
1659
1832
|
let measures = [];
|
|
1660
1833
|
if (await fsPromise.access(this.jsonReportDirPath).then(() => true).catch(() => false)) {
|
|
1661
|
-
const files = (await fsPromise.readdir(this.jsonReportDirPath)).map((file) =>
|
|
1834
|
+
const files = (await fsPromise.readdir(this.jsonReportDirPath)).map((file) => path4.resolve(this.jsonReportDirPath, file));
|
|
1662
1835
|
measures = (await Promise.all(files.map((file) => fsPromise.readFile(file, "utf-8")))).map((el) => `[${el.slice(0, -1)}]`).map((el) => JSON.parse(el)).flat();
|
|
1663
1836
|
}
|
|
1664
|
-
|
|
1837
|
+
BStackLogger.debug(`[Performance Upload] Total events from files: ${measures.length}`);
|
|
1665
1838
|
if (this._measuredEvents.length > 0) {
|
|
1666
|
-
|
|
1839
|
+
BStackLogger.debug(`[Performance Upload] Adding ${this._measuredEvents.length} in-memory events`);
|
|
1667
1840
|
measures = measures.concat(
|
|
1668
1841
|
this._measuredEvents.map((e) => {
|
|
1669
1842
|
if (typeof e.toJSON === "function") {
|
|
@@ -1724,10 +1897,10 @@ var init_performance_tester = __esm({
|
|
|
1724
1897
|
},
|
|
1725
1898
|
body: JSON.stringify(payload)
|
|
1726
1899
|
});
|
|
1727
|
-
|
|
1900
|
+
BStackLogger.debug(`[Performance Upload] Successfully uploaded to EDS: ${util2.format(await result.text())}`);
|
|
1728
1901
|
this.end(EVENTS.SDK_SEND_KEY_METRICS, true);
|
|
1729
1902
|
} catch (er) {
|
|
1730
|
-
|
|
1903
|
+
BStackLogger.debug(`[Performance Upload] Failed to upload events: ${util2.format(er)}`);
|
|
1731
1904
|
this.end(EVENTS.SDK_KEY_METRICS_PREPARATION, false, er);
|
|
1732
1905
|
this.end(EVENTS.SDK_SEND_KEY_METRICS, false, er);
|
|
1733
1906
|
}
|
|
@@ -1735,12 +1908,12 @@ var init_performance_tester = __esm({
|
|
|
1735
1908
|
if (await fsPromise.access(this.jsonReportDirPath).then(() => true, () => false)) {
|
|
1736
1909
|
const files = await fsPromise.readdir(this.jsonReportDirPath);
|
|
1737
1910
|
for (const file of files) {
|
|
1738
|
-
await fsPromise.unlink(
|
|
1911
|
+
await fsPromise.unlink(path4.join(this.jsonReportDirPath, file));
|
|
1739
1912
|
}
|
|
1740
|
-
|
|
1913
|
+
BStackLogger.debug(`[Performance Upload] Cleaned up ${files.length} temporary report files`);
|
|
1741
1914
|
}
|
|
1742
1915
|
} catch (er) {
|
|
1743
|
-
|
|
1916
|
+
BStackLogger.debug(`[Performance Upload] Failed to delete temporary files: ${util2.format(er)}`);
|
|
1744
1917
|
}
|
|
1745
1918
|
}
|
|
1746
1919
|
};
|
|
@@ -1748,7 +1921,7 @@ var init_performance_tester = __esm({
|
|
|
1748
1921
|
});
|
|
1749
1922
|
|
|
1750
1923
|
// src/testorchestration/testorcherstrationutils.ts
|
|
1751
|
-
import
|
|
1924
|
+
import fs5 from "node:fs";
|
|
1752
1925
|
var RUN_SMART_SELECTION, ALLOWED_ORCHESTRATION_KEYS, isPlainObject, asString, TestOrdering, OrchestrationUtils;
|
|
1753
1926
|
var init_testorcherstrationutils = __esm({
|
|
1754
1927
|
"src/testorchestration/testorcherstrationutils.ts"() {
|
|
@@ -1816,7 +1989,7 @@ var init_testorcherstrationutils = __esm({
|
|
|
1816
1989
|
for (const service of services) {
|
|
1817
1990
|
if (Array.isArray(service) && service[0] === "browserstack" && isPlainObject(service[1]) && isPlainObject(service[1].testOrchestrationOptions)) {
|
|
1818
1991
|
testOrchOptions = service[1].testOrchestrationOptions;
|
|
1819
|
-
|
|
1992
|
+
BStackLogger.debug("[constructor] Found testOrchestrationOptions in browserstack service config");
|
|
1820
1993
|
break;
|
|
1821
1994
|
}
|
|
1822
1995
|
}
|
|
@@ -1845,9 +2018,9 @@ var init_testorcherstrationutils = __esm({
|
|
|
1845
2018
|
}
|
|
1846
2019
|
});
|
|
1847
2020
|
}
|
|
1848
|
-
|
|
2021
|
+
BStackLogger.debug(`[_extractBuildDetails] Extracted - projectName: ${this.projectName}, buildName: ${this.buildName}, buildIdentifier: ${this.buildIdentifier}`);
|
|
1849
2022
|
} catch (error) {
|
|
1850
|
-
|
|
2023
|
+
BStackLogger.error(`[_extractBuildDetails] ${error}`);
|
|
1851
2024
|
}
|
|
1852
2025
|
}
|
|
1853
2026
|
_parseCapability(capability) {
|
|
@@ -1945,7 +2118,7 @@ var init_testorcherstrationutils = __esm({
|
|
|
1945
2118
|
this.projectName = projectName;
|
|
1946
2119
|
this.buildName = buildName;
|
|
1947
2120
|
this.buildIdentifier = buildIdentifier;
|
|
1948
|
-
|
|
2121
|
+
BStackLogger.debug(`[setBuildDetails] Set - projectName: ${this.projectName}, buildName: ${this.buildName}, buildIdentifier: ${this.buildIdentifier}`);
|
|
1949
2122
|
}
|
|
1950
2123
|
/**
|
|
1951
2124
|
* Set run smart selection
|
|
@@ -1955,27 +2128,27 @@ var init_testorcherstrationutils = __esm({
|
|
|
1955
2128
|
this.runSmartSelection = isValidEnabledValue(enabled);
|
|
1956
2129
|
this.smartSelectionMode = mode;
|
|
1957
2130
|
this.smartSelectionSource = [];
|
|
1958
|
-
|
|
2131
|
+
BStackLogger.debug(`Setting runSmartSelection: enabled=${this.runSmartSelection}, mode=${this.smartSelectionMode}`);
|
|
1959
2132
|
if (this.runSmartSelection) {
|
|
1960
2133
|
const validModes = [SMART_SELECTION_MODE_RELEVANT_FIRST, SMART_SELECTION_MODE_RELEVANT_ONLY];
|
|
1961
2134
|
if (!validModes.includes(this.smartSelectionMode)) {
|
|
1962
|
-
|
|
2135
|
+
BStackLogger.warn(`Invalid smart selection mode '${this.smartSelectionMode}' provided. Defaulting to '${SMART_SELECTION_MODE_RELEVANT_FIRST}'.`);
|
|
1963
2136
|
this.smartSelectionMode = SMART_SELECTION_MODE_RELEVANT_FIRST;
|
|
1964
2137
|
}
|
|
1965
2138
|
if (source === null) {
|
|
1966
2139
|
this.smartSelectionSource = null;
|
|
1967
|
-
|
|
2140
|
+
BStackLogger.debug("No source provided for smart selection; defaulting to null.");
|
|
1968
2141
|
} else if (Array.isArray(source)) {
|
|
1969
2142
|
this.smartSelectionSource = source;
|
|
1970
|
-
|
|
2143
|
+
BStackLogger.debug(`Smart selection source set to array: ${JSON.stringify(source)}`);
|
|
1971
2144
|
} else if (typeof source === "string" && source.endsWith(".json")) {
|
|
1972
2145
|
this.smartSelectionSource = this._loadSourceFromFile(source) || [];
|
|
1973
|
-
|
|
2146
|
+
BStackLogger.debug(`Smart selection source loaded from file: ${source}`);
|
|
1974
2147
|
}
|
|
1975
2148
|
this._setTestOrdering();
|
|
1976
2149
|
}
|
|
1977
2150
|
} catch (e) {
|
|
1978
|
-
|
|
2151
|
+
BStackLogger.error(`[_setRunSmartSelection] ${e}`);
|
|
1979
2152
|
}
|
|
1980
2153
|
}
|
|
1981
2154
|
/**
|
|
@@ -1985,17 +2158,17 @@ var init_testorcherstrationutils = __esm({
|
|
|
1985
2158
|
* @returns Formatted list of repository configurations
|
|
1986
2159
|
*/
|
|
1987
2160
|
_loadSourceFromFile(filePath) {
|
|
1988
|
-
if (!
|
|
1989
|
-
|
|
2161
|
+
if (!fs5.existsSync(filePath)) {
|
|
2162
|
+
BStackLogger.error(`Source file '${filePath}' does not exist.`);
|
|
1990
2163
|
return [];
|
|
1991
2164
|
}
|
|
1992
2165
|
let data = null;
|
|
1993
2166
|
try {
|
|
1994
|
-
const fileContent =
|
|
2167
|
+
const fileContent = fs5.readFileSync(filePath, "utf8");
|
|
1995
2168
|
data = JSON.parse(fileContent);
|
|
1996
2169
|
} catch (error) {
|
|
1997
2170
|
const message = error instanceof Error ? error.message : String(error);
|
|
1998
|
-
|
|
2171
|
+
BStackLogger.error(`Error parsing JSON from source file '${filePath}': ${message}`);
|
|
1999
2172
|
return [];
|
|
2000
2173
|
}
|
|
2001
2174
|
let featureBranchEnvMap = null;
|
|
@@ -2011,9 +2184,9 @@ var init_testorcherstrationutils = __esm({
|
|
|
2011
2184
|
return acc;
|
|
2012
2185
|
}, {});
|
|
2013
2186
|
} catch (error) {
|
|
2014
|
-
|
|
2187
|
+
BStackLogger.error(`Error parsing feature branch mappings: ${error}`);
|
|
2015
2188
|
}
|
|
2016
|
-
|
|
2189
|
+
BStackLogger.debug(`Feature branch mappings from env: ${JSON.stringify(envMap)}`);
|
|
2017
2190
|
return envMap;
|
|
2018
2191
|
};
|
|
2019
2192
|
featureBranchEnvMap = loadFeatureBranchMaps();
|
|
@@ -2035,23 +2208,23 @@ var init_testorcherstrationutils = __esm({
|
|
|
2035
2208
|
}
|
|
2036
2209
|
const typedRepoInfo = repoInfo;
|
|
2037
2210
|
if (!typedRepoInfo.url || typeof typedRepoInfo.url !== "string") {
|
|
2038
|
-
|
|
2211
|
+
BStackLogger.warn(`Repository URL is missing or invalid for source '${name}': ${JSON.stringify(repoInfo)}`);
|
|
2039
2212
|
continue;
|
|
2040
2213
|
}
|
|
2041
2214
|
if (typedRepoInfo.baseBranch !== void 0 && typeof typedRepoInfo.baseBranch !== "string") {
|
|
2042
|
-
|
|
2215
|
+
BStackLogger.warn(`Base branch must be a string for source '${name}': ${JSON.stringify(repoInfo)}`);
|
|
2043
2216
|
continue;
|
|
2044
2217
|
}
|
|
2045
2218
|
if (typedRepoInfo.featureBranch !== void 0 && typeof typedRepoInfo.featureBranch !== "string") {
|
|
2046
|
-
|
|
2219
|
+
BStackLogger.warn(`Feature branch must be a string for source '${name}': ${JSON.stringify(repoInfo)}`);
|
|
2047
2220
|
continue;
|
|
2048
2221
|
}
|
|
2049
2222
|
if (!namePattern.test(name)) {
|
|
2050
|
-
|
|
2223
|
+
BStackLogger.warn(`Invalid source identifier format for '${name}': ${JSON.stringify(repoInfo)}`);
|
|
2051
2224
|
continue;
|
|
2052
2225
|
}
|
|
2053
2226
|
if (name.length > 30 || name.length < 1) {
|
|
2054
|
-
|
|
2227
|
+
BStackLogger.warn(`Source identifier '${name}' must have a length between 1 and 30 characters.`);
|
|
2055
2228
|
continue;
|
|
2056
2229
|
}
|
|
2057
2230
|
const featureBranch = getFeatureBranch(name, typedRepoInfo);
|
|
@@ -2064,11 +2237,11 @@ var init_testorcherstrationutils = __esm({
|
|
|
2064
2237
|
filteredRepoInfo.baseBranch = typedRepoInfo.baseBranch;
|
|
2065
2238
|
}
|
|
2066
2239
|
if (!filteredRepoInfo.featureBranch || filteredRepoInfo.featureBranch === "") {
|
|
2067
|
-
|
|
2240
|
+
BStackLogger.warn(`Feature branch not specified for source '${name}': ${JSON.stringify(repoInfo)}`);
|
|
2068
2241
|
continue;
|
|
2069
2242
|
}
|
|
2070
2243
|
if (filteredRepoInfo.baseBranch && filteredRepoInfo.baseBranch === filteredRepoInfo.featureBranch) {
|
|
2071
|
-
|
|
2244
|
+
BStackLogger.warn(`Feature branch and base branch cannot be the same for source '${name}': ${JSON.stringify(repoInfo)}`);
|
|
2072
2245
|
continue;
|
|
2073
2246
|
}
|
|
2074
2247
|
formattedData.push(filteredRepoInfo);
|
|
@@ -2178,17 +2351,17 @@ var init_crash_reporter = __esm({
|
|
|
2178
2351
|
this.credentialsForCrashReportUpload = process.env.CREDENTIALS_FOR_CRASH_REPORTING !== void 0 ? JSON.parse(process.env.CREDENTIALS_FOR_CRASH_REPORTING) : this.credentialsForCrashReportUpload;
|
|
2179
2352
|
}
|
|
2180
2353
|
} catch (error) {
|
|
2181
|
-
return
|
|
2354
|
+
return BStackLogger.error(`[Crash_Report_Upload] Failed to parse user credentials while reporting crash due to ${error}`);
|
|
2182
2355
|
}
|
|
2183
2356
|
if (!this.credentialsForCrashReportUpload.username || !this.credentialsForCrashReportUpload.password) {
|
|
2184
|
-
return
|
|
2357
|
+
return BStackLogger.error("[Crash_Report_Upload] Failed to parse user credentials while reporting crash");
|
|
2185
2358
|
}
|
|
2186
2359
|
try {
|
|
2187
2360
|
if (Object.keys(this.userConfigForReporting).length === 0) {
|
|
2188
2361
|
this.userConfigForReporting = process.env.USER_CONFIG_FOR_REPORTING !== void 0 ? JSON.parse(process.env.USER_CONFIG_FOR_REPORTING) : {};
|
|
2189
2362
|
}
|
|
2190
2363
|
} catch (error) {
|
|
2191
|
-
|
|
2364
|
+
BStackLogger.error(`[Crash_Report_Upload] Failed to parse user config while reporting crash due to ${error}`);
|
|
2192
2365
|
this.userConfigForReporting = {};
|
|
2193
2366
|
}
|
|
2194
2367
|
const data = {
|
|
@@ -2220,9 +2393,9 @@ var init_crash_reporter = __esm({
|
|
|
2220
2393
|
body = JSON.stringify(JSON.parse(body));
|
|
2221
2394
|
} catch {
|
|
2222
2395
|
}
|
|
2223
|
-
|
|
2396
|
+
BStackLogger.debug(`[Crash_Report_Upload] Success response: ${body}`);
|
|
2224
2397
|
} else {
|
|
2225
|
-
|
|
2398
|
+
BStackLogger.error(`[Crash_Report_Upload] Failed due to ${response.body}`);
|
|
2226
2399
|
}
|
|
2227
2400
|
}
|
|
2228
2401
|
static recursivelyRedactKeysFromObject(obj, keys) {
|
|
@@ -2282,7 +2455,7 @@ var init_crash_reporter = __esm({
|
|
|
2282
2455
|
}
|
|
2283
2456
|
}
|
|
2284
2457
|
} catch (err) {
|
|
2285
|
-
|
|
2458
|
+
BStackLogger.error(`Error in parsing user config PII with error ${err ? err.stack || err : err}`);
|
|
2286
2459
|
return configWithoutPII;
|
|
2287
2460
|
}
|
|
2288
2461
|
configWithoutPII.services = finalServices;
|
|
@@ -2317,7 +2490,7 @@ var init_featureStats = __esm({
|
|
|
2317
2490
|
this.failed(groupId);
|
|
2318
2491
|
break;
|
|
2319
2492
|
default:
|
|
2320
|
-
|
|
2493
|
+
BStackLogger.debug("Request to mark usage for unknown status - " + status);
|
|
2321
2494
|
break;
|
|
2322
2495
|
}
|
|
2323
2496
|
}
|
|
@@ -2482,6 +2655,8 @@ var init_testOpsConfig = __esm({
|
|
|
2482
2655
|
this.manuallySet = manuallySet;
|
|
2483
2656
|
_TestOpsConfig._instance = this;
|
|
2484
2657
|
}
|
|
2658
|
+
enabled;
|
|
2659
|
+
manuallySet;
|
|
2485
2660
|
static _instance;
|
|
2486
2661
|
buildStopped = false;
|
|
2487
2662
|
buildHashedId;
|
|
@@ -2553,7 +2728,7 @@ var init_usageStats = __esm({
|
|
|
2553
2728
|
try {
|
|
2554
2729
|
usage.events = this.getEventsData();
|
|
2555
2730
|
} catch (e) {
|
|
2556
|
-
|
|
2731
|
+
BStackLogger.debug("exception in getFormattedData: " + e);
|
|
2557
2732
|
}
|
|
2558
2733
|
return usage;
|
|
2559
2734
|
}
|
|
@@ -2563,7 +2738,7 @@ var init_usageStats = __esm({
|
|
|
2563
2738
|
const usageStatsForWorker = _UsageStats.fromJSON(workerData.usageStats);
|
|
2564
2739
|
this.add(usageStatsForWorker);
|
|
2565
2740
|
} catch (e) {
|
|
2566
|
-
|
|
2741
|
+
BStackLogger.debug("Exception in adding workerData: " + e);
|
|
2567
2742
|
}
|
|
2568
2743
|
});
|
|
2569
2744
|
}
|
|
@@ -2617,9 +2792,9 @@ var init_usageStats = __esm({
|
|
|
2617
2792
|
});
|
|
2618
2793
|
|
|
2619
2794
|
// src/scripts/accessibility-scripts.ts
|
|
2620
|
-
import
|
|
2621
|
-
import
|
|
2622
|
-
import
|
|
2795
|
+
import path5 from "node:path";
|
|
2796
|
+
import fs6 from "node:fs";
|
|
2797
|
+
import os2 from "node:os";
|
|
2623
2798
|
var AccessibilityScripts, accessibility_scripts_default;
|
|
2624
2799
|
var init_accessibility_scripts = __esm({
|
|
2625
2800
|
"src/scripts/accessibility-scripts.ts"() {
|
|
@@ -2637,7 +2812,7 @@ var init_accessibility_scripts = __esm({
|
|
|
2637
2812
|
// don't allow to create instances from it other than through `checkAndGetInstance`
|
|
2638
2813
|
constructor() {
|
|
2639
2814
|
this.browserstackFolderPath = this.getWritableDir();
|
|
2640
|
-
this.commandsPath =
|
|
2815
|
+
this.commandsPath = path5.join(this.browserstackFolderPath, "commands.json");
|
|
2641
2816
|
}
|
|
2642
2817
|
static checkAndGetInstance() {
|
|
2643
2818
|
if (!_AccessibilityScripts.instance) {
|
|
@@ -2649,17 +2824,17 @@ var init_accessibility_scripts = __esm({
|
|
|
2649
2824
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2650
2825
|
getWritableDir() {
|
|
2651
2826
|
const orderedPaths = [
|
|
2652
|
-
|
|
2827
|
+
path5.join(os2.homedir(), ".browserstack"),
|
|
2653
2828
|
process.cwd(),
|
|
2654
|
-
|
|
2829
|
+
os2.tmpdir()
|
|
2655
2830
|
];
|
|
2656
2831
|
for (const orderedPath of orderedPaths) {
|
|
2657
2832
|
try {
|
|
2658
|
-
if (
|
|
2659
|
-
|
|
2833
|
+
if (fs6.existsSync(orderedPath)) {
|
|
2834
|
+
fs6.accessSync(orderedPath);
|
|
2660
2835
|
return orderedPath;
|
|
2661
2836
|
}
|
|
2662
|
-
|
|
2837
|
+
fs6.mkdirSync(orderedPath, { recursive: true });
|
|
2663
2838
|
return orderedPath;
|
|
2664
2839
|
} catch (error) {
|
|
2665
2840
|
}
|
|
@@ -2668,8 +2843,8 @@ var init_accessibility_scripts = __esm({
|
|
|
2668
2843
|
}
|
|
2669
2844
|
readFromExistingFile() {
|
|
2670
2845
|
try {
|
|
2671
|
-
if (
|
|
2672
|
-
const data =
|
|
2846
|
+
if (fs6.existsSync(this.commandsPath)) {
|
|
2847
|
+
const data = fs6.readFileSync(this.commandsPath, "utf8");
|
|
2673
2848
|
if (data) {
|
|
2674
2849
|
this.update(JSON.parse(data));
|
|
2675
2850
|
}
|
|
@@ -2692,10 +2867,10 @@ var init_accessibility_scripts = __esm({
|
|
|
2692
2867
|
}
|
|
2693
2868
|
}
|
|
2694
2869
|
store() {
|
|
2695
|
-
if (!
|
|
2696
|
-
|
|
2870
|
+
if (!fs6.existsSync(this.browserstackFolderPath)) {
|
|
2871
|
+
fs6.mkdirSync(this.browserstackFolderPath);
|
|
2697
2872
|
}
|
|
2698
|
-
|
|
2873
|
+
fs6.writeFileSync(this.commandsPath, JSON.stringify({
|
|
2699
2874
|
commands: this.commandsToWrap,
|
|
2700
2875
|
scripts: {
|
|
2701
2876
|
scan: this.performScan,
|
|
@@ -2714,10 +2889,10 @@ var init_accessibility_scripts = __esm({
|
|
|
2714
2889
|
// src/util.ts
|
|
2715
2890
|
import { hostname as hostname2, platform as platform3, type as type2, version as version2, arch as arch3, tmpdir } from "node:os";
|
|
2716
2891
|
import crypto from "node:crypto";
|
|
2717
|
-
import
|
|
2892
|
+
import fs7 from "node:fs";
|
|
2718
2893
|
import zlib from "node:zlib";
|
|
2719
2894
|
import { format, promisify as promisify2 } from "node:util";
|
|
2720
|
-
import
|
|
2895
|
+
import path6 from "node:path";
|
|
2721
2896
|
import util3 from "node:util";
|
|
2722
2897
|
import gitRepoInfo from "git-repo-info";
|
|
2723
2898
|
import gitconfig from "gitconfiglocal";
|
|
@@ -2758,7 +2933,7 @@ function getParentSuiteName(fullTitle, testSuiteTitle) {
|
|
|
2758
2933
|
return parentSuiteName.trim();
|
|
2759
2934
|
}
|
|
2760
2935
|
function processError(error, fn, args) {
|
|
2761
|
-
|
|
2936
|
+
BStackLogger.error(`Error in executing ${fn.name} with args ${args}: ${error}`);
|
|
2762
2937
|
let argsString;
|
|
2763
2938
|
try {
|
|
2764
2939
|
argsString = JSON.stringify(args);
|
|
@@ -2796,7 +2971,7 @@ async function nodeRequest(requestType, apiEndpoint, options, apiUrl, timeout =
|
|
|
2796
2971
|
clearTimeout(timeoutId);
|
|
2797
2972
|
return await response.json();
|
|
2798
2973
|
} catch (error) {
|
|
2799
|
-
|
|
2974
|
+
BStackLogger.debug(`Error in firing request ${apiUrl}/${apiEndpoint}: ${format(error)}`);
|
|
2800
2975
|
const isLogUpload = apiEndpoint === UPLOAD_LOGS_ENDPOINT;
|
|
2801
2976
|
if (error && error.response) {
|
|
2802
2977
|
const errorMessageJson = error.response.body ? JSON.parse(error.response.body.toString()) : null;
|
|
@@ -2804,9 +2979,9 @@ async function nodeRequest(requestType, apiEndpoint, options, apiUrl, timeout =
|
|
|
2804
2979
|
if (errorMessage) {
|
|
2805
2980
|
const message = `${errorMessage} - ${error.stack}`;
|
|
2806
2981
|
if (isLogUpload) {
|
|
2807
|
-
|
|
2982
|
+
BStackLogger.debug(message);
|
|
2808
2983
|
} else {
|
|
2809
|
-
|
|
2984
|
+
BStackLogger.error(message);
|
|
2810
2985
|
}
|
|
2811
2986
|
}
|
|
2812
2987
|
if (isLogUpload) {
|
|
@@ -2815,10 +2990,10 @@ async function nodeRequest(requestType, apiEndpoint, options, apiUrl, timeout =
|
|
|
2815
2990
|
throw error;
|
|
2816
2991
|
} else {
|
|
2817
2992
|
if (isLogUpload) {
|
|
2818
|
-
|
|
2993
|
+
BStackLogger.debug(`Failed to fire api request due to ${error} - ${error.stack}`);
|
|
2819
2994
|
return;
|
|
2820
2995
|
}
|
|
2821
|
-
|
|
2996
|
+
BStackLogger.debug(`Failed to fire api request due to ${error} - ${error.stack}`);
|
|
2822
2997
|
throw error;
|
|
2823
2998
|
}
|
|
2824
2999
|
}
|
|
@@ -3238,9 +3413,9 @@ async function batchAndPostEvents(eventUrl, kind, data) {
|
|
|
3238
3413
|
},
|
|
3239
3414
|
body: JSON.stringify(data)
|
|
3240
3415
|
});
|
|
3241
|
-
|
|
3416
|
+
BStackLogger.debug(`[${kind}] Success response: ${JSON.stringify(await response.json())}`);
|
|
3242
3417
|
} catch (error) {
|
|
3243
|
-
|
|
3418
|
+
BStackLogger.debug(`[${kind}] EXCEPTION IN ${kind} REQUEST TO TEST REPORTING AND ANALYTICS : ${error}`);
|
|
3244
3419
|
throw new Error("Exception in request " + error);
|
|
3245
3420
|
}
|
|
3246
3421
|
}
|
|
@@ -3278,7 +3453,7 @@ function getObservabilityBuild(options, bstackBuildName) {
|
|
|
3278
3453
|
if (options.testObservabilityOptions && options.testObservabilityOptions.buildName) {
|
|
3279
3454
|
return options.testObservabilityOptions.buildName;
|
|
3280
3455
|
}
|
|
3281
|
-
return bstackBuildName ||
|
|
3456
|
+
return bstackBuildName || path6.basename(path6.resolve(process.cwd()));
|
|
3282
3457
|
}
|
|
3283
3458
|
function getObservabilityBuildTags(options, bstackBuildTag) {
|
|
3284
3459
|
if (process.env.TEST_OBSERVABILITY_BUILD_TAG) {
|
|
@@ -3364,26 +3539,26 @@ async function uploadLogs(user, key, clientBuildUuid) {
|
|
|
3364
3539
|
if (!user || !key) {
|
|
3365
3540
|
success = false;
|
|
3366
3541
|
failure = "skipped: missing_credentials";
|
|
3367
|
-
|
|
3542
|
+
BStackLogger.debug("Uploading logs failed due to no credentials");
|
|
3368
3543
|
return;
|
|
3369
3544
|
}
|
|
3370
3545
|
const tmpDir = tmpdir();
|
|
3371
|
-
const tarPath =
|
|
3372
|
-
const tarGzPath =
|
|
3546
|
+
const tarPath = path6.join(tmpDir, "logs.tar");
|
|
3547
|
+
const tarGzPath = path6.join(tmpDir, "logs.tar.gz");
|
|
3373
3548
|
const filesToArchive = [
|
|
3374
|
-
|
|
3549
|
+
BStackLogger.logFilePath,
|
|
3375
3550
|
CLI_DEBUG_LOGS_FILE
|
|
3376
|
-
].filter((f) =>
|
|
3551
|
+
].filter((f) => fs7.existsSync(f));
|
|
3377
3552
|
const copiedFileNames = [];
|
|
3378
3553
|
const archiveAddFailures = [];
|
|
3379
3554
|
for (const f of filesToArchive) {
|
|
3380
3555
|
try {
|
|
3381
|
-
const dest =
|
|
3382
|
-
|
|
3383
|
-
copiedFileNames.push(
|
|
3556
|
+
const dest = path6.join(tmpDir, path6.basename(f));
|
|
3557
|
+
fs7.copyFileSync(f, dest);
|
|
3558
|
+
copiedFileNames.push(path6.basename(f));
|
|
3384
3559
|
} catch (copyErr) {
|
|
3385
3560
|
const msg = copyErr?.message || String(copyErr);
|
|
3386
|
-
archiveAddFailures.push(`${
|
|
3561
|
+
archiveAddFailures.push(`${path6.basename(f)}: ${msg}`);
|
|
3387
3562
|
}
|
|
3388
3563
|
}
|
|
3389
3564
|
if (archiveAddFailures.length > 0 && failure === void 0) {
|
|
@@ -3400,15 +3575,15 @@ async function uploadLogs(user, key, clientBuildUuid) {
|
|
|
3400
3575
|
copiedFileNames
|
|
3401
3576
|
);
|
|
3402
3577
|
await new Promise((resolve, reject) => {
|
|
3403
|
-
const source =
|
|
3404
|
-
const dest =
|
|
3578
|
+
const source = fs7.createReadStream(tarPath);
|
|
3579
|
+
const dest = fs7.createWriteStream(tarGzPath);
|
|
3405
3580
|
const gzip = zlib.createGzip({ level: 1 });
|
|
3406
3581
|
source.pipe(gzip).pipe(dest);
|
|
3407
3582
|
dest.on("finish", resolve);
|
|
3408
3583
|
dest.on("error", reject);
|
|
3409
3584
|
});
|
|
3410
3585
|
const formData = new FormData();
|
|
3411
|
-
const file = await
|
|
3586
|
+
const file = await fs7.openAsBlob(tarGzPath, { type: "application/x-gzip" });
|
|
3412
3587
|
formData.append("data", file, "logs.tar.gz");
|
|
3413
3588
|
formData.append("clientBuildUuid", clientBuildUuid);
|
|
3414
3589
|
const auth = Buffer.from(`${user}:${key}`).toString("base64");
|
|
@@ -3424,16 +3599,16 @@ async function uploadLogs(user, key, clientBuildUuid) {
|
|
|
3424
3599
|
requestOptions,
|
|
3425
3600
|
APIUtils.UPLOAD_LOGS_ADDRESS
|
|
3426
3601
|
);
|
|
3427
|
-
|
|
3428
|
-
|
|
3602
|
+
fs7.unlinkSync(tarPath);
|
|
3603
|
+
fs7.unlinkSync(tarGzPath);
|
|
3429
3604
|
for (const f of copiedFileNames) {
|
|
3430
|
-
const filePath =
|
|
3431
|
-
if (
|
|
3432
|
-
|
|
3605
|
+
const filePath = path6.join(tmpDir, f);
|
|
3606
|
+
if (fs7.existsSync(filePath)) {
|
|
3607
|
+
fs7.unlinkSync(filePath);
|
|
3433
3608
|
}
|
|
3434
3609
|
}
|
|
3435
|
-
if (
|
|
3436
|
-
|
|
3610
|
+
if (fs7.existsSync(CLI_DEBUG_LOGS_FILE)) {
|
|
3611
|
+
fs7.unlinkSync(CLI_DEBUG_LOGS_FILE);
|
|
3437
3612
|
}
|
|
3438
3613
|
if (!response) {
|
|
3439
3614
|
success = false;
|
|
@@ -3446,7 +3621,7 @@ async function uploadLogs(user, key, clientBuildUuid) {
|
|
|
3446
3621
|
} catch (error) {
|
|
3447
3622
|
success = false;
|
|
3448
3623
|
failure = `uploadLogs exception: ${getErrorString(error)}`;
|
|
3449
|
-
|
|
3624
|
+
BStackLogger.error(`Error while uploading logs: ${getErrorString(error)}`);
|
|
3450
3625
|
return null;
|
|
3451
3626
|
} finally {
|
|
3452
3627
|
PerformanceTester.end(eventName, success, failure);
|
|
@@ -3463,7 +3638,7 @@ function truncateString(field, truncateSizeInBytes) {
|
|
|
3463
3638
|
return truncatedString;
|
|
3464
3639
|
}
|
|
3465
3640
|
} catch (error) {
|
|
3466
|
-
|
|
3641
|
+
BStackLogger.debug(`Error while truncating field, nothing was truncated here: ${error}`);
|
|
3467
3642
|
}
|
|
3468
3643
|
return field;
|
|
3469
3644
|
}
|
|
@@ -3472,7 +3647,7 @@ function getSizeOfJsonObjectInBytes(jsonData) {
|
|
|
3472
3647
|
const buffer = Buffer.from(JSON.stringify(jsonData));
|
|
3473
3648
|
return buffer.length;
|
|
3474
3649
|
} catch (error) {
|
|
3475
|
-
|
|
3650
|
+
BStackLogger.debug(`Something went wrong while calculating size of JSON object: ${error}`);
|
|
3476
3651
|
}
|
|
3477
3652
|
return -1;
|
|
3478
3653
|
}
|
|
@@ -3482,7 +3657,7 @@ function checkAndTruncateVCSInfo(gitMetaData) {
|
|
|
3482
3657
|
const truncateSize = gitMetaDataSizeInBytes - MAX_GIT_META_DATA_SIZE_IN_BYTES;
|
|
3483
3658
|
const truncatedCommitMessage = truncateString(gitMetaData.commit_message, truncateSize);
|
|
3484
3659
|
gitMetaData.commit_message = truncatedCommitMessage;
|
|
3485
|
-
|
|
3660
|
+
BStackLogger.info(`The commit has been truncated. Size of commit after truncation is ${getSizeOfJsonObjectInBytes(gitMetaData) / 1024} KB`);
|
|
3486
3661
|
}
|
|
3487
3662
|
return gitMetaData;
|
|
3488
3663
|
}
|
|
@@ -3494,7 +3669,7 @@ function getObservabilityProduct(options, isAppAutomate) {
|
|
|
3494
3669
|
}
|
|
3495
3670
|
async function pollApi(url3, params, headers, upperLimit, startTime = Date.now()) {
|
|
3496
3671
|
params.timestamp = Math.round(Date.now() / 1e3);
|
|
3497
|
-
|
|
3672
|
+
BStackLogger.debug(`current timestamp ${params.timestamp}`);
|
|
3498
3673
|
try {
|
|
3499
3674
|
const response = await makeGetRequest(url3, params, headers);
|
|
3500
3675
|
const responseData = await response.json();
|
|
@@ -3506,9 +3681,9 @@ async function pollApi(url3, params, headers, upperLimit, startTime = Date.now()
|
|
|
3506
3681
|
} catch (error) {
|
|
3507
3682
|
if (error.response && error.response.status === 404) {
|
|
3508
3683
|
const nextPollTime = parseInt(error.response.headers.get("next_poll_time"), 10) * 1e3;
|
|
3509
|
-
|
|
3684
|
+
BStackLogger.debug(`timeInMillis ${nextPollTime}`);
|
|
3510
3685
|
if (isNaN(nextPollTime)) {
|
|
3511
|
-
|
|
3686
|
+
BStackLogger.warn("Invalid or missing `nextPollTime` header. Stopping polling.");
|
|
3512
3687
|
return {
|
|
3513
3688
|
data: {},
|
|
3514
3689
|
headers: error.response.headers,
|
|
@@ -3516,18 +3691,18 @@ async function pollApi(url3, params, headers, upperLimit, startTime = Date.now()
|
|
|
3516
3691
|
};
|
|
3517
3692
|
}
|
|
3518
3693
|
const elapsedTime = nextPollTime - Date.now();
|
|
3519
|
-
|
|
3694
|
+
BStackLogger.debug(
|
|
3520
3695
|
`elapsedTime ${elapsedTime} timeInMillis ${nextPollTime} upperLimit ${upperLimit}`
|
|
3521
3696
|
);
|
|
3522
3697
|
if (nextPollTime > upperLimit) {
|
|
3523
|
-
|
|
3698
|
+
BStackLogger.warn("Polling stopped due to upper time limit.");
|
|
3524
3699
|
return {
|
|
3525
3700
|
data: {},
|
|
3526
3701
|
headers: error.response.headers,
|
|
3527
3702
|
message: "Polling stopped due to upper time limit."
|
|
3528
3703
|
};
|
|
3529
3704
|
}
|
|
3530
|
-
|
|
3705
|
+
BStackLogger.debug(`Polling again in ${elapsedTime}ms with params:`, params);
|
|
3531
3706
|
await new Promise((resolve) => setTimeout(resolve, elapsedTime));
|
|
3532
3707
|
return pollApi(url3, params, headers, upperLimit, startTime);
|
|
3533
3708
|
} else if (error.response) {
|
|
@@ -3536,7 +3711,7 @@ async function pollApi(url3, params, headers, upperLimit, startTime = Date.now()
|
|
|
3536
3711
|
const parsedError = JSON.parse(error.response.json());
|
|
3537
3712
|
errorMessage = parsedError.message;
|
|
3538
3713
|
} catch {
|
|
3539
|
-
|
|
3714
|
+
BStackLogger.debug(`Error parsing pollApi request body ${error.response.body}`);
|
|
3540
3715
|
errorMessage = "Unknown error";
|
|
3541
3716
|
}
|
|
3542
3717
|
throw {
|
|
@@ -3545,7 +3720,7 @@ async function pollApi(url3, params, headers, upperLimit, startTime = Date.now()
|
|
|
3545
3720
|
message: errorMessage
|
|
3546
3721
|
};
|
|
3547
3722
|
} else {
|
|
3548
|
-
|
|
3723
|
+
BStackLogger.error(`Unexpected error occurred: ${error}`);
|
|
3549
3724
|
return { data: {}, headers: {}, message: "Unexpected error occurred." };
|
|
3550
3725
|
}
|
|
3551
3726
|
}
|
|
@@ -3654,28 +3829,28 @@ function nestedKeyValue(hash, keys) {
|
|
|
3654
3829
|
return keys.reduce((hash2, key) => isHash(hash2) ? hash2[key] : void 0, hash);
|
|
3655
3830
|
}
|
|
3656
3831
|
function removeDir(dir) {
|
|
3657
|
-
const list =
|
|
3832
|
+
const list = fs7.readdirSync(dir);
|
|
3658
3833
|
for (let i = 0; i < list.length; i++) {
|
|
3659
|
-
const filename =
|
|
3660
|
-
const stat =
|
|
3834
|
+
const filename = path6.join(dir, list[i]);
|
|
3835
|
+
const stat = fs7.statSync(filename);
|
|
3661
3836
|
if (filename === "." || filename === "..") {
|
|
3662
3837
|
} else if (stat.isDirectory()) {
|
|
3663
3838
|
removeDir(filename);
|
|
3664
3839
|
} else {
|
|
3665
|
-
|
|
3840
|
+
fs7.unlinkSync(filename);
|
|
3666
3841
|
}
|
|
3667
3842
|
}
|
|
3668
|
-
|
|
3843
|
+
fs7.rmdirSync(dir);
|
|
3669
3844
|
}
|
|
3670
3845
|
function createDir(dir) {
|
|
3671
|
-
if (
|
|
3846
|
+
if (fs7.existsSync(dir)) {
|
|
3672
3847
|
removeDir(dir);
|
|
3673
3848
|
}
|
|
3674
|
-
|
|
3849
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
3675
3850
|
}
|
|
3676
3851
|
function isWritable(dirPath) {
|
|
3677
3852
|
try {
|
|
3678
|
-
|
|
3853
|
+
fs7.accessSync(dirPath, fs7.constants.W_OK);
|
|
3679
3854
|
return true;
|
|
3680
3855
|
} catch {
|
|
3681
3856
|
return false;
|
|
@@ -3683,10 +3858,10 @@ function isWritable(dirPath) {
|
|
|
3683
3858
|
}
|
|
3684
3859
|
function setReadWriteAccess(dirPath) {
|
|
3685
3860
|
try {
|
|
3686
|
-
|
|
3687
|
-
|
|
3861
|
+
fs7.chmodSync(dirPath, 438);
|
|
3862
|
+
BStackLogger.debug(`Directory ${dirPath} is now read/write accessible.`);
|
|
3688
3863
|
} catch (err) {
|
|
3689
|
-
|
|
3864
|
+
BStackLogger.error(`Failed to set directory access: ${err.stack}`);
|
|
3690
3865
|
}
|
|
3691
3866
|
}
|
|
3692
3867
|
function getMochaTestHierarchy(test) {
|
|
@@ -3714,7 +3889,7 @@ function isMultiRemoteCaps(capabilities) {
|
|
|
3714
3889
|
(cap) => Object.values(cap).length > 0 && Object.values(cap).every((c) => c !== null && typeof c === "object" && c.capabilities)
|
|
3715
3890
|
);
|
|
3716
3891
|
}
|
|
3717
|
-
var pGitconfig, DEFAULT_REQUEST_CONFIG, COLORS, processTestObservabilityResponse, jsonifyAccessibilityArray, processAccessibilityResponse, processLaunchBuildResponse, launchTestSession, validateCapsWithAppA11y, validateCapsWithA11y, validateCapsWithNonBstackA11y, shouldScanTestForAccessibility, isAccessibilityAutomationSession, isAppAccessibilityAutomationSession, formatString, _getParamsForAppAccessibility, performA11yScan, getA11yResults, getAppA11yResults, getAppA11yResultsSummary, getAppA11yResultResponse, getA11yResultsSummary, stopBuildUpstream, patchConsoleLogs, sleep, isObject, ObjectsAreEqual, getPlatformVersion, getBasicAuthHeader, isObjectEmpty, getErrorString, hasBrowserName, isValidCapsForHealing, performO11ySync;
|
|
3892
|
+
var pGitconfig, DEFAULT_REQUEST_CONFIG, COLORS, processTestObservabilityResponse, jsonifyAccessibilityArray, processAccessibilityResponse, processLaunchBuildResponse, launchTestSession, validateCapsWithAppA11y, validateCapsWithA11y, validateCapsWithNonBstackA11y, shouldScanTestForAccessibility, isAccessibilityAutomationSession, isAppAccessibilityAutomationSession, formatString, _getParamsForAppAccessibility, performA11yScan, getA11yResults, getAppA11yResults, getAppA11yResultsSummary, getAppA11yResultResponse, getA11yResultsSummary, stopBuildUpstream, patchConsoleLogs, sleep, isObject, ObjectsAreEqual, getPlatformVersion, getResolvedDeviceName, getBasicAuthHeader, isObjectEmpty, getErrorString, hasBrowserName, isValidCapsForHealing, performO11ySync;
|
|
3718
3893
|
var init_util = __esm({
|
|
3719
3894
|
"src/util.ts"() {
|
|
3720
3895
|
"use strict";
|
|
@@ -3788,7 +3963,7 @@ var init_util = __esm({
|
|
|
3788
3963
|
};
|
|
3789
3964
|
if (scannerVersion) {
|
|
3790
3965
|
process.env.BSTACK_A11Y_SCANNER_VERSION = scannerVersion;
|
|
3791
|
-
|
|
3966
|
+
BStackLogger.debug(`Accessibility scannerVersion ${scannerVersion}`);
|
|
3792
3967
|
}
|
|
3793
3968
|
if (accessibilityToken) {
|
|
3794
3969
|
process.env.BSTACK_A11Y_JWT = accessibilityToken;
|
|
@@ -3860,7 +4035,7 @@ var init_util = __esm({
|
|
|
3860
4035
|
CrashReporter.userConfigForReporting = process.env.USER_CONFIG_FOR_REPORTING !== void 0 ? JSON.parse(process.env.USER_CONFIG_FOR_REPORTING) : {};
|
|
3861
4036
|
}
|
|
3862
4037
|
} catch (error) {
|
|
3863
|
-
return
|
|
4038
|
+
return BStackLogger.error(`[Crash_Report_Upload] Failed to parse user config while sending build start event due to ${error}`);
|
|
3864
4039
|
}
|
|
3865
4040
|
data.config = CrashReporter.userConfigForReporting;
|
|
3866
4041
|
try {
|
|
@@ -3877,8 +4052,8 @@ var init_util = __esm({
|
|
|
3877
4052
|
});
|
|
3878
4053
|
const jsonResponse = await response.json();
|
|
3879
4054
|
delete data?.accessibility?.settings?.includeEncodedExtension;
|
|
3880
|
-
|
|
3881
|
-
|
|
4055
|
+
BStackLogger.debug(`[Start_Build] Success response: ${JSON.stringify(jsonResponse)}`);
|
|
4056
|
+
BStackLogger.debug(`Test Plan Id sent in request: ${getTestPlanId(options)}`);
|
|
3882
4057
|
process.env[TESTOPS_BUILD_COMPLETED_ENV] = "true";
|
|
3883
4058
|
if (jsonResponse.jwt) {
|
|
3884
4059
|
process.env[BROWSERSTACK_TESTHUB_JWT] = jsonResponse.jwt;
|
|
@@ -3886,13 +4061,13 @@ var init_util = __esm({
|
|
|
3886
4061
|
if (jsonResponse.build_hashed_id) {
|
|
3887
4062
|
process.env[BROWSERSTACK_TESTHUB_UUID] = jsonResponse.build_hashed_id;
|
|
3888
4063
|
testOpsConfig_default.getInstance().buildHashedId = jsonResponse.build_hashed_id;
|
|
3889
|
-
|
|
4064
|
+
BStackLogger.info(`Testhub started with id: ${testOpsConfig_default.getInstance()?.buildHashedId}`);
|
|
3890
4065
|
}
|
|
3891
4066
|
processLaunchBuildResponse(jsonResponse, options);
|
|
3892
4067
|
launchBuildUsage.success();
|
|
3893
4068
|
return jsonResponse;
|
|
3894
4069
|
} catch (error) {
|
|
3895
|
-
|
|
4070
|
+
BStackLogger.debug(`TestHub build start failed: ${format(error)}`);
|
|
3896
4071
|
if (!error.success) {
|
|
3897
4072
|
launchBuildUsage.failed(error);
|
|
3898
4073
|
logBuildError(error);
|
|
@@ -3902,7 +4077,7 @@ var init_util = __esm({
|
|
|
3902
4077
|
}));
|
|
3903
4078
|
validateCapsWithAppA11y = (platformMeta) => {
|
|
3904
4079
|
if (platformMeta?.platform_name && String(platformMeta?.platform_name).toLowerCase() === "android" && (platformMeta?.platform_version && parseInt(platformMeta?.platform_version?.toString()) < 11)) {
|
|
3905
|
-
|
|
4080
|
+
BStackLogger.warn("App Accessibility Automation tests are supported on OS version 11 and above for Android devices.");
|
|
3906
4081
|
return false;
|
|
3907
4082
|
}
|
|
3908
4083
|
return true;
|
|
@@ -3910,38 +4085,79 @@ var init_util = __esm({
|
|
|
3910
4085
|
validateCapsWithA11y = (deviceName, platformMeta, chromeOptions) => {
|
|
3911
4086
|
try {
|
|
3912
4087
|
if (deviceName) {
|
|
3913
|
-
|
|
3914
|
-
return false;
|
|
3915
|
-
}
|
|
3916
|
-
if (platformMeta?.browser_name?.toLowerCase() !== "chrome") {
|
|
3917
|
-
BStackLogger2.warn("Accessibility Automation will run only on Chrome browsers.");
|
|
4088
|
+
BStackLogger.warn("Accessibility Automation will run only on Desktop browsers.");
|
|
3918
4089
|
return false;
|
|
3919
4090
|
}
|
|
4091
|
+
const browserName = platformMeta?.browser_name?.toLowerCase();
|
|
3920
4092
|
const browserVersion = platformMeta?.browser_version;
|
|
3921
|
-
|
|
3922
|
-
|
|
4093
|
+
const validBrowsers = SUPPORTED_BROWSERS_FOR_ACCESSIBILITY;
|
|
4094
|
+
if (!browserName || !validBrowsers.includes(browserName)) {
|
|
4095
|
+
BStackLogger.warn(`Accessibility Automation supports Chrome 95+, Chrome for Testing 141+, and Safari 18.4+. Current browser: ${browserName}`);
|
|
3923
4096
|
return false;
|
|
3924
4097
|
}
|
|
3925
|
-
if (
|
|
3926
|
-
|
|
3927
|
-
|
|
4098
|
+
if (browserName === "chrome" || browserName === "chromefortesting") {
|
|
4099
|
+
const minVersion = MIN_BROWSER_VERSIONS_A11Y[browserName];
|
|
4100
|
+
if (browserVersion && browserVersion !== "latest") {
|
|
4101
|
+
const version3 = parseInt(browserVersion.toString().split(".")[0] || "0", 10);
|
|
4102
|
+
if (version3 < minVersion) {
|
|
4103
|
+
BStackLogger.warn(`Accessibility Automation requires ${browserName === "chrome" ? "Chrome" : "Chrome for Testing"} version ${minVersion} or higher.`);
|
|
4104
|
+
return false;
|
|
4105
|
+
}
|
|
4106
|
+
}
|
|
4107
|
+
if (chromeOptions?.args?.includes("--headless")) {
|
|
4108
|
+
BStackLogger.warn("Accessibility Automation will not run on legacy headless mode. Switch to new headless mode or avoid using headless mode.");
|
|
4109
|
+
return false;
|
|
4110
|
+
}
|
|
4111
|
+
}
|
|
4112
|
+
if (browserName === "safari") {
|
|
4113
|
+
if (browserVersion && browserVersion !== "latest") {
|
|
4114
|
+
const [currentMajor = 0, currentMinor = 0] = browserVersion.toString().split(".").map(Number);
|
|
4115
|
+
const [requiredMajor = 0, requiredMinor = 0] = MIN_BROWSER_VERSIONS_A11Y.safari.toString().split(".").map(Number);
|
|
4116
|
+
if (currentMajor < requiredMajor || currentMajor === requiredMajor && currentMinor < requiredMinor) {
|
|
4117
|
+
BStackLogger.warn(`Accessibility Automation requires Safari version ${MIN_BROWSER_VERSIONS_A11Y.safari} or higher.`);
|
|
4118
|
+
return false;
|
|
4119
|
+
}
|
|
4120
|
+
}
|
|
3928
4121
|
}
|
|
3929
4122
|
return true;
|
|
3930
4123
|
} catch (error) {
|
|
3931
|
-
|
|
4124
|
+
BStackLogger.debug(`Exception in checking capabilities compatibility with Accessibility. Error: ${error}`);
|
|
3932
4125
|
}
|
|
3933
4126
|
return false;
|
|
3934
4127
|
};
|
|
3935
4128
|
validateCapsWithNonBstackA11y = (browserName, browserVersion) => {
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
4129
|
+
try {
|
|
4130
|
+
const browser = browserName?.toLowerCase();
|
|
4131
|
+
const validBrowsers = ["chrome", "chromefortesting", "safari"];
|
|
4132
|
+
if (!browser || !validBrowsers.includes(browser)) {
|
|
4133
|
+
BStackLogger.warn("Accessibility Automation on non-BrowserStack infrastructure supports Chrome 100+, Chrome for Testing 141+, and Safari 18.4+.");
|
|
4134
|
+
return false;
|
|
4135
|
+
}
|
|
4136
|
+
if (browser === "chrome" || browser === "chromefortesting") {
|
|
4137
|
+
const minVersion = MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK[browser];
|
|
4138
|
+
if (browserVersion && browserVersion !== "latest") {
|
|
4139
|
+
const version3 = parseInt(browserVersion.toString().split(".")[0] || "0", 10);
|
|
4140
|
+
if (version3 < minVersion) {
|
|
4141
|
+
BStackLogger.warn(`Accessibility Automation requires ${browser === "chrome" ? "Chrome" : "Chrome for Testing"} version ${minVersion}+ on non-BrowserStack infrastructure.`);
|
|
4142
|
+
return false;
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4145
|
+
}
|
|
4146
|
+
if (browser === "safari") {
|
|
4147
|
+
if (browserVersion && browserVersion !== "latest") {
|
|
4148
|
+
const [currentMajor = 0, currentMinor = 0] = browserVersion.toString().split(".").map(Number);
|
|
4149
|
+
const [requiredMajor = 0, requiredMinor = 0] = MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK.safari.toString().split(".").map(Number);
|
|
4150
|
+
if (currentMajor < requiredMajor || currentMajor === requiredMajor && currentMinor < requiredMinor) {
|
|
4151
|
+
BStackLogger.warn(`Accessibility Automation requires Safari version ${MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK.safari}+ on non-BrowserStack infrastructure.`);
|
|
4152
|
+
return false;
|
|
4153
|
+
}
|
|
4154
|
+
}
|
|
4155
|
+
}
|
|
4156
|
+
return true;
|
|
4157
|
+
} catch (error) {
|
|
4158
|
+
BStackLogger.debug(`Exception in checking capabilities compatibility with Accessibility. Error: ${error}`);
|
|
3943
4159
|
}
|
|
3944
|
-
return
|
|
4160
|
+
return false;
|
|
3945
4161
|
};
|
|
3946
4162
|
shouldScanTestForAccessibility = (suiteTitle, testTitle, accessibilityOptions, world, isCucumber) => {
|
|
3947
4163
|
try {
|
|
@@ -3959,7 +4175,7 @@ var init_util = __esm({
|
|
|
3959
4175
|
const included = includeTags?.length === 0 || includeTags?.some((include) => fullTestName.includes(include));
|
|
3960
4176
|
return !excluded && included;
|
|
3961
4177
|
} catch (error) {
|
|
3962
|
-
|
|
4178
|
+
BStackLogger.debug(`Error while validating test case for accessibility before scanning. Error : ${error}`);
|
|
3963
4179
|
}
|
|
3964
4180
|
return false;
|
|
3965
4181
|
};
|
|
@@ -3968,7 +4184,7 @@ var init_util = __esm({
|
|
|
3968
4184
|
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";
|
|
3969
4185
|
return accessibilityFlag && hasA11yJwtToken;
|
|
3970
4186
|
} catch (error) {
|
|
3971
|
-
|
|
4187
|
+
BStackLogger.debug(`Exception in verifying the Accessibility session with error : ${error}`);
|
|
3972
4188
|
}
|
|
3973
4189
|
return false;
|
|
3974
4190
|
};
|
|
@@ -3999,43 +4215,43 @@ var init_util = __esm({
|
|
|
3999
4215
|
};
|
|
4000
4216
|
performA11yScan = async (isAppAutomate, browser, isBrowserStackSession, isAccessibility, commandName, testName) => {
|
|
4001
4217
|
if (!isAccessibilityAutomationSession(isAccessibility)) {
|
|
4002
|
-
|
|
4218
|
+
BStackLogger.warn("Not an Accessibility Automation session, cannot perform Accessibility scan.");
|
|
4003
4219
|
return;
|
|
4004
4220
|
}
|
|
4005
4221
|
try {
|
|
4006
4222
|
if (isAppAccessibilityAutomationSession(isAccessibility, isAppAutomate)) {
|
|
4007
4223
|
const results = await browser.execute(formatString(accessibility_scripts_default.performScan, JSON.stringify(_getParamsForAppAccessibility(commandName, testName))), {});
|
|
4008
|
-
|
|
4224
|
+
BStackLogger.debug(util3.format(results));
|
|
4009
4225
|
return results;
|
|
4010
4226
|
}
|
|
4011
4227
|
if (accessibility_scripts_default.performScan) {
|
|
4012
4228
|
const results = await executeAccessibilityScript(browser, accessibility_scripts_default.performScan, { method: commandName || "" });
|
|
4013
4229
|
return results;
|
|
4014
4230
|
}
|
|
4015
|
-
|
|
4231
|
+
BStackLogger.error("AccessibilityScripts.performScan is null");
|
|
4016
4232
|
return;
|
|
4017
4233
|
} catch (err) {
|
|
4018
|
-
|
|
4234
|
+
BStackLogger.error("Accessibility Scan could not be performed : " + err);
|
|
4019
4235
|
return;
|
|
4020
4236
|
}
|
|
4021
4237
|
};
|
|
4022
4238
|
getA11yResults = PerformanceTester.measureWrapper(A11Y_EVENTS.GET_RESULTS, async (isAppAutomate, browser, isBrowserStackSession, isAccessibility) => {
|
|
4023
4239
|
if (!isAccessibilityAutomationSession(isAccessibility)) {
|
|
4024
|
-
|
|
4240
|
+
BStackLogger.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results.");
|
|
4025
4241
|
return [];
|
|
4026
4242
|
}
|
|
4027
4243
|
try {
|
|
4028
|
-
|
|
4244
|
+
BStackLogger.debug("Performing scan before getting results");
|
|
4029
4245
|
await performA11yScan(isAppAutomate, browser, isBrowserStackSession, isAccessibility);
|
|
4030
4246
|
if (accessibility_scripts_default.getResults) {
|
|
4031
4247
|
const results = await executeAccessibilityScript(browser, accessibility_scripts_default.getResults);
|
|
4032
4248
|
return results;
|
|
4033
4249
|
}
|
|
4034
|
-
|
|
4250
|
+
BStackLogger.error("AccessibilityScripts.getResults is null");
|
|
4035
4251
|
return [];
|
|
4036
4252
|
} catch (error) {
|
|
4037
|
-
|
|
4038
|
-
|
|
4253
|
+
BStackLogger.error("No accessibility results were found.");
|
|
4254
|
+
BStackLogger.debug(`getA11yResults Failed. Error: ${error}`);
|
|
4039
4255
|
return [];
|
|
4040
4256
|
}
|
|
4041
4257
|
});
|
|
@@ -4044,18 +4260,18 @@ var init_util = __esm({
|
|
|
4044
4260
|
return [];
|
|
4045
4261
|
}
|
|
4046
4262
|
if (!isAppAccessibilityAutomationSession(isAccessibility, isAppAutomate)) {
|
|
4047
|
-
|
|
4263
|
+
BStackLogger.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results summary.");
|
|
4048
4264
|
return [];
|
|
4049
4265
|
}
|
|
4050
4266
|
try {
|
|
4051
4267
|
const apiUrl = `${APIUtils.APP_ALLY_ENDPOINT}/${APP_ALLY_ISSUES_ENDPOINT}`;
|
|
4052
4268
|
const apiRespone = await getAppA11yResultResponse(apiUrl, isAppAutomate, browser, testName, isBrowserStackSession, isAccessibility, sessionId);
|
|
4053
4269
|
const result = apiRespone?.data?.data?.issues;
|
|
4054
|
-
|
|
4270
|
+
BStackLogger.debug(`Polling Result: ${JSON.stringify(result)}`);
|
|
4055
4271
|
return result;
|
|
4056
4272
|
} catch (error) {
|
|
4057
|
-
|
|
4058
|
-
|
|
4273
|
+
BStackLogger.error("No accessibility summary was found.");
|
|
4274
|
+
BStackLogger.debug(`getAppA11yResults Failed. Error: ${error}`);
|
|
4059
4275
|
return [];
|
|
4060
4276
|
}
|
|
4061
4277
|
});
|
|
@@ -4064,46 +4280,46 @@ var init_util = __esm({
|
|
|
4064
4280
|
return {};
|
|
4065
4281
|
}
|
|
4066
4282
|
if (!isAppAccessibilityAutomationSession(isAccessibility, isAppAutomate)) {
|
|
4067
|
-
|
|
4283
|
+
BStackLogger.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results summary.");
|
|
4068
4284
|
return {};
|
|
4069
4285
|
}
|
|
4070
4286
|
try {
|
|
4071
4287
|
const apiUrl = `${APIUtils.APP_ALLY_ENDPOINT}/${APP_ALLY_ISSUES_SUMMARY_ENDPOINT}`;
|
|
4072
4288
|
const apiRespone = await getAppA11yResultResponse(apiUrl, isAppAutomate, browser, testName, isBrowserStackSession, isAccessibility, sessionId);
|
|
4073
4289
|
const result = apiRespone?.data?.data?.summary;
|
|
4074
|
-
|
|
4290
|
+
BStackLogger.debug(`Polling Result: ${JSON.stringify(result)}`);
|
|
4075
4291
|
return result;
|
|
4076
4292
|
} catch {
|
|
4077
|
-
|
|
4293
|
+
BStackLogger.error("No accessibility summary was found.");
|
|
4078
4294
|
return {};
|
|
4079
4295
|
}
|
|
4080
4296
|
});
|
|
4081
4297
|
getAppA11yResultResponse = async (apiUrl, isAppAutomate, browser, testName, isBrowserStackSession, isAccessibility, sessionId) => {
|
|
4082
|
-
|
|
4298
|
+
BStackLogger.debug("Performing scan before getting results summary");
|
|
4083
4299
|
await performA11yScan(isAppAutomate, browser, isBrowserStackSession, isAccessibility, void 0, testName);
|
|
4084
4300
|
const upperTimeLimit = process.env.BSTACK_A11Y_POLLING_TIMEOUT ? Date.now() + parseInt(process.env.BSTACK_A11Y_POLLING_TIMEOUT) * 1e3 : Date.now() + 3e4;
|
|
4085
4301
|
const params = { test_run_uuid: process.env.TEST_ANALYTICS_ID, session_id: sessionId, timestamp: Date.now() };
|
|
4086
4302
|
const header = { Authorization: `Bearer ${process.env.BSTACK_A11Y_JWT}` };
|
|
4087
4303
|
const apiRespone = await pollApi(apiUrl, params, header, upperTimeLimit);
|
|
4088
|
-
|
|
4304
|
+
BStackLogger.debug(`Polling Result: ${JSON.stringify(apiRespone)}`);
|
|
4089
4305
|
return apiRespone;
|
|
4090
4306
|
};
|
|
4091
4307
|
getA11yResultsSummary = PerformanceTester.measureWrapper(A11Y_EVENTS.GET_RESULTS_SUMMARY, async (isAppAutomate, browser, isBrowserStackSession, isAccessibility) => {
|
|
4092
4308
|
if (!isAccessibilityAutomationSession(isAccessibility)) {
|
|
4093
|
-
|
|
4309
|
+
BStackLogger.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results summary.");
|
|
4094
4310
|
return {};
|
|
4095
4311
|
}
|
|
4096
4312
|
try {
|
|
4097
|
-
|
|
4313
|
+
BStackLogger.debug("Performing scan before getting results summary");
|
|
4098
4314
|
await performA11yScan(isAppAutomate, browser, isBrowserStackSession, isAccessibility);
|
|
4099
4315
|
if (accessibility_scripts_default.getResultsSummary) {
|
|
4100
4316
|
const summaryResults = await executeAccessibilityScript(browser, accessibility_scripts_default.getResultsSummary);
|
|
4101
4317
|
return summaryResults;
|
|
4102
4318
|
}
|
|
4103
|
-
|
|
4319
|
+
BStackLogger.error("AccessibilityScripts.getResultsSummary is null");
|
|
4104
4320
|
return {};
|
|
4105
4321
|
} catch {
|
|
4106
|
-
|
|
4322
|
+
BStackLogger.error("No accessibility summary was found.");
|
|
4107
4323
|
return {};
|
|
4108
4324
|
}
|
|
4109
4325
|
});
|
|
@@ -4119,7 +4335,7 @@ var init_util = __esm({
|
|
|
4119
4335
|
}
|
|
4120
4336
|
if (!process.env[BROWSERSTACK_TESTHUB_JWT]) {
|
|
4121
4337
|
stopBuildUsage.failed("Token/buildID is undefined, build creation might have failed");
|
|
4122
|
-
|
|
4338
|
+
BStackLogger.debug("[STOP_BUILD] Missing Authentication Token/ Build ID");
|
|
4123
4339
|
return {
|
|
4124
4340
|
status: "error",
|
|
4125
4341
|
message: "Token/buildID is undefined, build creation might have failed"
|
|
@@ -4138,7 +4354,7 @@ var init_util = __esm({
|
|
|
4138
4354
|
},
|
|
4139
4355
|
body: JSON.stringify(data)
|
|
4140
4356
|
});
|
|
4141
|
-
|
|
4357
|
+
BStackLogger.debug(`[STOP_BUILD] Success response: ${await response.text()}`);
|
|
4142
4358
|
stopBuildUsage.success();
|
|
4143
4359
|
return {
|
|
4144
4360
|
status: "success",
|
|
@@ -4146,7 +4362,7 @@ var init_util = __esm({
|
|
|
4146
4362
|
};
|
|
4147
4363
|
} catch (error) {
|
|
4148
4364
|
stopBuildUsage.failed(error);
|
|
4149
|
-
|
|
4365
|
+
BStackLogger.debug(`[STOP_BUILD] Failed. Error: ${error}`);
|
|
4150
4366
|
return {
|
|
4151
4367
|
status: "error",
|
|
4152
4368
|
message: error.message
|
|
@@ -4157,7 +4373,7 @@ var init_util = __esm({
|
|
|
4157
4373
|
const BSTestOpsPatcher = new logPatcher_default({});
|
|
4158
4374
|
Object.keys(consoleHolder).forEach((method) => {
|
|
4159
4375
|
if (!(method in console) || method === "Console" || typeof console[method] !== "function") {
|
|
4160
|
-
|
|
4376
|
+
BStackLogger.debug(`Skipping method: ${method}, exists: ${method in console}, type: ${typeof console[method]}`);
|
|
4161
4377
|
return;
|
|
4162
4378
|
}
|
|
4163
4379
|
const origMethod = console[method].bind(console);
|
|
@@ -4170,7 +4386,7 @@ var init_util = __esm({
|
|
|
4170
4386
|
BSTestOpsPatcher[method](...args);
|
|
4171
4387
|
}
|
|
4172
4388
|
} catch (error) {
|
|
4173
|
-
|
|
4389
|
+
BStackLogger.debug(`Error while patching console logs : ${error}`);
|
|
4174
4390
|
origMethod(...args);
|
|
4175
4391
|
}
|
|
4176
4392
|
};
|
|
@@ -4204,18 +4420,57 @@ var init_util = __esm({
|
|
|
4204
4420
|
const keys = ["platformVersion", "platform_version", "osVersion", "os_version"];
|
|
4205
4421
|
for (const key of keys) {
|
|
4206
4422
|
if (caps?.[key]) {
|
|
4207
|
-
|
|
4423
|
+
BStackLogger.debug(`Got ${key} from driver caps`);
|
|
4208
4424
|
return String(caps?.[key]);
|
|
4209
4425
|
} else if (bstackOptions && bstackOptions?.[key]) {
|
|
4210
|
-
|
|
4426
|
+
BStackLogger.debug(`Got ${key} from user bstack options`);
|
|
4211
4427
|
return String(bstackOptions?.[key]);
|
|
4212
4428
|
} else if (userCaps[key]) {
|
|
4213
|
-
|
|
4429
|
+
BStackLogger.debug(`Got ${key} from user caps`);
|
|
4214
4430
|
return String(userCaps[key]);
|
|
4215
4431
|
}
|
|
4216
4432
|
}
|
|
4217
4433
|
return void 0;
|
|
4218
4434
|
});
|
|
4435
|
+
getResolvedDeviceName = o11yErrorHandler(function getResolvedDeviceName2(driverCaps, requestedCaps) {
|
|
4436
|
+
const flattenMultiremote = (caps) => {
|
|
4437
|
+
if (!caps) {
|
|
4438
|
+
return [];
|
|
4439
|
+
}
|
|
4440
|
+
const obj = caps;
|
|
4441
|
+
if (obj["deviceModel"] || obj["appium:deviceModel"] || obj["deviceName"] || obj["bstack:options"]) {
|
|
4442
|
+
return [caps];
|
|
4443
|
+
}
|
|
4444
|
+
return Object.values(obj).filter((v) => v !== null && typeof v === "object" && "capabilities" in v).map((v) => v.capabilities).filter(Boolean);
|
|
4445
|
+
};
|
|
4446
|
+
const sources = [
|
|
4447
|
+
...flattenMultiremote(driverCaps),
|
|
4448
|
+
...flattenMultiremote(requestedCaps)
|
|
4449
|
+
];
|
|
4450
|
+
if (!sources.length) {
|
|
4451
|
+
return void 0;
|
|
4452
|
+
}
|
|
4453
|
+
const pickString = (obj, key) => {
|
|
4454
|
+
const v = obj?.[key];
|
|
4455
|
+
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
4456
|
+
};
|
|
4457
|
+
const paths = [
|
|
4458
|
+
(c) => pickString(c, "deviceModel"),
|
|
4459
|
+
(c) => pickString(c, "appium:deviceModel"),
|
|
4460
|
+
(c) => pickString(c["bstack:options"], "deviceName"),
|
|
4461
|
+
(c) => pickString(c, "appium:deviceName"),
|
|
4462
|
+
(c) => pickString(c, "deviceName")
|
|
4463
|
+
];
|
|
4464
|
+
for (const path22 of paths) {
|
|
4465
|
+
for (const src of sources) {
|
|
4466
|
+
const v = path22(src);
|
|
4467
|
+
if (v) {
|
|
4468
|
+
return v;
|
|
4469
|
+
}
|
|
4470
|
+
}
|
|
4471
|
+
}
|
|
4472
|
+
return void 0;
|
|
4473
|
+
});
|
|
4219
4474
|
getBasicAuthHeader = (username, password) => {
|
|
4220
4475
|
const encodedAuth = Buffer.from(`${username}:${password}`, "utf8").toString("base64");
|
|
4221
4476
|
return `Basic ${encodedAuth}`;
|
|
@@ -4259,20 +4514,20 @@ var init_util = __esm({
|
|
|
4259
4514
|
});
|
|
4260
4515
|
|
|
4261
4516
|
// src/bstackLogger.ts
|
|
4262
|
-
import
|
|
4263
|
-
import
|
|
4517
|
+
import path7 from "node:path";
|
|
4518
|
+
import fs8 from "node:fs";
|
|
4264
4519
|
import chalk2 from "chalk";
|
|
4265
4520
|
import logger2 from "@wdio/logger";
|
|
4266
|
-
var log2,
|
|
4521
|
+
var log2, BStackLogger;
|
|
4267
4522
|
var init_bstackLogger = __esm({
|
|
4268
4523
|
"src/bstackLogger.ts"() {
|
|
4269
4524
|
"use strict";
|
|
4270
4525
|
init_constants();
|
|
4271
4526
|
init_util();
|
|
4272
4527
|
log2 = logger2("@wdio/browserstack-service");
|
|
4273
|
-
|
|
4274
|
-
static logFilePath =
|
|
4275
|
-
static logFolderPath =
|
|
4528
|
+
BStackLogger = class {
|
|
4529
|
+
static logFilePath = path7.join(process.cwd(), LOGS_FILE);
|
|
4530
|
+
static logFolderPath = path7.join(process.cwd(), "logs");
|
|
4276
4531
|
static logFileStream;
|
|
4277
4532
|
static redactCredentials(logMessage) {
|
|
4278
4533
|
return logMessage.replace(/(["']?(?:username|userName|accesskey|accessKey|user|key)["']?\s*[:=]\s*["']?)([^"'\s,}]+)/gi, "$1").replace(/([?&](?:username|userName|access_key|accesskey|accessKey|user|key)=)([^&#\s]+)/gi, "$1");
|
|
@@ -4282,7 +4537,7 @@ var init_bstackLogger = __esm({
|
|
|
4282
4537
|
const redactedMessage = this.redactCredentials(logMessage);
|
|
4283
4538
|
if (!this.logFileStream) {
|
|
4284
4539
|
this.ensureLogsFolder();
|
|
4285
|
-
this.logFileStream =
|
|
4540
|
+
this.logFileStream = fs8.createWriteStream(this.logFilePath, { flags: "a" });
|
|
4286
4541
|
}
|
|
4287
4542
|
if (this.logFileStream && this.logFileStream.writable) {
|
|
4288
4543
|
this.logFileStream.write(this.formatLog(redactedMessage, logLevel));
|
|
@@ -4331,13 +4586,13 @@ var init_bstackLogger = __esm({
|
|
|
4331
4586
|
this.logFileStream = null;
|
|
4332
4587
|
}
|
|
4333
4588
|
static clearLogFile() {
|
|
4334
|
-
if (
|
|
4335
|
-
|
|
4589
|
+
if (fs8.existsSync(this.logFilePath)) {
|
|
4590
|
+
fs8.truncateSync(this.logFilePath);
|
|
4336
4591
|
}
|
|
4337
4592
|
}
|
|
4338
4593
|
static ensureLogsFolder() {
|
|
4339
|
-
if (!
|
|
4340
|
-
|
|
4594
|
+
if (!fs8.existsSync(this.logFolderPath)) {
|
|
4595
|
+
fs8.mkdirSync(this.logFolderPath);
|
|
4341
4596
|
}
|
|
4342
4597
|
}
|
|
4343
4598
|
};
|
|
@@ -4355,7 +4610,7 @@ var init_utils = __esm({
|
|
|
4355
4610
|
getProductMap = (config) => {
|
|
4356
4611
|
const entries = [
|
|
4357
4612
|
["observability", config.testObservability.enabled],
|
|
4358
|
-
["accessibility", config.accessibility],
|
|
4613
|
+
["accessibility", !!config.accessibility],
|
|
4359
4614
|
["percy", config.percy],
|
|
4360
4615
|
["automate", config.automate],
|
|
4361
4616
|
["app_automate", config.appAutomate]
|
|
@@ -4384,7 +4639,7 @@ var init_utils = __esm({
|
|
|
4384
4639
|
};
|
|
4385
4640
|
logBuildError = (error, product = "") => {
|
|
4386
4641
|
if (!error || !error.errors) {
|
|
4387
|
-
|
|
4642
|
+
BStackLogger.error(`${product.toUpperCase()} Build creation failed ${error}`);
|
|
4388
4643
|
return;
|
|
4389
4644
|
}
|
|
4390
4645
|
for (const errorJson of error.errors) {
|
|
@@ -4393,16 +4648,16 @@ var init_utils = __esm({
|
|
|
4393
4648
|
if (errorMessage) {
|
|
4394
4649
|
switch (errorType) {
|
|
4395
4650
|
case "ERROR_INVALID_CREDENTIALS":
|
|
4396
|
-
|
|
4651
|
+
BStackLogger.error(errorMessage);
|
|
4397
4652
|
break;
|
|
4398
4653
|
case "ERROR_ACCESS_DENIED":
|
|
4399
|
-
|
|
4654
|
+
BStackLogger.info(errorMessage);
|
|
4400
4655
|
break;
|
|
4401
4656
|
case "ERROR_SDK_DEPRECATED":
|
|
4402
|
-
|
|
4657
|
+
BStackLogger.error(errorMessage);
|
|
4403
4658
|
break;
|
|
4404
4659
|
default:
|
|
4405
|
-
|
|
4660
|
+
BStackLogger.error(errorMessage);
|
|
4406
4661
|
}
|
|
4407
4662
|
}
|
|
4408
4663
|
}
|
|
@@ -4421,8 +4676,8 @@ var init_utils = __esm({
|
|
|
4421
4676
|
});
|
|
4422
4677
|
|
|
4423
4678
|
// src/Percy/PercyLogger.ts
|
|
4424
|
-
import
|
|
4425
|
-
import
|
|
4679
|
+
import path8 from "node:path";
|
|
4680
|
+
import fs9 from "node:fs";
|
|
4426
4681
|
import chalk3 from "chalk";
|
|
4427
4682
|
import logger3 from "@wdio/logger";
|
|
4428
4683
|
var log3, PercyLogger;
|
|
@@ -4433,16 +4688,16 @@ var init_PercyLogger = __esm({
|
|
|
4433
4688
|
init_util();
|
|
4434
4689
|
log3 = logger3("@wdio/browserstack-service");
|
|
4435
4690
|
PercyLogger = class {
|
|
4436
|
-
static logFilePath =
|
|
4437
|
-
static logFolderPath =
|
|
4691
|
+
static logFilePath = path8.join(process.cwd(), PERCY_LOGS_FILE);
|
|
4692
|
+
static logFolderPath = path8.join(process.cwd(), "logs");
|
|
4438
4693
|
static logFileStream;
|
|
4439
4694
|
static logToFile(logMessage, logLevel) {
|
|
4440
4695
|
try {
|
|
4441
4696
|
if (!this.logFileStream) {
|
|
4442
|
-
if (!
|
|
4443
|
-
|
|
4697
|
+
if (!fs9.existsSync(this.logFolderPath)) {
|
|
4698
|
+
fs9.mkdirSync(this.logFolderPath);
|
|
4444
4699
|
}
|
|
4445
|
-
this.logFileStream =
|
|
4700
|
+
this.logFileStream = fs9.createWriteStream(this.logFilePath, { flags: "a" });
|
|
4446
4701
|
}
|
|
4447
4702
|
if (this.logFileStream && this.logFileStream.writable) {
|
|
4448
4703
|
this.logFileStream.write(this.formatLog(logMessage, logLevel));
|
|
@@ -4486,8 +4741,8 @@ var init_PercyLogger = __esm({
|
|
|
4486
4741
|
this.logFileStream = null;
|
|
4487
4742
|
}
|
|
4488
4743
|
static clearLogFile() {
|
|
4489
|
-
if (
|
|
4490
|
-
|
|
4744
|
+
if (fs9.existsSync(this.logFilePath)) {
|
|
4745
|
+
fs9.truncateSync(this.logFilePath);
|
|
4491
4746
|
}
|
|
4492
4747
|
}
|
|
4493
4748
|
};
|
|
@@ -4495,7 +4750,7 @@ var init_PercyLogger = __esm({
|
|
|
4495
4750
|
});
|
|
4496
4751
|
|
|
4497
4752
|
// src/cli/grpcClient.ts
|
|
4498
|
-
import
|
|
4753
|
+
import path13 from "node:path";
|
|
4499
4754
|
import util5, { promisify as promisify3 } from "node:util";
|
|
4500
4755
|
import {
|
|
4501
4756
|
SDKClient,
|
|
@@ -4528,7 +4783,7 @@ var init_grpcClient = __esm({
|
|
|
4528
4783
|
listenAddress;
|
|
4529
4784
|
channel = null;
|
|
4530
4785
|
client = null;
|
|
4531
|
-
logger =
|
|
4786
|
+
logger = BStackLogger2;
|
|
4532
4787
|
constructor() {
|
|
4533
4788
|
}
|
|
4534
4789
|
/**
|
|
@@ -4620,7 +4875,7 @@ var init_grpcClient = __esm({
|
|
|
4620
4875
|
sdkLanguage: CLIUtils.getSdkLanguage(),
|
|
4621
4876
|
sdkVersion: packageVersion,
|
|
4622
4877
|
pathProject: process.cwd(),
|
|
4623
|
-
pathConfig:
|
|
4878
|
+
pathConfig: path13.resolve(process.cwd(), "browserstack.yml"),
|
|
4624
4879
|
cliArgs: process.argv.slice(2),
|
|
4625
4880
|
frameworks: [automationFrameworkDetail.name, testFrameworkDetail.name],
|
|
4626
4881
|
frameworkVersions,
|
|
@@ -5066,7 +5321,7 @@ var init_baseModule = __esm({
|
|
|
5066
5321
|
this.platformIndex = platformIndex;
|
|
5067
5322
|
this.client = client;
|
|
5068
5323
|
this.config = config;
|
|
5069
|
-
|
|
5324
|
+
BStackLogger2.debug(`Configured module ${this.getModuleName()} with binSessionId=${binSessionId}, platformIndex=${platformIndex}`);
|
|
5070
5325
|
}
|
|
5071
5326
|
};
|
|
5072
5327
|
}
|
|
@@ -5337,7 +5592,7 @@ var init_testFramework = __esm({
|
|
|
5337
5592
|
* @returns {void}
|
|
5338
5593
|
*/
|
|
5339
5594
|
trackEvent(testFrameworkState, hookState, args = {}) {
|
|
5340
|
-
|
|
5595
|
+
BStackLogger2.info(`trackEvent: testFrameworkState=${testFrameworkState}; hookState=${hookState}; args=${args}`);
|
|
5341
5596
|
}
|
|
5342
5597
|
/**
|
|
5343
5598
|
* run test hooks
|
|
@@ -5347,7 +5602,7 @@ var init_testFramework = __esm({
|
|
|
5347
5602
|
* @param {*} args
|
|
5348
5603
|
*/
|
|
5349
5604
|
async runHooks(instance, testFrameworkState, hookState, args = {}) {
|
|
5350
|
-
|
|
5605
|
+
BStackLogger2.info(`runHooks: instance=${instance} automationFrameworkState=${testFrameworkState} hookState=${hookState}`);
|
|
5351
5606
|
const hookRegistryKey = CLIUtils.getHookRegistryKey(testFrameworkState, hookState);
|
|
5352
5607
|
await eventDispatcher.notifyObserver(hookRegistryKey, args);
|
|
5353
5608
|
}
|
|
@@ -5611,7 +5866,7 @@ var init_automationFramework = __esm({
|
|
|
5611
5866
|
* @returns {void}
|
|
5612
5867
|
*/
|
|
5613
5868
|
async trackEvent(automationFrameworkState, hookState, args = {}) {
|
|
5614
|
-
|
|
5869
|
+
BStackLogger2.info(`trackEvent: automationFrameworkState=${automationFrameworkState} hookState=${hookState} args=${args}`);
|
|
5615
5870
|
}
|
|
5616
5871
|
/**
|
|
5617
5872
|
*
|
|
@@ -5621,7 +5876,7 @@ var init_automationFramework = __esm({
|
|
|
5621
5876
|
* @param {*} args
|
|
5622
5877
|
*/
|
|
5623
5878
|
async runHooks(instance, automationFrameworkState, hookState, args = {}) {
|
|
5624
|
-
|
|
5879
|
+
BStackLogger2.info(`runHooks: automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
|
|
5625
5880
|
const hookRegistryKey = CLIUtils.getHookRegistryKey(automationFrameworkState, hookState);
|
|
5626
5881
|
await eventDispatcher.notifyObserver(hookRegistryKey, args);
|
|
5627
5882
|
}
|
|
@@ -5639,7 +5894,7 @@ var init_automationFramework = __esm({
|
|
|
5639
5894
|
* @returns {void}
|
|
5640
5895
|
*/
|
|
5641
5896
|
static setTrackedInstance(context, instance) {
|
|
5642
|
-
|
|
5897
|
+
BStackLogger2.debug(`setTrackedInstance: ${context.getId()}`);
|
|
5643
5898
|
_AutomationFramework.instances.set(context.getId(), instance);
|
|
5644
5899
|
}
|
|
5645
5900
|
/**
|
|
@@ -5647,7 +5902,7 @@ var init_automationFramework = __esm({
|
|
|
5647
5902
|
* @returns {TrackedInstance} The tracked instance
|
|
5648
5903
|
*/
|
|
5649
5904
|
static getTrackedInstance() {
|
|
5650
|
-
|
|
5905
|
+
BStackLogger2.debug(`getTrackedInstance: ${CLIUtils.getCurrentInstanceName()}`);
|
|
5651
5906
|
const context = TrackedInstance.createContext(CLIUtils.getCurrentInstanceName());
|
|
5652
5907
|
return _AutomationFramework.instances.get(context.getId());
|
|
5653
5908
|
}
|
|
@@ -5775,7 +6030,7 @@ var init_automateModule = __esm({
|
|
|
5775
6030
|
init_automationFrameworkState();
|
|
5776
6031
|
init_fetchWrapper();
|
|
5777
6032
|
AutomateModule = class _AutomateModule extends BaseModule {
|
|
5778
|
-
logger =
|
|
6033
|
+
logger = BStackLogger2;
|
|
5779
6034
|
browserStackConfig;
|
|
5780
6035
|
sessionMap = /* @__PURE__ */ new Map();
|
|
5781
6036
|
static MODULE_NAME = "AutomateModule";
|
|
@@ -6091,7 +6346,7 @@ var init_testFrameworkInstance = __esm({
|
|
|
6091
6346
|
|
|
6092
6347
|
// src/cli/frameworks/wdioMochaTestFramework.ts
|
|
6093
6348
|
import { v4 as uuidv42 } from "uuid";
|
|
6094
|
-
import
|
|
6349
|
+
import path14 from "node:path";
|
|
6095
6350
|
var WdioMochaTestFramework;
|
|
6096
6351
|
var init_wdioMochaTestFramework = __esm({
|
|
6097
6352
|
"src/cli/frameworks/wdioMochaTestFramework.ts"() {
|
|
@@ -6125,11 +6380,11 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6125
6380
|
* @param {*} args
|
|
6126
6381
|
*/
|
|
6127
6382
|
async trackEvent(testFrameworkState, hookState, args = {}) {
|
|
6128
|
-
|
|
6383
|
+
BStackLogger2.info(`trackEvent: testFrameworkState=${testFrameworkState} hookState=${hookState}`);
|
|
6129
6384
|
await super.trackEvent(testFrameworkState, hookState, args);
|
|
6130
6385
|
const instance = this.resolveInstance(testFrameworkState, hookState, args);
|
|
6131
6386
|
if (instance === null) {
|
|
6132
|
-
|
|
6387
|
+
BStackLogger2.error(`trackEvent: instance not found for testFrameworkState=${testFrameworkState} hookState=${hookState}`);
|
|
6133
6388
|
return;
|
|
6134
6389
|
}
|
|
6135
6390
|
try {
|
|
@@ -6141,7 +6396,7 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6141
6396
|
if (!TestFramework.getState(instance, TestFrameworkConstants.KEY_TEST_ID) && hookState === HookState.PRE && testFrameworkState === TestFrameworkState.TEST) {
|
|
6142
6397
|
const test = args.test;
|
|
6143
6398
|
const testData = await this.getTestData(instance, test);
|
|
6144
|
-
|
|
6399
|
+
BStackLogger2.info(`trackEvent: instanceData=${JSON.stringify(Object.fromEntries(instance.getAllData()))}`);
|
|
6145
6400
|
instance.updateMultipleEntries(testData);
|
|
6146
6401
|
}
|
|
6147
6402
|
if (testFrameworkState === TestFrameworkState.TEST) {
|
|
@@ -6159,13 +6414,13 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6159
6414
|
logEntry.uuid = TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOK_ID);
|
|
6160
6415
|
this.loadLogEntries(instance, testFrameworkState, hookState, logEntry);
|
|
6161
6416
|
} else if (testFrameworkState === TestFrameworkState.LOG_REPORT && hookState === HookState.POST) {
|
|
6162
|
-
|
|
6417
|
+
BStackLogger2.info("trackEvent: load test results");
|
|
6163
6418
|
this.loadTestResult(instance, args);
|
|
6164
6419
|
}
|
|
6165
6420
|
await this.trackHookEvents(instance, testFrameworkState, hookState, args);
|
|
6166
|
-
|
|
6421
|
+
BStackLogger2.debug(`trackEvent: tracked instance data=${JSON.stringify(Object.fromEntries(instance.getAllData()))}`);
|
|
6167
6422
|
} catch (error) {
|
|
6168
|
-
|
|
6423
|
+
BStackLogger2.error(`trackEvent: Error in tracking events: ${error} hookState=${hookState} testFrameworkState=${testFrameworkState}`);
|
|
6169
6424
|
}
|
|
6170
6425
|
args.instance = instance;
|
|
6171
6426
|
await this.runHooks(instance, testFrameworkState, hookState, args);
|
|
@@ -6179,7 +6434,7 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6179
6434
|
*/
|
|
6180
6435
|
resolveInstance(testFrameworkState, hookState, args = {}) {
|
|
6181
6436
|
let instance = null;
|
|
6182
|
-
|
|
6437
|
+
BStackLogger2.info(`resolveInstance: resolving instance for testFrameworkState=${testFrameworkState} hookState=${hookState}`);
|
|
6183
6438
|
if (testFrameworkState === TestFrameworkState.INIT_TEST || testFrameworkState === TestFrameworkState.NONE) {
|
|
6184
6439
|
this.trackWdioMochaInstance(testFrameworkState, args);
|
|
6185
6440
|
}
|
|
@@ -6196,7 +6451,7 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6196
6451
|
const target = CLIUtils.getCurrentInstanceName();
|
|
6197
6452
|
const trackedContext = TrackedInstance.createContext(target);
|
|
6198
6453
|
let instance = null;
|
|
6199
|
-
|
|
6454
|
+
BStackLogger2.info(`trackWdioMochaInstance: created instance for target=${target}, state=${testFrameworkState}, args=${args}`);
|
|
6200
6455
|
instance = new TestFrameworkInstance(
|
|
6201
6456
|
trackedContext,
|
|
6202
6457
|
this.getTestFrameworks(),
|
|
@@ -6219,7 +6474,7 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6219
6474
|
process.env[TEST_ANALYTICS_ID] = instanceEntries[TestFrameworkConstants.KEY_TEST_UUID];
|
|
6220
6475
|
instance.updateMultipleEntries(instanceEntries);
|
|
6221
6476
|
TestFramework.setTrackedInstance(trackedContext, instance);
|
|
6222
|
-
|
|
6477
|
+
BStackLogger2.info(`trackWdioMochaInstance: saved instance contextId=${trackedContext.getId()} target=${target}`);
|
|
6223
6478
|
}
|
|
6224
6479
|
async getTestData(instance, test) {
|
|
6225
6480
|
const framework = TestFramework.getState(instance, TestFrameworkConstants.KEY_TEST_FRAMEWORK_NAME);
|
|
@@ -6230,8 +6485,8 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6230
6485
|
[TestFrameworkConstants.KEY_TEST_ID]: getUniqueIdentifier(test, framework),
|
|
6231
6486
|
[TestFrameworkConstants.KEY_TEST_NAME]: test.title || test.description,
|
|
6232
6487
|
[TestFrameworkConstants.KEY_TEST_CODE]: test.body || "",
|
|
6233
|
-
[TestFrameworkConstants.KEY_TEST_FILE_PATH]: gitConfig?.root && filename ?
|
|
6234
|
-
[TestFrameworkConstants.KEY_TEST_LOCATION]: filename ?
|
|
6488
|
+
[TestFrameworkConstants.KEY_TEST_FILE_PATH]: gitConfig?.root && filename ? path14.relative(gitConfig.root, filename) : void 0,
|
|
6489
|
+
[TestFrameworkConstants.KEY_TEST_LOCATION]: filename ? path14.relative(process.cwd(), filename) : void 0,
|
|
6235
6490
|
[TestFrameworkConstants.KEY_TEST_SCOPE]: fullTitle,
|
|
6236
6491
|
[TestFrameworkConstants.KEY_TEST_SCOPES]: getMochaTestHierarchy(test)
|
|
6237
6492
|
};
|
|
@@ -6284,7 +6539,7 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6284
6539
|
if (lastActiveHook) {
|
|
6285
6540
|
const hookLogs = lastActiveHook[TestFrameworkConstants.KEY_HOOK_LOGS];
|
|
6286
6541
|
hookLogs.push(logRecord);
|
|
6287
|
-
|
|
6542
|
+
BStackLogger2.debug(`hooks after update logs ${TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOKS_STARTED)} ${TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOKS_FINISHED)}`);
|
|
6288
6543
|
return;
|
|
6289
6544
|
}
|
|
6290
6545
|
const entries = TestFramework.getState(instance, TestFrameworkConstants.KEY_TEST_LOGS);
|
|
@@ -6385,15 +6640,15 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6385
6640
|
[TestFrameworkConstants.KEY_EVENT_STARTED_AT]: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6386
6641
|
[TestFrameworkConstants.KEY_HOOK_LOGS]: [],
|
|
6387
6642
|
[TestFrameworkConstants.KEY_HOOK_NAME]: test.title || test.description,
|
|
6388
|
-
[TestFrameworkConstants.KEY_TEST_FILE_PATH]: gitConfig?.root && filename ?
|
|
6389
|
-
[TestFrameworkConstants.KEY_TEST_LOCATION]: filename ?
|
|
6643
|
+
[TestFrameworkConstants.KEY_TEST_FILE_PATH]: gitConfig?.root && filename ? path14.relative(gitConfig.root, filename) : void 0,
|
|
6644
|
+
[TestFrameworkConstants.KEY_TEST_LOCATION]: filename ? path14.relative(process.cwd(), filename) : void 0
|
|
6390
6645
|
};
|
|
6391
6646
|
hooksStarted.get(key)?.push(hook);
|
|
6392
6647
|
updates[_WdioMochaTestFramework.KEY_HOOK_LAST_STARTED] = key;
|
|
6393
|
-
|
|
6648
|
+
BStackLogger2.info(`Hook Started in PRE key = ${key} & hook = ${JSON.stringify(hook)}`);
|
|
6394
6649
|
} else if (hookState === HookState.POST) {
|
|
6395
6650
|
const hooksList = hooksStarted.get(key) || [];
|
|
6396
|
-
|
|
6651
|
+
BStackLogger2.info(`Hook List in Post ${JSON.stringify(hooksList)}`);
|
|
6397
6652
|
if (hooksList.length > 0) {
|
|
6398
6653
|
const hook = hooksList.pop();
|
|
6399
6654
|
const result = testResult.status;
|
|
@@ -6406,7 +6661,7 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6406
6661
|
}
|
|
6407
6662
|
}
|
|
6408
6663
|
instance.updateMultipleEntries(updates);
|
|
6409
|
-
|
|
6664
|
+
BStackLogger2.info(`trackHookEvents: hook state=${key}.${hookState}, hooks started=${JSON.stringify(hooksStarted)}, hooks finished=${JSON.stringify(hooksFinished)}`);
|
|
6410
6665
|
}
|
|
6411
6666
|
};
|
|
6412
6667
|
}
|
|
@@ -6430,7 +6685,7 @@ var init_testHubModule = __esm({
|
|
|
6430
6685
|
init_automationFramework();
|
|
6431
6686
|
init_automationFrameworkConstants();
|
|
6432
6687
|
TestHubModule = class _TestHubModule extends BaseModule {
|
|
6433
|
-
logger =
|
|
6688
|
+
logger = BStackLogger2;
|
|
6434
6689
|
testhubConfig;
|
|
6435
6690
|
name;
|
|
6436
6691
|
static MODULE_NAME = "TestHubModule";
|
|
@@ -6703,11 +6958,11 @@ var init_wdioAutomationFramework = __esm({
|
|
|
6703
6958
|
* @param {*} args
|
|
6704
6959
|
*/
|
|
6705
6960
|
async trackEvent(automationFrameworkState, hookState, args = {}) {
|
|
6706
|
-
|
|
6961
|
+
BStackLogger2.info(`trackEvent: automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
|
|
6707
6962
|
await super.trackEvent(automationFrameworkState, hookState, args);
|
|
6708
6963
|
const instance = this.resolveInstance(automationFrameworkState, hookState, args);
|
|
6709
6964
|
if (instance === null) {
|
|
6710
|
-
|
|
6965
|
+
BStackLogger2.error(`trackEvent: instance not found for automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
|
|
6711
6966
|
return;
|
|
6712
6967
|
}
|
|
6713
6968
|
args.instance = instance;
|
|
@@ -6722,7 +6977,7 @@ var init_wdioAutomationFramework = __esm({
|
|
|
6722
6977
|
*/
|
|
6723
6978
|
resolveInstance(automationFrameworkState, hookState, args = {}) {
|
|
6724
6979
|
let instance = null;
|
|
6725
|
-
|
|
6980
|
+
BStackLogger2.info(`resolveInstance: resolving instance for automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
|
|
6726
6981
|
if (automationFrameworkState === AutomationFrameworkState.CREATE || automationFrameworkState === AutomationFrameworkState.NONE) {
|
|
6727
6982
|
this.trackWebdriverIOInstance(automationFrameworkState, args);
|
|
6728
6983
|
}
|
|
@@ -6738,13 +6993,13 @@ var init_wdioAutomationFramework = __esm({
|
|
|
6738
6993
|
// !args.browser &&
|
|
6739
6994
|
AutomationFramework.getTrackedInstance()
|
|
6740
6995
|
) {
|
|
6741
|
-
|
|
6996
|
+
BStackLogger2.info("trackWebdriverIOInstance: instance already exists");
|
|
6742
6997
|
return;
|
|
6743
6998
|
}
|
|
6744
6999
|
const target = CLIUtils.getCurrentInstanceName();
|
|
6745
7000
|
const trackedContext = TrackedInstance.createContext(target);
|
|
6746
7001
|
let instance = null;
|
|
6747
|
-
|
|
7002
|
+
BStackLogger2.info(`trackWebdriverIOInstance: created instance for target=${target}, state=${automationFrameworkState}, args=${args}`);
|
|
6748
7003
|
instance = new AutomationFrameworkInstance(
|
|
6749
7004
|
trackedContext,
|
|
6750
7005
|
this.getAutomationFrameworkName(),
|
|
@@ -6752,7 +7007,7 @@ var init_wdioAutomationFramework = __esm({
|
|
|
6752
7007
|
automationFrameworkState
|
|
6753
7008
|
);
|
|
6754
7009
|
AutomationFramework.setTrackedInstance(trackedContext, instance);
|
|
6755
|
-
|
|
7010
|
+
BStackLogger2.info(`trackWebdriverIOInstance: saved instance contextId=${trackedContext.getId()} target=${target}`);
|
|
6756
7011
|
}
|
|
6757
7012
|
};
|
|
6758
7013
|
}
|
|
@@ -6778,7 +7033,7 @@ var init_webdriverIOModule = __esm({
|
|
|
6778
7033
|
browserVersion;
|
|
6779
7034
|
platforms;
|
|
6780
7035
|
testRunId;
|
|
6781
|
-
logger =
|
|
7036
|
+
logger = BStackLogger2;
|
|
6782
7037
|
static MODULE_NAME = "WebdriverIOModule";
|
|
6783
7038
|
/**
|
|
6784
7039
|
* Create a new WebdriverIOModule
|
|
@@ -6906,7 +7161,7 @@ var init_accessibilityModule = __esm({
|
|
|
6906
7161
|
init_constants2();
|
|
6907
7162
|
init_grpcClient();
|
|
6908
7163
|
AccessibilityModule = class extends BaseModule {
|
|
6909
|
-
logger =
|
|
7164
|
+
logger = BStackLogger2;
|
|
6910
7165
|
name;
|
|
6911
7166
|
scriptInstance;
|
|
6912
7167
|
accessibility = false;
|
|
@@ -7190,7 +7445,7 @@ var init_accessibilityModule = __esm({
|
|
|
7190
7445
|
formatString(this.scriptInstance.performScan, JSON.stringify(_getParamsForAppAccessibility(commandName, testName))),
|
|
7191
7446
|
{}
|
|
7192
7447
|
);
|
|
7193
|
-
|
|
7448
|
+
BStackLogger2.debug(util9.format(results2));
|
|
7194
7449
|
return results2;
|
|
7195
7450
|
}
|
|
7196
7451
|
const results = await browser.executeAsync(
|
|
@@ -7313,7 +7568,7 @@ var init_observabilityModule = __esm({
|
|
|
7313
7568
|
init_cliLogger();
|
|
7314
7569
|
init_util();
|
|
7315
7570
|
ObservabilityModule = class _ObservabilityModule extends BaseModule {
|
|
7316
|
-
logger =
|
|
7571
|
+
logger = BStackLogger2;
|
|
7317
7572
|
observabilityConfig;
|
|
7318
7573
|
name;
|
|
7319
7574
|
static MODULE_NAME = "ObservabilityModule";
|
|
@@ -7416,22 +7671,22 @@ var init_request_handler = __esm({
|
|
|
7416
7671
|
throw new Error("Test Reporting and Analytics build start not completed yet.");
|
|
7417
7672
|
}
|
|
7418
7673
|
this.queue.push(event);
|
|
7419
|
-
|
|
7674
|
+
BStackLogger.debug(`Added data to request queue. Queue length = ${this.queue.length}`);
|
|
7420
7675
|
const shouldProceed = this.shouldProceed();
|
|
7421
7676
|
if (shouldProceed) {
|
|
7422
7677
|
this.sendBatch().catch((e) => {
|
|
7423
|
-
|
|
7678
|
+
BStackLogger.debug("Exception in sending batch: " + e);
|
|
7424
7679
|
});
|
|
7425
7680
|
}
|
|
7426
7681
|
}
|
|
7427
7682
|
async shutdown() {
|
|
7428
|
-
|
|
7683
|
+
BStackLogger.debug("shutdown started");
|
|
7429
7684
|
this.removeEventBatchPolling("Shutting down");
|
|
7430
7685
|
while (this.queue.length > 0) {
|
|
7431
7686
|
const data = this.queue.splice(0, DATA_BATCH_SIZE);
|
|
7432
7687
|
await this.callCallback(data, "SHUTDOWN_QUEUE");
|
|
7433
7688
|
}
|
|
7434
|
-
|
|
7689
|
+
BStackLogger.debug("shutdown ended");
|
|
7435
7690
|
}
|
|
7436
7691
|
startEventBatchPolling() {
|
|
7437
7692
|
this.pollEventBatchInterval = setInterval(this.sendBatch.bind(this), DATA_BATCH_INTERVAL);
|
|
@@ -7441,11 +7696,11 @@ var init_request_handler = __esm({
|
|
|
7441
7696
|
if (data.length === 0) {
|
|
7442
7697
|
return;
|
|
7443
7698
|
}
|
|
7444
|
-
|
|
7699
|
+
BStackLogger.debug(`Sending data from request queue. Data length = ${data.length}, Queue length after removal = ${this.queue.length}`);
|
|
7445
7700
|
await this.callCallback(data, "INTERVAL_QUEUE");
|
|
7446
7701
|
}
|
|
7447
7702
|
callCallback = async (data, kind) => {
|
|
7448
|
-
|
|
7703
|
+
BStackLogger.debug("calling callback with kind " + kind);
|
|
7449
7704
|
await this.callback?.(data);
|
|
7450
7705
|
};
|
|
7451
7706
|
resetEventBatchPolling() {
|
|
@@ -7454,13 +7709,13 @@ var init_request_handler = __esm({
|
|
|
7454
7709
|
}
|
|
7455
7710
|
removeEventBatchPolling(tag) {
|
|
7456
7711
|
if (this.pollEventBatchInterval) {
|
|
7457
|
-
|
|
7712
|
+
BStackLogger.debug(`${tag} request queue`);
|
|
7458
7713
|
clearInterval(this.pollEventBatchInterval);
|
|
7459
7714
|
}
|
|
7460
7715
|
}
|
|
7461
7716
|
shouldProceed() {
|
|
7462
7717
|
if (_RequestQueueHandler.tearDownInvoked) {
|
|
7463
|
-
|
|
7718
|
+
BStackLogger.debug("Force request-queue shutdown, as test run event is received after teardown");
|
|
7464
7719
|
return true;
|
|
7465
7720
|
}
|
|
7466
7721
|
return this.queue.length >= DATA_BATCH_SIZE;
|
|
@@ -7483,7 +7738,7 @@ async function uploadEventData(eventData, eventUrl = DATA_EVENT_ENDPOINT) {
|
|
|
7483
7738
|
throw new Error("Build start not completed yet");
|
|
7484
7739
|
}
|
|
7485
7740
|
if (!process.env[BROWSERSTACK_TESTHUB_JWT]) {
|
|
7486
|
-
|
|
7741
|
+
BStackLogger.debug(`[${logTag}] Missing Authentication Token/ Build ID`);
|
|
7487
7742
|
throw new Error("Token/buildID is undefined, build creation might have failed");
|
|
7488
7743
|
}
|
|
7489
7744
|
try {
|
|
@@ -7496,9 +7751,9 @@ async function uploadEventData(eventData, eventUrl = DATA_EVENT_ENDPOINT) {
|
|
|
7496
7751
|
},
|
|
7497
7752
|
body: JSON.stringify(eventData)
|
|
7498
7753
|
});
|
|
7499
|
-
|
|
7754
|
+
BStackLogger.debug(`[${logTag}] Success response: ${JSON.stringify(await data.json())}`);
|
|
7500
7755
|
} catch (error) {
|
|
7501
|
-
|
|
7756
|
+
BStackLogger.debug(`[${logTag}] Failed. Error: ${format3(error)}`);
|
|
7502
7757
|
throw error;
|
|
7503
7758
|
}
|
|
7504
7759
|
}
|
|
@@ -7561,7 +7816,7 @@ var init_listener = __esm({
|
|
|
7561
7816
|
await this.uploadPending();
|
|
7562
7817
|
await this.teardown();
|
|
7563
7818
|
} catch (e) {
|
|
7564
|
-
|
|
7819
|
+
BStackLogger.debug("Exception in onWorkerEnd: " + e);
|
|
7565
7820
|
}
|
|
7566
7821
|
}
|
|
7567
7822
|
async uploadPending(waitTimeout = DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS, waitInterval = DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS) {
|
|
@@ -7572,10 +7827,10 @@ var init_listener = __esm({
|
|
|
7572
7827
|
return this.uploadPending(waitTimeout - waitInterval);
|
|
7573
7828
|
}
|
|
7574
7829
|
async teardown() {
|
|
7575
|
-
|
|
7830
|
+
BStackLogger.debug("teardown started");
|
|
7576
7831
|
RequestQueueHandler.tearDownInvoked = true;
|
|
7577
7832
|
await this.requestBatcher?.shutdown();
|
|
7578
|
-
|
|
7833
|
+
BStackLogger.debug("teardown ended");
|
|
7579
7834
|
}
|
|
7580
7835
|
hookStarted(hookData) {
|
|
7581
7836
|
try {
|
|
@@ -7683,7 +7938,7 @@ var init_listener = __esm({
|
|
|
7683
7938
|
}
|
|
7684
7939
|
markLogs(status, data) {
|
|
7685
7940
|
if (!data) {
|
|
7686
|
-
|
|
7941
|
+
BStackLogger.debug("No log data");
|
|
7687
7942
|
return;
|
|
7688
7943
|
}
|
|
7689
7944
|
try {
|
|
@@ -7692,7 +7947,7 @@ var init_listener = __esm({
|
|
|
7692
7947
|
this.logEvents.mark(status, LOG_KIND_USAGE_MAP[kind] || kind);
|
|
7693
7948
|
}
|
|
7694
7949
|
} catch (e) {
|
|
7695
|
-
|
|
7950
|
+
BStackLogger.debug("Exception in marking logs status " + e);
|
|
7696
7951
|
throw e;
|
|
7697
7952
|
}
|
|
7698
7953
|
}
|
|
@@ -7710,14 +7965,14 @@ var init_listener = __esm({
|
|
|
7710
7965
|
}
|
|
7711
7966
|
if (!this.requestBatcher) {
|
|
7712
7967
|
this.requestBatcher = RequestQueueHandler.getInstance(async (data) => {
|
|
7713
|
-
|
|
7968
|
+
BStackLogger.debug("callback: called with events " + data.length);
|
|
7714
7969
|
try {
|
|
7715
7970
|
this.pendingUploads += 1;
|
|
7716
7971
|
await batchAndPostEvents(DATA_BATCH_ENDPOINT, "BATCH_DATA", data);
|
|
7717
|
-
|
|
7972
|
+
BStackLogger.debug("callback: marking events success " + data.length);
|
|
7718
7973
|
this.eventsSuccess(data);
|
|
7719
7974
|
} catch {
|
|
7720
|
-
|
|
7975
|
+
BStackLogger.debug("callback: marking events failed " + data.length);
|
|
7721
7976
|
this.eventsFailed(data);
|
|
7722
7977
|
} finally {
|
|
7723
7978
|
this.pendingUploads -= 1;
|
|
@@ -7774,7 +8029,7 @@ var init_listener = __esm({
|
|
|
7774
8029
|
});
|
|
7775
8030
|
|
|
7776
8031
|
// src/reporter.ts
|
|
7777
|
-
import
|
|
8032
|
+
import path15 from "node:path";
|
|
7778
8033
|
import WDIOReporter from "@wdio/reporter";
|
|
7779
8034
|
import * as url from "node:url";
|
|
7780
8035
|
import { v4 as uuidv43 } from "uuid";
|
|
@@ -7867,7 +8122,7 @@ var init_reporter = __esm({
|
|
|
7867
8122
|
filename = this._suiteName || suiteStats.file;
|
|
7868
8123
|
}
|
|
7869
8124
|
} catch {
|
|
7870
|
-
|
|
8125
|
+
BStackLogger.debug("Error in decoding file name of suite");
|
|
7871
8126
|
}
|
|
7872
8127
|
}
|
|
7873
8128
|
this._suiteName = filename;
|
|
@@ -7997,9 +8252,9 @@ var init_reporter = __esm({
|
|
|
7997
8252
|
scope,
|
|
7998
8253
|
scopes,
|
|
7999
8254
|
identifier,
|
|
8000
|
-
file_name: suiteFileName ?
|
|
8001
|
-
location: suiteFileName ?
|
|
8002
|
-
vc_filepath: this._gitConfigPath && suiteFileName ?
|
|
8255
|
+
file_name: suiteFileName ? path15.relative(process.cwd(), suiteFileName) : void 0,
|
|
8256
|
+
location: suiteFileName ? path15.relative(process.cwd(), suiteFileName) : void 0,
|
|
8257
|
+
vc_filepath: this._gitConfigPath && suiteFileName ? path15.relative(this._gitConfigPath, suiteFileName) : void 0,
|
|
8003
8258
|
started_at: testStats.start && testStats.start.toISOString(),
|
|
8004
8259
|
finished_at: testStats.end && testStats.end.toISOString(),
|
|
8005
8260
|
framework,
|
|
@@ -8012,13 +8267,15 @@ var init_reporter = __esm({
|
|
|
8012
8267
|
if (eventType.startsWith("TestRun") || eventType === "HookRunStarted") {
|
|
8013
8268
|
const cloudProvider = getCloudProvider({ options: { hostname: this._config?.hostname } });
|
|
8014
8269
|
testData.integrations = {};
|
|
8270
|
+
const liveBrowserCaps = globalThis?.browser?.capabilities;
|
|
8015
8271
|
testData.integrations[cloudProvider] = {
|
|
8016
8272
|
capabilities: this._capabilities,
|
|
8017
8273
|
session_id: this._sessionId,
|
|
8018
8274
|
browser: this._capabilities?.browserName,
|
|
8019
8275
|
browser_version: this._capabilities?.browserVersion,
|
|
8020
8276
|
platform: this._capabilities?.platformName,
|
|
8021
|
-
platform_version: getPlatformVersion(this._capabilities, this._userCaps)
|
|
8277
|
+
platform_version: getPlatformVersion(this._capabilities, this._userCaps),
|
|
8278
|
+
device: getResolvedDeviceName(liveBrowserCaps, this._userCaps)
|
|
8022
8279
|
};
|
|
8023
8280
|
}
|
|
8024
8281
|
if (eventType === "TestRunFinished" || eventType === "HookRunFinished") {
|
|
@@ -8048,7 +8305,7 @@ var init_reporter = __esm({
|
|
|
8048
8305
|
});
|
|
8049
8306
|
|
|
8050
8307
|
// src/insights-handler.ts
|
|
8051
|
-
import
|
|
8308
|
+
import path16 from "node:path";
|
|
8052
8309
|
import { v4 as uuidv44 } from "uuid";
|
|
8053
8310
|
var _InsightsHandler, InsightsHandler, insights_handler_default;
|
|
8054
8311
|
var init_insights_handler = __esm({
|
|
@@ -8082,6 +8339,8 @@ var init_insights_handler = __esm({
|
|
|
8082
8339
|
};
|
|
8083
8340
|
this.registerListeners();
|
|
8084
8341
|
}
|
|
8342
|
+
_browser;
|
|
8343
|
+
_framework;
|
|
8085
8344
|
_tests = {};
|
|
8086
8345
|
_hooks = {};
|
|
8087
8346
|
_platformMeta;
|
|
@@ -8328,9 +8587,9 @@ var init_insights_handler = __esm({
|
|
|
8328
8587
|
test_run_id: hookData.testRunId,
|
|
8329
8588
|
scope: feature?.name,
|
|
8330
8589
|
scopes: [feature?.name || ""],
|
|
8331
|
-
file_name: uri ?
|
|
8332
|
-
location: uri ?
|
|
8333
|
-
vc_filepath: this._gitConfigPath && uri ?
|
|
8590
|
+
file_name: uri ? path16.relative(process.cwd(), uri) : void 0,
|
|
8591
|
+
location: uri ? path16.relative(process.cwd(), uri) : void 0,
|
|
8592
|
+
vc_filepath: this._gitConfigPath && uri ? path16.relative(this._gitConfigPath, uri) : void 0,
|
|
8334
8593
|
result: "pending",
|
|
8335
8594
|
framework: this._framework
|
|
8336
8595
|
};
|
|
@@ -8495,7 +8754,7 @@ var init_insights_handler = __esm({
|
|
|
8495
8754
|
this.listener.logCreated([stdLog]);
|
|
8496
8755
|
}
|
|
8497
8756
|
} catch (error) {
|
|
8498
|
-
|
|
8757
|
+
BStackLogger.debug(`Exception in uploading log data to Test Reporting and Analytics with error : ${error}`);
|
|
8499
8758
|
}
|
|
8500
8759
|
};
|
|
8501
8760
|
async browserCommand(commandType, args, test) {
|
|
@@ -8628,9 +8887,9 @@ var init_insights_handler = __esm({
|
|
|
8628
8887
|
scope: fullTitle,
|
|
8629
8888
|
scopes: this.getHierarchy(test),
|
|
8630
8889
|
identifier: fullTitle,
|
|
8631
|
-
file_name: filename ?
|
|
8632
|
-
location: filename ?
|
|
8633
|
-
vc_filepath: this._gitConfigPath && filename ?
|
|
8890
|
+
file_name: filename ? path16.relative(process.cwd(), filename) : void 0,
|
|
8891
|
+
location: filename ? path16.relative(process.cwd(), filename) : void 0,
|
|
8892
|
+
vc_filepath: this._gitConfigPath && filename ? path16.relative(this._gitConfigPath, filename) : void 0,
|
|
8634
8893
|
started_at: testMetaData.startedAt,
|
|
8635
8894
|
finished_at: testMetaData.finishedAt,
|
|
8636
8895
|
result: "pending",
|
|
@@ -8740,9 +8999,9 @@ var init_insights_handler = __esm({
|
|
|
8740
8999
|
scope: fullNameWithExamples,
|
|
8741
9000
|
scopes: [feature?.name || ""],
|
|
8742
9001
|
identifier: scenario?.name,
|
|
8743
|
-
file_name: feature && feature.path ?
|
|
8744
|
-
location: feature && feature.path ?
|
|
8745
|
-
vc_filepath: this._gitConfigPath && feature?.path ?
|
|
9002
|
+
file_name: feature && feature.path ? path16.relative(process.cwd(), feature.path) : void 0,
|
|
9003
|
+
location: feature && feature.path ? path16.relative(process.cwd(), feature.path) : void 0,
|
|
9004
|
+
vc_filepath: this._gitConfigPath && feature?.path ? path16.relative(this._gitConfigPath, feature?.path) : void 0,
|
|
8746
9005
|
framework: this._framework,
|
|
8747
9006
|
result: "pending",
|
|
8748
9007
|
meta: {
|
|
@@ -8795,7 +9054,7 @@ var init_insights_handler = __esm({
|
|
|
8795
9054
|
return testData;
|
|
8796
9055
|
}
|
|
8797
9056
|
async flushCBTDataQueue() {
|
|
8798
|
-
|
|
9057
|
+
BStackLogger.debug(`Flushing CBT Data Queue ${this.currentTestId}`);
|
|
8799
9058
|
if (isUndefined(this.currentTestId)) {
|
|
8800
9059
|
return;
|
|
8801
9060
|
}
|
|
@@ -8815,7 +9074,7 @@ var init_insights_handler = __esm({
|
|
|
8815
9074
|
uuid: "",
|
|
8816
9075
|
integrations: integrationsData
|
|
8817
9076
|
};
|
|
8818
|
-
|
|
9077
|
+
BStackLogger.debug(`Sending CBT Data ${this.currentTestId} ${JSON.stringify(cbtData)}`);
|
|
8819
9078
|
if (this.currentTestId !== void 0) {
|
|
8820
9079
|
cbtData.uuid = this.currentTestId;
|
|
8821
9080
|
this.listener.cbtSessionCreated(cbtData);
|
|
@@ -8826,8 +9085,8 @@ var init_insights_handler = __esm({
|
|
|
8826
9085
|
getIntegrationsObject() {
|
|
8827
9086
|
const caps = this._browser?.capabilities;
|
|
8828
9087
|
const sessionId = this._browser?.sessionId;
|
|
8829
|
-
|
|
8830
|
-
|
|
9088
|
+
BStackLogger.debug(`Driver capabilities used for integration object: ${JSON.stringify(caps)}`);
|
|
9089
|
+
BStackLogger.debug(`User capabilities used for integration object: ${JSON.stringify(this._userCaps)}`);
|
|
8831
9090
|
return {
|
|
8832
9091
|
capabilities: caps,
|
|
8833
9092
|
session_id: sessionId,
|
|
@@ -8835,7 +9094,8 @@ var init_insights_handler = __esm({
|
|
|
8835
9094
|
browser_version: caps?.browserVersion,
|
|
8836
9095
|
platform: caps?.platformName,
|
|
8837
9096
|
product: this._platformMeta?.product,
|
|
8838
|
-
platform_version: getPlatformVersion(caps, this._userCaps)
|
|
9097
|
+
platform_version: getPlatformVersion(caps, this._userCaps),
|
|
9098
|
+
device: getResolvedDeviceName(caps, this._userCaps)
|
|
8839
9099
|
};
|
|
8840
9100
|
}
|
|
8841
9101
|
getIdentifier(test) {
|
|
@@ -8989,6 +9249,11 @@ var init_Percy_Handler = __esm({
|
|
|
8989
9249
|
this._percyAutoCaptureMode = "auto";
|
|
8990
9250
|
}
|
|
8991
9251
|
}
|
|
9252
|
+
_percyAutoCaptureMode;
|
|
9253
|
+
_browser;
|
|
9254
|
+
_capabilities;
|
|
9255
|
+
_isAppAutomate;
|
|
9256
|
+
_framework;
|
|
8992
9257
|
_sessionName;
|
|
8993
9258
|
_isPercyCleanupProcessingUnderway = false;
|
|
8994
9259
|
_percyScreenshotCounter = 0;
|
|
@@ -9128,7 +9393,7 @@ var init_percyModule = __esm({
|
|
|
9128
9393
|
init_Percy_Handler();
|
|
9129
9394
|
init_testFrameworkConstants();
|
|
9130
9395
|
PercyModule = class _PercyModule extends BaseModule {
|
|
9131
|
-
logger =
|
|
9396
|
+
logger = BStackLogger2;
|
|
9132
9397
|
browser;
|
|
9133
9398
|
static MODULE_NAME = "PercyModule";
|
|
9134
9399
|
percyHandler;
|
|
@@ -9249,7 +9514,7 @@ var init_cli = __esm({
|
|
|
9249
9514
|
cliParams = null;
|
|
9250
9515
|
automationFramework = null;
|
|
9251
9516
|
SDK_CLI_BIN_PATH = null;
|
|
9252
|
-
logger =
|
|
9517
|
+
logger = BStackLogger2;
|
|
9253
9518
|
options;
|
|
9254
9519
|
constructor() {
|
|
9255
9520
|
this.initialized = false;
|
|
@@ -9308,7 +9573,7 @@ var init_cli = __esm({
|
|
|
9308
9573
|
const response = await GrpcClient.getInstance().startBinSession(this.wdioConfig);
|
|
9309
9574
|
const redactedStartResponse = JSON.parse(JSON.stringify(response));
|
|
9310
9575
|
CrashReporter.recursivelyRedactKeysFromObject(redactedStartResponse, ["user", "username", "key", "accesskey", "password"]);
|
|
9311
|
-
|
|
9576
|
+
BStackLogger2.debug(`start: startBinSession response=${JSON.stringify(redactedStartResponse)}`);
|
|
9312
9577
|
this.loadModules(response);
|
|
9313
9578
|
this.isMainConnected = true;
|
|
9314
9579
|
}
|
|
@@ -9320,6 +9585,7 @@ var init_cli = __esm({
|
|
|
9320
9585
|
this.binSessionId = startBinResponse.binSessionId;
|
|
9321
9586
|
this.logger.info(`loadModules: binSessionId=${this.binSessionId}`);
|
|
9322
9587
|
this.setConfig(startBinResponse);
|
|
9588
|
+
this.logBuildErrors(startBinResponse);
|
|
9323
9589
|
APIUtils.updateURLSForGRR(this.config.apis);
|
|
9324
9590
|
this.setupTestFramework();
|
|
9325
9591
|
this.setupAutomationFramework();
|
|
@@ -9341,17 +9607,6 @@ var init_cli = __esm({
|
|
|
9341
9607
|
}
|
|
9342
9608
|
this.modules[ObservabilityModule.MODULE_NAME] = new ObservabilityModule(startBinResponse.observability);
|
|
9343
9609
|
}
|
|
9344
|
-
if (startBinResponse.testhub.errors && startBinResponse.testhub.errors.length > 0) {
|
|
9345
|
-
try {
|
|
9346
|
-
const errors = JSON.parse(Buffer.from(startBinResponse.testhub.errors).toString());
|
|
9347
|
-
for (const [code, detail] of Object.entries(errors)) {
|
|
9348
|
-
const { message } = detail;
|
|
9349
|
-
BStackLogger.error(`[Build] ${code}: ${message}`);
|
|
9350
|
-
}
|
|
9351
|
-
} catch (e) {
|
|
9352
|
-
BStackLogger.debug(`Failed to parse testhub errors: ${e}`);
|
|
9353
|
-
}
|
|
9354
|
-
}
|
|
9355
9610
|
this.modules[TestHubModule.MODULE_NAME] = new TestHubModule(startBinResponse.testhub);
|
|
9356
9611
|
if (startBinResponse.accessibility?.success) {
|
|
9357
9612
|
process.env[BROWSERSTACK_ACCESSIBILITY] = "true";
|
|
@@ -9366,6 +9621,28 @@ var init_cli = __esm({
|
|
|
9366
9621
|
}
|
|
9367
9622
|
this.configureModules();
|
|
9368
9623
|
}
|
|
9624
|
+
/**
|
|
9625
|
+
* Log any build errors the binary reported via testhub.errors. The
|
|
9626
|
+
* field is a JSON-encoded { [errorKey]: { message, type } } map. Called
|
|
9627
|
+
* early in loadModules so the user sees the actionable cause (e.g.
|
|
9628
|
+
* invalid credentials) before any downstream bootstrap step that
|
|
9629
|
+
* depends on a fully populated config.
|
|
9630
|
+
*/
|
|
9631
|
+
logBuildErrors(startBinResponse) {
|
|
9632
|
+
const rawErrors = startBinResponse.testhub?.errors;
|
|
9633
|
+
if (!rawErrors || !rawErrors.length) {
|
|
9634
|
+
return;
|
|
9635
|
+
}
|
|
9636
|
+
try {
|
|
9637
|
+
const errors = JSON.parse(Buffer.from(rawErrors).toString());
|
|
9638
|
+
for (const [code, detail] of Object.entries(errors)) {
|
|
9639
|
+
const { message } = detail;
|
|
9640
|
+
BStackLogger2.error(`[Build] ${code}: ${message}`);
|
|
9641
|
+
}
|
|
9642
|
+
} catch (e) {
|
|
9643
|
+
BStackLogger2.debug(`Failed to parse testhub errors: ${e}`);
|
|
9644
|
+
}
|
|
9645
|
+
}
|
|
9369
9646
|
/**
|
|
9370
9647
|
* Configure modules
|
|
9371
9648
|
* @returns {Promise<void>}
|
|
@@ -9490,7 +9767,7 @@ var init_cli = __esm({
|
|
|
9490
9767
|
try {
|
|
9491
9768
|
if (this.isMainConnected) {
|
|
9492
9769
|
const response = await GrpcClient.getInstance().stopBinSession();
|
|
9493
|
-
|
|
9770
|
+
BStackLogger2.debug(`stop: stopBinSession response=${JSON.stringify(response)}`);
|
|
9494
9771
|
}
|
|
9495
9772
|
await this.unConfigureModules();
|
|
9496
9773
|
if (this.process && this.process.pid) {
|
|
@@ -9672,8 +9949,8 @@ var init_cli = __esm({
|
|
|
9672
9949
|
});
|
|
9673
9950
|
|
|
9674
9951
|
// src/testorchestration/helpers.ts
|
|
9675
|
-
import
|
|
9676
|
-
import
|
|
9952
|
+
import os6 from "node:os";
|
|
9953
|
+
import path19 from "node:path";
|
|
9677
9954
|
import { spawnSync } from "node:child_process";
|
|
9678
9955
|
import logger4 from "@wdio/logger";
|
|
9679
9956
|
function isValidGitRef(ref) {
|
|
@@ -9699,11 +9976,11 @@ function safeGitCommand(args, cwd) {
|
|
|
9699
9976
|
}
|
|
9700
9977
|
function getHostInfo() {
|
|
9701
9978
|
return {
|
|
9702
|
-
hostname:
|
|
9979
|
+
hostname: os6.hostname(),
|
|
9703
9980
|
platform: process.platform,
|
|
9704
9981
|
architecture: process.arch,
|
|
9705
|
-
release:
|
|
9706
|
-
username:
|
|
9982
|
+
release: os6.release(),
|
|
9983
|
+
username: os6.userInfo().username
|
|
9707
9984
|
};
|
|
9708
9985
|
}
|
|
9709
9986
|
function isValidGitResult(result) {
|
|
@@ -9794,7 +10071,7 @@ function getGitMetadataForAISelection(folders = []) {
|
|
|
9794
10071
|
if (folders === null) {
|
|
9795
10072
|
folders = [process.cwd()];
|
|
9796
10073
|
}
|
|
9797
|
-
const uniqueFolders = [...new Set(folders.map((f) =>
|
|
10074
|
+
const uniqueFolders = [...new Set(folders.map((f) => path19.resolve(f)))];
|
|
9798
10075
|
log4.debug(`Processing ${uniqueFolders.length} unique folders out of ${folders.length} total`);
|
|
9799
10076
|
const results = [];
|
|
9800
10077
|
for (const folder of uniqueFolders) {
|
|
@@ -9951,14 +10228,14 @@ var init_request_utils = __esm({
|
|
|
9951
10228
|
* Makes a request to the test orchestration split tests endpoint
|
|
9952
10229
|
*/
|
|
9953
10230
|
static async testOrchestrationSplitTests(reqEndpoint, data) {
|
|
9954
|
-
|
|
10231
|
+
BStackLogger.debug("Processing Request for testOrchestrationSplitTests");
|
|
9955
10232
|
return _RequestUtils.makeOrchestrationRequest("POST", reqEndpoint, { data });
|
|
9956
10233
|
}
|
|
9957
10234
|
/**
|
|
9958
10235
|
* Gets ordered tests from the test orchestration
|
|
9959
10236
|
*/
|
|
9960
10237
|
static async getTestOrchestrationOrderedTests(reqEndpoint) {
|
|
9961
|
-
|
|
10238
|
+
BStackLogger.debug("Processing Request for getTestOrchestrationOrderedTests");
|
|
9962
10239
|
return _RequestUtils.makeOrchestrationRequest("GET", reqEndpoint, {});
|
|
9963
10240
|
}
|
|
9964
10241
|
/**
|
|
@@ -9995,13 +10272,13 @@ var init_request_utils = __esm({
|
|
|
9995
10272
|
throw new Error(`Unsupported HTTP method: ${method}`);
|
|
9996
10273
|
}
|
|
9997
10274
|
const response = await fetchWrap(urlObject.toString(), requestInit);
|
|
9998
|
-
|
|
10275
|
+
BStackLogger.debug(`Orchestration request made to URL: ${urlObject.toString()} with method: ${method}`);
|
|
9999
10276
|
const rawBody = await response.text();
|
|
10000
10277
|
let responseObj = rawBody;
|
|
10001
10278
|
try {
|
|
10002
10279
|
responseObj = rawBody ? JSON.parse(rawBody) : {};
|
|
10003
10280
|
} catch (error) {
|
|
10004
|
-
|
|
10281
|
+
BStackLogger.debug(`Failed to parse JSON response: ${error} - ${rawBody}`);
|
|
10005
10282
|
}
|
|
10006
10283
|
if (responseObj && typeof responseObj === "object" && !Array.isArray(responseObj)) {
|
|
10007
10284
|
return {
|
|
@@ -10012,7 +10289,7 @@ var init_request_utils = __esm({
|
|
|
10012
10289
|
}
|
|
10013
10290
|
return typeof responseObj === "string" ? responseObj : rawBody;
|
|
10014
10291
|
} catch (error) {
|
|
10015
|
-
|
|
10292
|
+
BStackLogger.error(`Orchestration request failed: ${error} - ${url3}`);
|
|
10016
10293
|
return null;
|
|
10017
10294
|
}
|
|
10018
10295
|
}
|
|
@@ -10021,7 +10298,7 @@ var init_request_utils = __esm({
|
|
|
10021
10298
|
});
|
|
10022
10299
|
|
|
10023
10300
|
// src/testorchestration/test-ordering-server.ts
|
|
10024
|
-
import
|
|
10301
|
+
import path20 from "node:path";
|
|
10025
10302
|
function isSplitTestsResponse(value) {
|
|
10026
10303
|
return typeof value === "object" && value !== null;
|
|
10027
10304
|
}
|
|
@@ -10055,7 +10332,7 @@ var init_test_ordering_server = __esm({
|
|
|
10055
10332
|
* Initiates the split tests request and stores the response data for polling.
|
|
10056
10333
|
*/
|
|
10057
10334
|
async splitTests(testFiles, orchestrationStrategy, orchestrationMetadata = "{}") {
|
|
10058
|
-
|
|
10335
|
+
BStackLogger.debug(`[splitTests] Initiating split tests with strategy: ${orchestrationStrategy}`);
|
|
10059
10336
|
try {
|
|
10060
10337
|
let prDetails = [];
|
|
10061
10338
|
const parsedMetadata = JSON.parse(orchestrationMetadata);
|
|
@@ -10065,7 +10342,7 @@ var init_test_ordering_server = __esm({
|
|
|
10065
10342
|
const multiRepoSource = parsedMetadata.run_smart_selection?.source;
|
|
10066
10343
|
prDetails = getGitMetadataForAISelection(multiRepoSource);
|
|
10067
10344
|
}
|
|
10068
|
-
|
|
10345
|
+
BStackLogger.debug(`PR Details for AI Selection: ${JSON.stringify(prDetails)}`);
|
|
10069
10346
|
const payload = {
|
|
10070
10347
|
tests: testFiles.map((f) => ({ filePath: f })),
|
|
10071
10348
|
orchestrationStrategy,
|
|
@@ -10073,23 +10350,23 @@ var init_test_ordering_server = __esm({
|
|
|
10073
10350
|
nodeIndex: parseInt(process.env.BROWSERSTACK_NODE_INDEX || "0"),
|
|
10074
10351
|
totalNodes: parseInt(process.env.BROWSERSTACK_TOTAL_NODE_COUNT || "1"),
|
|
10075
10352
|
projectName: this.config.testObservabilityOptions?.projectName || "",
|
|
10076
|
-
buildName: this.config.testObservabilityOptions?.buildName ||
|
|
10353
|
+
buildName: this.config.testObservabilityOptions?.buildName || path20.basename(process.cwd()),
|
|
10077
10354
|
buildRunIdentifier: process.env.BROWSERSTACK_BUILD_RUN_IDENTIFIER || "",
|
|
10078
10355
|
hostInfo: getHostInfo(),
|
|
10079
10356
|
prDetails
|
|
10080
10357
|
};
|
|
10081
|
-
|
|
10358
|
+
BStackLogger.info(`[splitTests] Split tests payload: ${JSON.stringify(payload)}`);
|
|
10082
10359
|
const response = await RequestUtils.testOrchestrationSplitTests(this.ORDERING_ENDPOINT, payload);
|
|
10083
10360
|
if (isSplitTestsResponse(response)) {
|
|
10084
10361
|
this.requestData = this._processSplitTestsResponse(response);
|
|
10085
|
-
|
|
10362
|
+
BStackLogger.debug(`[splitTests] Split tests response: ${JSON.stringify(this.requestData)}`);
|
|
10086
10363
|
} else if (response) {
|
|
10087
|
-
|
|
10364
|
+
BStackLogger.error("[splitTests] Received unexpected response format from split tests request.");
|
|
10088
10365
|
} else {
|
|
10089
|
-
|
|
10366
|
+
BStackLogger.error("[splitTests] Failed to get split tests response.");
|
|
10090
10367
|
}
|
|
10091
10368
|
} catch (error) {
|
|
10092
|
-
|
|
10369
|
+
BStackLogger.error(`[splitTests] Exception in sending test files:: ${error}`);
|
|
10093
10370
|
}
|
|
10094
10371
|
}
|
|
10095
10372
|
/**
|
|
@@ -10107,7 +10384,7 @@ var init_test_ordering_server = __esm({
|
|
|
10107
10384
|
const resultUrl = normalizeUrl(response.resultUrl);
|
|
10108
10385
|
const timeoutUrl = normalizeUrl(response.timeoutUrl);
|
|
10109
10386
|
if (response.timeout === void 0 || response.timeoutInterval === void 0 || response.timeoutUrl === void 0 || response.resultUrl === void 0) {
|
|
10110
|
-
|
|
10387
|
+
BStackLogger.debug("[process_split_tests_response] Received null value(s) for some attributes in split tests API response");
|
|
10111
10388
|
}
|
|
10112
10389
|
return {
|
|
10113
10390
|
timeout,
|
|
@@ -10121,7 +10398,7 @@ var init_test_ordering_server = __esm({
|
|
|
10121
10398
|
*/
|
|
10122
10399
|
async getOrderedTestFiles() {
|
|
10123
10400
|
if (!this.requestData) {
|
|
10124
|
-
|
|
10401
|
+
BStackLogger.error("[getOrderedTestFiles] No request data available to fetch ordered test files.");
|
|
10125
10402
|
return null;
|
|
10126
10403
|
}
|
|
10127
10404
|
let testFilesJsonList = null;
|
|
@@ -10145,10 +10422,10 @@ var init_test_ordering_server = __esm({
|
|
|
10145
10422
|
break;
|
|
10146
10423
|
}
|
|
10147
10424
|
await new Promise((resolve) => setTimeout(resolve, timeoutInterval * 1e3));
|
|
10148
|
-
|
|
10425
|
+
BStackLogger.debug(`[getOrderedTestFiles] Fetching ordered tests from result URL after waiting for ${timeoutInterval} seconds.`);
|
|
10149
10426
|
}
|
|
10150
10427
|
if (timeoutUrl && !testFilesJsonList) {
|
|
10151
|
-
|
|
10428
|
+
BStackLogger.debug("[getOrderedTestFiles] Fetching ordered tests from timeout URL");
|
|
10152
10429
|
const response = await RequestUtils.getTestOrchestrationOrderedTests(timeoutUrl);
|
|
10153
10430
|
if (isSplitTestsResponse(response) && Array.isArray(response.tests)) {
|
|
10154
10431
|
testFilesJsonList = response.tests;
|
|
@@ -10165,10 +10442,10 @@ var init_test_ordering_server = __esm({
|
|
|
10165
10442
|
if (!testFilesJsonList) {
|
|
10166
10443
|
return null;
|
|
10167
10444
|
}
|
|
10168
|
-
|
|
10445
|
+
BStackLogger.debug(`[getOrderedTestFiles] Ordered test files received: ${JSON.stringify(testFiles)}`);
|
|
10169
10446
|
return testFiles;
|
|
10170
10447
|
} catch (error) {
|
|
10171
|
-
|
|
10448
|
+
BStackLogger.error(`[getOrderedTestFiles] Exception in fetching ordered test files: ${error}`);
|
|
10172
10449
|
return null;
|
|
10173
10450
|
}
|
|
10174
10451
|
}
|
|
@@ -10260,10 +10537,10 @@ var init_testorcherstrationhandler = __esm({
|
|
|
10260
10537
|
return;
|
|
10261
10538
|
}
|
|
10262
10539
|
if (this.config.projectName === void 0 || this.config.buildName === void 0) {
|
|
10263
|
-
|
|
10540
|
+
BStackLogger.info("Test Reordering can't work as buildName or projectName is null. Please set a non-null value.");
|
|
10264
10541
|
}
|
|
10265
10542
|
if (!this._isObservabilityEnabled()) {
|
|
10266
|
-
|
|
10543
|
+
BStackLogger.info("Test Reordering can't work as testReporting is disabled. Please enable it from browserstack.yml file.");
|
|
10267
10544
|
}
|
|
10268
10545
|
}
|
|
10269
10546
|
/**
|
|
@@ -10272,7 +10549,7 @@ var init_testorcherstrationhandler = __esm({
|
|
|
10272
10549
|
async reorderTestFiles(testFiles) {
|
|
10273
10550
|
try {
|
|
10274
10551
|
if (!testFiles || testFiles.length === 0) {
|
|
10275
|
-
|
|
10552
|
+
BStackLogger.debug("[reorderTestFiles] No test files provided for ordering.");
|
|
10276
10553
|
return null;
|
|
10277
10554
|
}
|
|
10278
10555
|
let orchestrationStrategy = null;
|
|
@@ -10281,16 +10558,16 @@ var init_testorcherstrationhandler = __esm({
|
|
|
10281
10558
|
orchestrationStrategy = this.orchestrationUtils.getTestOrderingName();
|
|
10282
10559
|
}
|
|
10283
10560
|
if (orchestrationStrategy === null) {
|
|
10284
|
-
|
|
10561
|
+
BStackLogger.error("Orchestration strategy is None. Cannot proceed with test orchestration session.");
|
|
10285
10562
|
return null;
|
|
10286
10563
|
}
|
|
10287
|
-
|
|
10564
|
+
BStackLogger.info(`Reordering test files with orchestration strategy: ${orchestrationStrategy}`);
|
|
10288
10565
|
let orderedTestFiles = [];
|
|
10289
10566
|
if (BrowserstackCLI.getInstance().isRunning()) {
|
|
10290
|
-
|
|
10567
|
+
BStackLogger.info("Using CLI flow for test files orchestration.");
|
|
10291
10568
|
orderedTestFiles = await GrpcClient.getInstance().testOrchestrationSession(testFiles, orchestrationStrategy, JSON.stringify(orchestrationMetadata)) || [];
|
|
10292
10569
|
} else {
|
|
10293
|
-
|
|
10570
|
+
BStackLogger.info("Using SDK flow for test files orchestration.");
|
|
10294
10571
|
await this.testOrderingServerHandler.splitTests(testFiles, orchestrationStrategy, JSON.stringify(orchestrationMetadata));
|
|
10295
10572
|
orderedTestFiles = await this.testOrderingServerHandler.getOrderedTestFiles() || [];
|
|
10296
10573
|
}
|
|
@@ -10301,7 +10578,7 @@ var init_testorcherstrationhandler = __esm({
|
|
|
10301
10578
|
this.addToOrderingInstrumentationData("splitTestsAPICallCount", this.testOrderingServerHandler.getSplitTestsApiCallCount());
|
|
10302
10579
|
return orderedTestFiles;
|
|
10303
10580
|
} catch (error) {
|
|
10304
|
-
|
|
10581
|
+
BStackLogger.debug(`[reorderTestFiles] Error in ordering test classes: ${error}`);
|
|
10305
10582
|
}
|
|
10306
10583
|
return null;
|
|
10307
10584
|
}
|
|
@@ -10331,22 +10608,22 @@ import { performance as performance3 } from "node:perf_hooks";
|
|
|
10331
10608
|
async function applyOrchestrationIfEnabled(specs, config) {
|
|
10332
10609
|
const orchestrationHandler = TestOrchestrationHandler.getInstance(config);
|
|
10333
10610
|
if (!orchestrationHandler) {
|
|
10334
|
-
|
|
10611
|
+
BStackLogger.debug("Orchestration handler is not initialized. Skipping orchestration.");
|
|
10335
10612
|
return specs;
|
|
10336
10613
|
}
|
|
10337
10614
|
const runSmartSelectionEnabled = isValidEnabledValue(config?.testOrchestrationOptions?.runSmartSelection?.enabled);
|
|
10338
10615
|
if (!runSmartSelectionEnabled) {
|
|
10339
|
-
|
|
10616
|
+
BStackLogger.info("runSmartSelection is not enabled in config. Skipping orchestration.");
|
|
10340
10617
|
return specs;
|
|
10341
10618
|
}
|
|
10342
10619
|
orchestrationHandler.addToOrderingInstrumentationData("enabled", orchestrationHandler.testOrderingEnabled());
|
|
10343
10620
|
const startTime = performance3.now();
|
|
10344
|
-
|
|
10621
|
+
BStackLogger.info("Test orchestration is enabled. Attempting to reorder test files.");
|
|
10345
10622
|
const testFiles = specs;
|
|
10346
|
-
|
|
10623
|
+
BStackLogger.info(`Test files to be reordered: ${testFiles.join(", ")}`);
|
|
10347
10624
|
const orderedFiles = await orchestrationHandler.reorderTestFiles(testFiles);
|
|
10348
10625
|
if (orderedFiles && orderedFiles.length > 0) {
|
|
10349
|
-
|
|
10626
|
+
BStackLogger.info(`Tests reordered using orchestration: ${orderedFiles.join(", ")}`);
|
|
10350
10627
|
orchestrationHandler.addToOrderingInstrumentationData(
|
|
10351
10628
|
"timeTakenToApply",
|
|
10352
10629
|
Math.floor(performance3.now() - startTime)
|
|
@@ -10354,7 +10631,7 @@ async function applyOrchestrationIfEnabled(specs, config) {
|
|
|
10354
10631
|
);
|
|
10355
10632
|
return orderedFiles;
|
|
10356
10633
|
}
|
|
10357
|
-
|
|
10634
|
+
BStackLogger.info("No test files were reordered by orchestration.");
|
|
10358
10635
|
orchestrationHandler.addToOrderingInstrumentationData(
|
|
10359
10636
|
"timeTakenToApply",
|
|
10360
10637
|
Math.floor(performance3.now() - startTime)
|
|
@@ -10376,12 +10653,12 @@ var init_apply_orchestration = __esm({
|
|
|
10376
10653
|
// src/launcher.ts
|
|
10377
10654
|
init_utils();
|
|
10378
10655
|
init_testOpsConfig();
|
|
10379
|
-
import
|
|
10656
|
+
import fs15 from "node:fs";
|
|
10380
10657
|
import { readFile } from "node:fs/promises";
|
|
10381
|
-
import
|
|
10658
|
+
import path21 from "node:path";
|
|
10382
10659
|
import { promisify as promisify4, format as format4 } from "node:util";
|
|
10383
10660
|
import { performance as performance4, PerformanceObserver as PerformanceObserver2 } from "node:perf_hooks";
|
|
10384
|
-
import
|
|
10661
|
+
import os7 from "node:os";
|
|
10385
10662
|
import { SevereServiceError } from "webdriverio";
|
|
10386
10663
|
import * as BrowserstackLocalLauncher from "browserstack-local";
|
|
10387
10664
|
|
|
@@ -10391,9 +10668,9 @@ init_PercyLogger();
|
|
|
10391
10668
|
// src/Percy/Percy.ts
|
|
10392
10669
|
init_util();
|
|
10393
10670
|
init_PercyLogger();
|
|
10394
|
-
import
|
|
10395
|
-
import
|
|
10396
|
-
import
|
|
10671
|
+
import fs11 from "node:fs";
|
|
10672
|
+
import path10 from "node:path";
|
|
10673
|
+
import os4 from "node:os";
|
|
10397
10674
|
import { spawn as spawn2 } from "node:child_process";
|
|
10398
10675
|
|
|
10399
10676
|
// src/Percy/PercyBinary.ts
|
|
@@ -10403,20 +10680,20 @@ init_constants2();
|
|
|
10403
10680
|
init_bstackLogger();
|
|
10404
10681
|
init_fetchWrapper();
|
|
10405
10682
|
import yauzl2 from "yauzl";
|
|
10406
|
-
import
|
|
10683
|
+
import fs10 from "node:fs";
|
|
10407
10684
|
import fsp2 from "node:fs/promises";
|
|
10408
10685
|
import { pipeline } from "node:stream/promises";
|
|
10409
|
-
import
|
|
10410
|
-
import
|
|
10686
|
+
import path9 from "node:path";
|
|
10687
|
+
import os3 from "node:os";
|
|
10411
10688
|
import { spawn } from "node:child_process";
|
|
10412
10689
|
var PercyBinary = class {
|
|
10413
10690
|
#hostOS = process.platform;
|
|
10414
10691
|
#httpPath = null;
|
|
10415
10692
|
#binaryName = "percy";
|
|
10416
10693
|
#orderedPaths = [
|
|
10417
|
-
|
|
10694
|
+
path9.join(os3.homedir(), ".browserstack"),
|
|
10418
10695
|
process.cwd(),
|
|
10419
|
-
|
|
10696
|
+
os3.tmpdir()
|
|
10420
10697
|
];
|
|
10421
10698
|
constructor() {
|
|
10422
10699
|
const base = "https://github.com/percy/cli/releases/latest/download";
|
|
@@ -10429,15 +10706,15 @@ var PercyBinary = class {
|
|
|
10429
10706
|
this.#httpPath = base + "/percy-linux.zip";
|
|
10430
10707
|
}
|
|
10431
10708
|
}
|
|
10432
|
-
async #makePath(
|
|
10433
|
-
if (await this.#checkPath(
|
|
10709
|
+
async #makePath(path22) {
|
|
10710
|
+
if (await this.#checkPath(path22)) {
|
|
10434
10711
|
return true;
|
|
10435
10712
|
}
|
|
10436
|
-
return fsp2.mkdir(
|
|
10713
|
+
return fsp2.mkdir(path22).then(() => true).catch(() => false);
|
|
10437
10714
|
}
|
|
10438
|
-
async #checkPath(
|
|
10715
|
+
async #checkPath(path22) {
|
|
10439
10716
|
try {
|
|
10440
|
-
const hasDir = await fsp2.access(
|
|
10717
|
+
const hasDir = await fsp2.access(path22).then(() => true, () => false);
|
|
10441
10718
|
if (hasDir) {
|
|
10442
10719
|
return true;
|
|
10443
10720
|
}
|
|
@@ -10447,7 +10724,7 @@ var PercyBinary = class {
|
|
|
10447
10724
|
}
|
|
10448
10725
|
// Get the path for storing the ETag
|
|
10449
10726
|
#getETagPath(destParentDir) {
|
|
10450
|
-
return
|
|
10727
|
+
return path9.join(destParentDir, `${this.#binaryName}.etag`);
|
|
10451
10728
|
}
|
|
10452
10729
|
// Load the stored ETag if it exists
|
|
10453
10730
|
async #loadETag(destParentDir) {
|
|
@@ -10457,7 +10734,7 @@ var PercyBinary = class {
|
|
|
10457
10734
|
const data = await fsp2.readFile(etagPath, "utf8");
|
|
10458
10735
|
return data.trim();
|
|
10459
10736
|
} catch (err) {
|
|
10460
|
-
|
|
10737
|
+
BStackLogger.warn(`Failed to read ETag file ${err}`);
|
|
10461
10738
|
}
|
|
10462
10739
|
}
|
|
10463
10740
|
return null;
|
|
@@ -10470,23 +10747,23 @@ var PercyBinary = class {
|
|
|
10470
10747
|
try {
|
|
10471
10748
|
const etagPath = this.#getETagPath(destParentDir);
|
|
10472
10749
|
await fsp2.writeFile(etagPath, etag);
|
|
10473
|
-
|
|
10750
|
+
BStackLogger.debug("Saved new ETag for percy binary");
|
|
10474
10751
|
} catch (err) {
|
|
10475
|
-
|
|
10752
|
+
BStackLogger.error(`Failed to save ETag file ${err}`);
|
|
10476
10753
|
}
|
|
10477
10754
|
}
|
|
10478
10755
|
async #getAvailableDirs() {
|
|
10479
10756
|
for (let i = 0; i < this.#orderedPaths.length; i++) {
|
|
10480
|
-
const
|
|
10481
|
-
if (await this.#makePath(
|
|
10482
|
-
return
|
|
10757
|
+
const path22 = this.#orderedPaths[i];
|
|
10758
|
+
if (await this.#makePath(path22)) {
|
|
10759
|
+
return path22;
|
|
10483
10760
|
}
|
|
10484
10761
|
}
|
|
10485
10762
|
throw new Error("Error trying to download percy binary");
|
|
10486
10763
|
}
|
|
10487
10764
|
async getBinaryPath() {
|
|
10488
10765
|
const destParentDir = await this.#getAvailableDirs();
|
|
10489
|
-
const binaryPath =
|
|
10766
|
+
const binaryPath = path9.join(destParentDir, this.#binaryName);
|
|
10490
10767
|
let response;
|
|
10491
10768
|
if (await this.#checkPath(binaryPath)) {
|
|
10492
10769
|
const currentETag = await this.#loadETag(destParentDir);
|
|
@@ -10494,13 +10771,13 @@ var PercyBinary = class {
|
|
|
10494
10771
|
try {
|
|
10495
10772
|
const result = await this.#checkForUpdate(currentETag);
|
|
10496
10773
|
if (!result.needsUpdate) {
|
|
10497
|
-
|
|
10774
|
+
BStackLogger.debug("Percy binary is up to date (ETag unchanged)");
|
|
10498
10775
|
return binaryPath;
|
|
10499
10776
|
}
|
|
10500
10777
|
response = result.response;
|
|
10501
|
-
|
|
10778
|
+
BStackLogger.debug("New Percy binary version available, downloading update");
|
|
10502
10779
|
} catch (err) {
|
|
10503
|
-
|
|
10780
|
+
BStackLogger.warn(`Failed to check for binary updates, using existing binary ${err}`);
|
|
10504
10781
|
return binaryPath;
|
|
10505
10782
|
}
|
|
10506
10783
|
}
|
|
@@ -10528,11 +10805,11 @@ var PercyBinary = class {
|
|
|
10528
10805
|
}
|
|
10529
10806
|
const newETag = response.headers.get("eTag");
|
|
10530
10807
|
if (newETag) {
|
|
10531
|
-
await this.#saveETag(
|
|
10808
|
+
await this.#saveETag(path9.dirname(this.#getETagPath(await this.#getAvailableDirs())), newETag);
|
|
10532
10809
|
}
|
|
10533
10810
|
return { needsUpdate: true, response };
|
|
10534
10811
|
} catch (error) {
|
|
10535
|
-
|
|
10812
|
+
BStackLogger.warn(`Error checking for Percy binary updates: ${error}`);
|
|
10536
10813
|
throw error;
|
|
10537
10814
|
}
|
|
10538
10815
|
}
|
|
@@ -10555,9 +10832,9 @@ var PercyBinary = class {
|
|
|
10555
10832
|
await fsp2.mkdir(destParentDir);
|
|
10556
10833
|
}
|
|
10557
10834
|
const binaryName = this.#binaryName;
|
|
10558
|
-
const zipFilePath =
|
|
10559
|
-
const binaryPath =
|
|
10560
|
-
const downloadedFileStream =
|
|
10835
|
+
const zipFilePath = path9.join(destParentDir, binaryName + ".zip");
|
|
10836
|
+
const binaryPath = path9.join(destParentDir, binaryName);
|
|
10837
|
+
const downloadedFileStream = fs10.createWriteStream(zipFilePath);
|
|
10561
10838
|
if (!response) {
|
|
10562
10839
|
response = await _fetch(this.#httpPath);
|
|
10563
10840
|
}
|
|
@@ -10576,8 +10853,8 @@ var PercyBinary = class {
|
|
|
10576
10853
|
if (/\/$/.test(entry.fileName)) {
|
|
10577
10854
|
zipfile.readEntry();
|
|
10578
10855
|
} else {
|
|
10579
|
-
const writeStream =
|
|
10580
|
-
|
|
10856
|
+
const writeStream = fs10.createWriteStream(
|
|
10857
|
+
path9.join(destParentDir, entry.fileName)
|
|
10581
10858
|
);
|
|
10582
10859
|
zipfile.openReadStream(entry, function(zipErr, readStream) {
|
|
10583
10860
|
if (zipErr) {
|
|
@@ -10598,7 +10875,7 @@ var PercyBinary = class {
|
|
|
10598
10875
|
reject(zipErr);
|
|
10599
10876
|
});
|
|
10600
10877
|
zipfile.once("end", () => {
|
|
10601
|
-
|
|
10878
|
+
fs10.chmod(binaryPath, "0755", function(zipErr) {
|
|
10602
10879
|
if (zipErr) {
|
|
10603
10880
|
reject(zipErr);
|
|
10604
10881
|
}
|
|
@@ -10622,7 +10899,7 @@ init_constants2();
|
|
|
10622
10899
|
init_apiUtils();
|
|
10623
10900
|
var logDir = "logs";
|
|
10624
10901
|
var Percy = class {
|
|
10625
|
-
#logfile =
|
|
10902
|
+
#logfile = path10.join(logDir, "percy.log");
|
|
10626
10903
|
#address = process.env.PERCY_SERVER_ADDRESS || "http://127.0.0.1:5338";
|
|
10627
10904
|
#binaryPath = null;
|
|
10628
10905
|
#options;
|
|
@@ -10663,7 +10940,7 @@ var Percy = class {
|
|
|
10663
10940
|
}
|
|
10664
10941
|
async start() {
|
|
10665
10942
|
const binaryPath = await this.#getBinaryPath();
|
|
10666
|
-
const logStream =
|
|
10943
|
+
const logStream = fs11.createWriteStream(this.#logfile, { flags: "a" });
|
|
10667
10944
|
const token = await this.fetchPercyToken();
|
|
10668
10945
|
const configPath = await this.createPercyConfig();
|
|
10669
10946
|
if (!token) {
|
|
@@ -10750,13 +11027,13 @@ var Percy = class {
|
|
|
10750
11027
|
if (!this.#options.percyOptions) {
|
|
10751
11028
|
return null;
|
|
10752
11029
|
}
|
|
10753
|
-
const configPath =
|
|
11030
|
+
const configPath = path10.join(os4.tmpdir(), "percy.json");
|
|
10754
11031
|
const percyOptions = this.#options.percyOptions;
|
|
10755
11032
|
if (!percyOptions.version) {
|
|
10756
11033
|
percyOptions.version = "2";
|
|
10757
11034
|
}
|
|
10758
11035
|
return new Promise((resolve) => {
|
|
10759
|
-
|
|
11036
|
+
fs11.writeFile(
|
|
10760
11037
|
configPath,
|
|
10761
11038
|
JSON.stringify(
|
|
10762
11039
|
percyOptions
|
|
@@ -10850,6 +11127,7 @@ init_constants();
|
|
|
10850
11127
|
init_util();
|
|
10851
11128
|
init_crash_reporter();
|
|
10852
11129
|
init_bstackLogger();
|
|
11130
|
+
init_caCert();
|
|
10853
11131
|
init_PercyLogger();
|
|
10854
11132
|
|
|
10855
11133
|
// src/config.ts
|
|
@@ -10857,10 +11135,62 @@ init_testOpsConfig();
|
|
|
10857
11135
|
init_util();
|
|
10858
11136
|
init_bstackLogger();
|
|
10859
11137
|
import { v4 as uuidv4 } from "uuid";
|
|
11138
|
+
var APP_AUTOMATE_CAP_KEYS = ["appium:app", "appium:bundleId", "appium:appPackage", "appium:appActivity"];
|
|
11139
|
+
function hasAppCap(cap) {
|
|
11140
|
+
if (!cap || typeof cap !== "object") {
|
|
11141
|
+
return false;
|
|
11142
|
+
}
|
|
11143
|
+
const record = cap;
|
|
11144
|
+
if (APP_AUTOMATE_CAP_KEYS.some((key) => !isUndefined(record[key]))) {
|
|
11145
|
+
return true;
|
|
11146
|
+
}
|
|
11147
|
+
const appiumOptions = record["appium:options"];
|
|
11148
|
+
return !!(appiumOptions && !isUndefined(appiumOptions.app));
|
|
11149
|
+
}
|
|
11150
|
+
function detectAppAutomate(capabilities) {
|
|
11151
|
+
if (!capabilities) {
|
|
11152
|
+
return false;
|
|
11153
|
+
}
|
|
11154
|
+
const flat = [];
|
|
11155
|
+
if (Array.isArray(capabilities)) {
|
|
11156
|
+
for (const entry of capabilities) {
|
|
11157
|
+
if (!entry || typeof entry !== "object") {
|
|
11158
|
+
continue;
|
|
11159
|
+
}
|
|
11160
|
+
if ("alwaysMatch" in entry) {
|
|
11161
|
+
const w3c = entry;
|
|
11162
|
+
flat.push(w3c.alwaysMatch);
|
|
11163
|
+
if (Array.isArray(w3c.firstMatch)) {
|
|
11164
|
+
flat.push(...w3c.firstMatch);
|
|
11165
|
+
}
|
|
11166
|
+
continue;
|
|
11167
|
+
}
|
|
11168
|
+
const values = Object.values(entry);
|
|
11169
|
+
const isParallelMultiremote = values.length > 0 && values.every(
|
|
11170
|
+
(v) => v !== null && typeof v === "object" && v.capabilities
|
|
11171
|
+
);
|
|
11172
|
+
if (isParallelMultiremote) {
|
|
11173
|
+
for (const v of values) {
|
|
11174
|
+
flat.push(v.capabilities);
|
|
11175
|
+
}
|
|
11176
|
+
} else {
|
|
11177
|
+
flat.push(entry);
|
|
11178
|
+
}
|
|
11179
|
+
}
|
|
11180
|
+
} else {
|
|
11181
|
+
for (const v of Object.values(capabilities)) {
|
|
11182
|
+
const inner = v.capabilities;
|
|
11183
|
+
if (inner) {
|
|
11184
|
+
flat.push(inner);
|
|
11185
|
+
}
|
|
11186
|
+
}
|
|
11187
|
+
}
|
|
11188
|
+
return flat.some(hasAppCap);
|
|
11189
|
+
}
|
|
10860
11190
|
var BrowserStackConfig = class _BrowserStackConfig {
|
|
10861
|
-
static getInstance(options, config) {
|
|
11191
|
+
static getInstance(options, config, capabilities, isBrowserStackInfra) {
|
|
10862
11192
|
if (!this._instance && options && config) {
|
|
10863
|
-
this._instance = new _BrowserStackConfig(options, config);
|
|
11193
|
+
this._instance = new _BrowserStackConfig(options, config, capabilities, isBrowserStackInfra);
|
|
10864
11194
|
}
|
|
10865
11195
|
return this._instance;
|
|
10866
11196
|
}
|
|
@@ -10881,7 +11211,7 @@ var BrowserStackConfig = class _BrowserStackConfig {
|
|
|
10881
11211
|
percyBuildId;
|
|
10882
11212
|
isPercyAutoEnabled = false;
|
|
10883
11213
|
sdkRunID;
|
|
10884
|
-
constructor(options, config) {
|
|
11214
|
+
constructor(options, config, capabilities, isBrowserStackInfra = true) {
|
|
10885
11215
|
this.framework = config.framework;
|
|
10886
11216
|
this.userName = config.user;
|
|
10887
11217
|
this.accessKey = config.key;
|
|
@@ -10889,11 +11219,11 @@ var BrowserStackConfig = class _BrowserStackConfig {
|
|
|
10889
11219
|
this.percy = options.percy || false;
|
|
10890
11220
|
this.accessibility = options.accessibility;
|
|
10891
11221
|
this.app = options.app;
|
|
10892
|
-
this.appAutomate = !isUndefined(options.app);
|
|
10893
|
-
this.automate = !this.appAutomate;
|
|
11222
|
+
this.appAutomate = isBrowserStackInfra && (!isUndefined(options.app) || detectAppAutomate(capabilities));
|
|
11223
|
+
this.automate = isBrowserStackInfra && !this.appAutomate;
|
|
10894
11224
|
this.buildIdentifier = options.buildIdentifier;
|
|
10895
11225
|
this.sdkRunID = uuidv4();
|
|
10896
|
-
|
|
11226
|
+
BStackLogger.info(`BrowserStack service started with id: ${this.sdkRunID}`);
|
|
10897
11227
|
}
|
|
10898
11228
|
sentFunnelData() {
|
|
10899
11229
|
this.funnelDataSent = true;
|
|
@@ -10903,32 +11233,32 @@ var config_default = BrowserStackConfig;
|
|
|
10903
11233
|
|
|
10904
11234
|
// src/exitHandler.ts
|
|
10905
11235
|
import { spawn as spawn4 } from "node:child_process";
|
|
10906
|
-
import
|
|
11236
|
+
import path17 from "node:path";
|
|
10907
11237
|
|
|
10908
11238
|
// src/instrumentation/funnelInstrumentation.ts
|
|
10909
11239
|
init_usageStats();
|
|
10910
11240
|
init_bstackLogger();
|
|
10911
11241
|
init_constants();
|
|
10912
|
-
import
|
|
11242
|
+
import os5 from "node:os";
|
|
10913
11243
|
import util4, { format as format2 } from "node:util";
|
|
10914
|
-
import
|
|
10915
|
-
import
|
|
11244
|
+
import path12 from "node:path";
|
|
11245
|
+
import fs13 from "node:fs";
|
|
10916
11246
|
|
|
10917
11247
|
// src/data-store.ts
|
|
10918
11248
|
init_bstackLogger();
|
|
10919
|
-
import
|
|
10920
|
-
import
|
|
10921
|
-
var workersDataDirPath =
|
|
11249
|
+
import path11 from "node:path";
|
|
11250
|
+
import fs12 from "node:fs";
|
|
11251
|
+
var workersDataDirPath = path11.join(process.cwd(), "logs", "worker_data");
|
|
10922
11252
|
function getDataFromWorkers() {
|
|
10923
11253
|
const workersData = [];
|
|
10924
|
-
if (!
|
|
11254
|
+
if (!fs12.existsSync(workersDataDirPath)) {
|
|
10925
11255
|
return workersData;
|
|
10926
11256
|
}
|
|
10927
|
-
const files =
|
|
11257
|
+
const files = fs12.readdirSync(workersDataDirPath);
|
|
10928
11258
|
files.forEach((file) => {
|
|
10929
|
-
|
|
10930
|
-
const filePath =
|
|
10931
|
-
const fileContent =
|
|
11259
|
+
BStackLogger.debug("Reading worker file " + file);
|
|
11260
|
+
const filePath = path11.join(workersDataDirPath, file);
|
|
11261
|
+
const fileContent = fs12.readFileSync(filePath, "utf8");
|
|
10932
11262
|
const workerData = JSON.parse(fileContent);
|
|
10933
11263
|
workersData.push(workerData);
|
|
10934
11264
|
});
|
|
@@ -10936,21 +11266,21 @@ function getDataFromWorkers() {
|
|
|
10936
11266
|
return workersData;
|
|
10937
11267
|
}
|
|
10938
11268
|
function saveWorkerData(data) {
|
|
10939
|
-
const filePath =
|
|
11269
|
+
const filePath = path11.join(workersDataDirPath, "worker-data-" + process.pid + ".json");
|
|
10940
11270
|
try {
|
|
10941
11271
|
createWorkersDataDir();
|
|
10942
|
-
|
|
11272
|
+
fs12.writeFileSync(filePath, JSON.stringify(data));
|
|
10943
11273
|
} catch (e) {
|
|
10944
|
-
|
|
11274
|
+
BStackLogger.debug("Exception in saving worker data: " + e);
|
|
10945
11275
|
}
|
|
10946
11276
|
}
|
|
10947
11277
|
function removeWorkersDataDir() {
|
|
10948
|
-
|
|
11278
|
+
fs12.rmSync(workersDataDirPath, { recursive: true, force: true });
|
|
10949
11279
|
return true;
|
|
10950
11280
|
}
|
|
10951
11281
|
function createWorkersDataDir() {
|
|
10952
|
-
if (!
|
|
10953
|
-
|
|
11282
|
+
if (!fs12.existsSync(workersDataDirPath)) {
|
|
11283
|
+
fs12.mkdirSync(workersDataDirPath, { recursive: true });
|
|
10954
11284
|
}
|
|
10955
11285
|
return true;
|
|
10956
11286
|
}
|
|
@@ -10964,16 +11294,16 @@ init_performance_tester();
|
|
|
10964
11294
|
init_constants2();
|
|
10965
11295
|
async function fireFunnelTestEvent(eventType, config, isCLIEnabled = false) {
|
|
10966
11296
|
if (!config.userName || !config.accessKey) {
|
|
10967
|
-
|
|
11297
|
+
BStackLogger.debug("username/accesskey not passed");
|
|
10968
11298
|
return;
|
|
10969
11299
|
}
|
|
10970
11300
|
try {
|
|
10971
11301
|
const data = buildEventData(eventType, config, isCLIEnabled);
|
|
10972
11302
|
await fireFunnelRequest(data);
|
|
10973
|
-
|
|
11303
|
+
BStackLogger.debug("Funnel event success");
|
|
10974
11304
|
config.sentFunnelData();
|
|
10975
11305
|
} catch (error) {
|
|
10976
|
-
|
|
11306
|
+
BStackLogger.debug(`Exception in sending funnel data: ${format2(error)}`);
|
|
10977
11307
|
}
|
|
10978
11308
|
}
|
|
10979
11309
|
async function sendStart(config) {
|
|
@@ -10998,9 +11328,9 @@ async function sendFinish(config, isCLIEnabled = false) {
|
|
|
10998
11328
|
}
|
|
10999
11329
|
function saveFunnelData(eventType, config, isCLIEnabled = false) {
|
|
11000
11330
|
const data = buildEventData(eventType, config, isCLIEnabled);
|
|
11001
|
-
|
|
11002
|
-
const filePath =
|
|
11003
|
-
|
|
11331
|
+
BStackLogger.ensureLogsFolder();
|
|
11332
|
+
const filePath = path12.join(BStackLogger.logFolderPath, "funnelData.json");
|
|
11333
|
+
fs13.writeFileSync(filePath, JSON.stringify(data));
|
|
11004
11334
|
return filePath;
|
|
11005
11335
|
}
|
|
11006
11336
|
function redactCredentialsFromFunnelData(data) {
|
|
@@ -11017,7 +11347,7 @@ function redactCredentialsFromFunnelData(data) {
|
|
|
11017
11347
|
async function fireFunnelRequest(data) {
|
|
11018
11348
|
const { userName, accessKey } = data;
|
|
11019
11349
|
redactCredentialsFromFunnelData(data);
|
|
11020
|
-
|
|
11350
|
+
BStackLogger.debug("Sending SDK event with data " + util4.inspect(data, { depth: 6 }));
|
|
11021
11351
|
const encodedAuth = Buffer.from(`${userName}:${accessKey}`, "utf8").toString("base64");
|
|
11022
11352
|
const response = await fetchWrap(APIUtils.FUNNEL_INSTRUMENTATION_URL, {
|
|
11023
11353
|
method: "POST",
|
|
@@ -11027,7 +11357,7 @@ async function fireFunnelRequest(data) {
|
|
|
11027
11357
|
},
|
|
11028
11358
|
body: JSON.stringify(data)
|
|
11029
11359
|
});
|
|
11030
|
-
|
|
11360
|
+
BStackLogger.debug("Funnel Event Response: " + JSON.stringify(await response.text()));
|
|
11031
11361
|
}
|
|
11032
11362
|
function getProductList(config) {
|
|
11033
11363
|
const products = [];
|
|
@@ -11061,8 +11391,8 @@ function buildEventData(eventType, config, isCLIEnabled = false) {
|
|
|
11061
11391
|
buildName: config.buildName || "undefined",
|
|
11062
11392
|
buildIdentifier: String(config.buildIdentifier),
|
|
11063
11393
|
// Host details
|
|
11064
|
-
os:
|
|
11065
|
-
hostname:
|
|
11394
|
+
os: os5.type() || "unknown",
|
|
11395
|
+
hostname: os5.hostname() || "unknown",
|
|
11066
11396
|
// Product Details
|
|
11067
11397
|
productMap: getProductMap(config),
|
|
11068
11398
|
product: getProductList(config),
|
|
@@ -11077,6 +11407,10 @@ function buildEventData(eventType, config, isCLIEnabled = false) {
|
|
|
11077
11407
|
if (process.env.BSTACK_A11Y_POLLING_TIMEOUT) {
|
|
11078
11408
|
eventProperties.pollingTimeout = process.env.BSTACK_A11Y_POLLING_TIMEOUT;
|
|
11079
11409
|
}
|
|
11410
|
+
const reloadHappened = workerData.some((worker2) => worker2.reloadHappened === true);
|
|
11411
|
+
if (reloadHappened) {
|
|
11412
|
+
eventProperties.finishedMetadata = { reason: "session_reloaded" };
|
|
11413
|
+
}
|
|
11080
11414
|
}
|
|
11081
11415
|
return {
|
|
11082
11416
|
userName: config.userName,
|
|
@@ -11112,30 +11446,30 @@ function isProxyError(authResult) {
|
|
|
11112
11446
|
function handleProxyError(config, isSelfHealEnabled) {
|
|
11113
11447
|
sendEvent.tcgProxyFailure(config);
|
|
11114
11448
|
if (isSelfHealEnabled) {
|
|
11115
|
-
|
|
11449
|
+
BStackLogger.warn("Proxy Error. Disabling Healing for this session.");
|
|
11116
11450
|
}
|
|
11117
11451
|
}
|
|
11118
11452
|
function handleUpgradeRequired(isSelfHealEnabled) {
|
|
11119
11453
|
if (isSelfHealEnabled) {
|
|
11120
|
-
|
|
11454
|
+
BStackLogger.warn("Please upgrade Browserstack Service to the latest version to use the self-healing feature.");
|
|
11121
11455
|
}
|
|
11122
11456
|
}
|
|
11123
11457
|
function handleAuthenticationFailure(status, config, isSelfHealEnabled) {
|
|
11124
11458
|
if (status >= 500) {
|
|
11125
11459
|
if (isSelfHealEnabled) {
|
|
11126
|
-
|
|
11460
|
+
BStackLogger.warn("Something went wrong. Disabling healing for this session. Please try again later.");
|
|
11127
11461
|
}
|
|
11128
11462
|
sendEvent.tcgDown(config);
|
|
11129
11463
|
} else {
|
|
11130
11464
|
if (isSelfHealEnabled) {
|
|
11131
|
-
|
|
11465
|
+
BStackLogger.warn("Authentication Failed. Disabling Healing for this session.");
|
|
11132
11466
|
}
|
|
11133
11467
|
sendEvent.tcgAuthFailure(config);
|
|
11134
11468
|
}
|
|
11135
11469
|
}
|
|
11136
11470
|
function handleAuthenticationSuccess(isHealingEnabledForUser, userId, config, isSelfHealEnabled) {
|
|
11137
11471
|
if (!isHealingEnabledForUser && isSelfHealEnabled) {
|
|
11138
|
-
|
|
11472
|
+
BStackLogger.warn("Healing is not enabled for your group, please contact the admin");
|
|
11139
11473
|
} else if (userId && isHealingEnabledForUser) {
|
|
11140
11474
|
sendEvent.tcgtInitSuccessful(config);
|
|
11141
11475
|
}
|
|
@@ -11147,7 +11481,7 @@ function handleInitializationFailure(status, config, isSelfHealEnabled) {
|
|
|
11147
11481
|
sendEvent.invalidTcgAuth(config);
|
|
11148
11482
|
}
|
|
11149
11483
|
if (isSelfHealEnabled) {
|
|
11150
|
-
|
|
11484
|
+
BStackLogger.warn("Authentication Failed. Healing will be disabled for this session.");
|
|
11151
11485
|
}
|
|
11152
11486
|
}
|
|
11153
11487
|
function handleHealingInstrumentation(authResult, config, isSelfHealEnabled) {
|
|
@@ -11174,7 +11508,7 @@ function handleHealingInstrumentation(authResult, config, isSelfHealEnabled) {
|
|
|
11174
11508
|
return;
|
|
11175
11509
|
}
|
|
11176
11510
|
} catch (err) {
|
|
11177
|
-
|
|
11511
|
+
BStackLogger.debug("Error in handling healing instrumentation: " + err);
|
|
11178
11512
|
}
|
|
11179
11513
|
}
|
|
11180
11514
|
|
|
@@ -11186,36 +11520,36 @@ init_bstackLogger();
|
|
|
11186
11520
|
init_cli();
|
|
11187
11521
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
11188
11522
|
var __filename = fileURLToPath2(import.meta.url);
|
|
11189
|
-
var __dirname =
|
|
11523
|
+
var __dirname = path17.dirname(__filename);
|
|
11190
11524
|
function setupExitHandlers() {
|
|
11191
11525
|
const handleCLICleanup = () => {
|
|
11192
|
-
|
|
11526
|
+
BStackLogger.debug("Handling CLI cleanup in exit handler");
|
|
11193
11527
|
try {
|
|
11194
11528
|
const cliProcess = BrowserstackCLI.getInstance()?.process;
|
|
11195
11529
|
if (cliProcess && cliProcess.pid && cliProcess.exitCode === null) {
|
|
11196
|
-
|
|
11530
|
+
BStackLogger.debug(`Found CLI process with PID ${cliProcess.pid}, terminating`);
|
|
11197
11531
|
try {
|
|
11198
11532
|
if (process.platform === "win32") {
|
|
11199
11533
|
cliProcess.kill("SIGTERM");
|
|
11200
|
-
|
|
11534
|
+
BStackLogger.debug("CLI process terminated successfully with SIGTERM (Windows)");
|
|
11201
11535
|
} else {
|
|
11202
11536
|
cliProcess.kill("SIGINT");
|
|
11203
|
-
|
|
11537
|
+
BStackLogger.debug("CLI process terminated successfully with SIGINT (Unix)");
|
|
11204
11538
|
}
|
|
11205
11539
|
} catch (processError2) {
|
|
11206
|
-
|
|
11540
|
+
BStackLogger.debug(`CLI process termination error: ${processError2}`);
|
|
11207
11541
|
try {
|
|
11208
11542
|
cliProcess.kill();
|
|
11209
|
-
|
|
11543
|
+
BStackLogger.debug("CLI process terminated with default signal (fallback)");
|
|
11210
11544
|
} catch (fallbackError) {
|
|
11211
|
-
|
|
11545
|
+
BStackLogger.debug(`CLI process fallback termination error: ${fallbackError}`);
|
|
11212
11546
|
}
|
|
11213
11547
|
}
|
|
11214
11548
|
} else {
|
|
11215
|
-
|
|
11549
|
+
BStackLogger.debug("No CLI process found to terminate");
|
|
11216
11550
|
}
|
|
11217
11551
|
} catch (error) {
|
|
11218
|
-
|
|
11552
|
+
BStackLogger.debug(`Error in CLI cleanup: ${error}`);
|
|
11219
11553
|
}
|
|
11220
11554
|
};
|
|
11221
11555
|
process.on("exit", () => {
|
|
@@ -11223,8 +11557,8 @@ function setupExitHandlers() {
|
|
|
11223
11557
|
handleCLICleanup();
|
|
11224
11558
|
const args = shouldCallCleanup(config_default.getInstance(), isCLIEnabled);
|
|
11225
11559
|
if (Array.isArray(args) && args.length) {
|
|
11226
|
-
|
|
11227
|
-
const childProcess = spawn4("node", [`${
|
|
11560
|
+
BStackLogger.debug(`Spawning cleanup.js with args: ${args.join(", ")}`);
|
|
11561
|
+
const childProcess = spawn4("node", [`${path17.join(__dirname, "cleanup.js")}`, ...args], { detached: true, stdio: "inherit", env: { ...process.env } });
|
|
11228
11562
|
childProcess.unref();
|
|
11229
11563
|
}
|
|
11230
11564
|
});
|
|
@@ -11250,8 +11584,8 @@ function shouldCallCleanup(config, isCLIEnabled = false) {
|
|
|
11250
11584
|
// src/ai-handler.ts
|
|
11251
11585
|
init_bstackLogger();
|
|
11252
11586
|
init_constants();
|
|
11253
|
-
import
|
|
11254
|
-
import
|
|
11587
|
+
import path18 from "node:path";
|
|
11588
|
+
import fs14 from "node:fs";
|
|
11255
11589
|
import url2 from "node:url";
|
|
11256
11590
|
import aiSDK from "@browserstack/ai-sdk-node";
|
|
11257
11591
|
init_util();
|
|
@@ -11278,7 +11612,7 @@ var AiHandler = class {
|
|
|
11278
11612
|
}
|
|
11279
11613
|
} else if (options.selfHeal === true) {
|
|
11280
11614
|
const healingWarnMessage = authResult.message;
|
|
11281
|
-
|
|
11615
|
+
BStackLogger.warn(`Healing Auth failed. Disabling healing for this session. Reason: ${healingWarnMessage}`);
|
|
11282
11616
|
}
|
|
11283
11617
|
return caps;
|
|
11284
11618
|
}
|
|
@@ -11287,8 +11621,8 @@ var AiHandler = class {
|
|
|
11287
11621
|
}
|
|
11288
11622
|
async installFirefoxExtension(browser) {
|
|
11289
11623
|
const __dirname2 = url2.fileURLToPath(new URL(".", import.meta.url));
|
|
11290
|
-
const extensionPath =
|
|
11291
|
-
const extFile =
|
|
11624
|
+
const extensionPath = path18.resolve(__dirname2, aiSDK.BrowserstackHealing.getFirefoxAddonPath());
|
|
11625
|
+
const extFile = fs14.readFileSync(extensionPath);
|
|
11292
11626
|
await browser.installAddOn(extFile.toString("base64"), true);
|
|
11293
11627
|
}
|
|
11294
11628
|
async handleHealing(orginalFunc, using, value, browser, options) {
|
|
@@ -11315,7 +11649,7 @@ var AiHandler = class {
|
|
|
11315
11649
|
return result;
|
|
11316
11650
|
}
|
|
11317
11651
|
if (options.selfHeal === true && this.authResult.isHealingEnabled) {
|
|
11318
|
-
|
|
11652
|
+
BStackLogger.info("findElement failed, trying to heal");
|
|
11319
11653
|
PerformanceTester.start(AI_EVENTS.SELF_HEAL_STEP);
|
|
11320
11654
|
const script = await aiSDK.BrowserstackHealing.healFailure(locatorType, locatorValue, void 0, void 0, this.authResult.userId, this.authResult.groupId, sessionId, void 0, void 0, this.authResult.isGroupAIEnabled, tcgDetails);
|
|
11321
11655
|
if (script) {
|
|
@@ -11325,7 +11659,7 @@ var AiHandler = class {
|
|
|
11325
11659
|
PerformanceTester.end(AI_EVENTS.SELF_HEAL_GET_RESULT);
|
|
11326
11660
|
if (tcgData && tcgData.selector && tcgData.value) {
|
|
11327
11661
|
const healedResult = await orginalFunc(tcgData.selector, tcgData.value);
|
|
11328
|
-
|
|
11662
|
+
BStackLogger.info("Healing worked, element found: " + tcgData.selector + ": " + tcgData.value);
|
|
11329
11663
|
PerformanceTester.end(AI_EVENTS.SELF_HEAL_STEP);
|
|
11330
11664
|
return healedResult.error ? result : healedResult;
|
|
11331
11665
|
}
|
|
@@ -11337,9 +11671,9 @@ var AiHandler = class {
|
|
|
11337
11671
|
} catch (err) {
|
|
11338
11672
|
PerformanceTester.end(AI_EVENTS.SELF_HEAL_STEP, false, String(err));
|
|
11339
11673
|
if (options.selfHeal === true) {
|
|
11340
|
-
|
|
11674
|
+
BStackLogger.warn("Something went wrong while healing. Disabling healing for this command");
|
|
11341
11675
|
} else {
|
|
11342
|
-
|
|
11676
|
+
BStackLogger.warn("Error in findElement: " + err + "using: " + using + "value: " + value);
|
|
11343
11677
|
}
|
|
11344
11678
|
}
|
|
11345
11679
|
return await orginalFunc(using, value);
|
|
@@ -11375,7 +11709,7 @@ var AiHandler = class {
|
|
|
11375
11709
|
}
|
|
11376
11710
|
} catch (err) {
|
|
11377
11711
|
if (options.selfHeal === true) {
|
|
11378
|
-
|
|
11712
|
+
BStackLogger.warn(`Error while initiliazing Browserstack healing Extension ${err}`);
|
|
11379
11713
|
}
|
|
11380
11714
|
}
|
|
11381
11715
|
return caps;
|
|
@@ -11384,7 +11718,7 @@ var AiHandler = class {
|
|
|
11384
11718
|
if (SUPPORTED_BROWSERS_FOR_AI.includes(browser.capabilities?.browserName?.toLowerCase())) {
|
|
11385
11719
|
const authInfo = this.authResult;
|
|
11386
11720
|
if (Object.keys(authInfo).length === 0 && options.selfHeal === true) {
|
|
11387
|
-
|
|
11721
|
+
BStackLogger.debug("TCG Auth result is empty");
|
|
11388
11722
|
return;
|
|
11389
11723
|
}
|
|
11390
11724
|
const { isAuthenticated, sessionToken, defaultLogDataEnabled } = authInfo;
|
|
@@ -11412,7 +11746,7 @@ var AiHandler = class {
|
|
|
11412
11746
|
}
|
|
11413
11747
|
} catch (err) {
|
|
11414
11748
|
if (options.selfHeal === true) {
|
|
11415
|
-
|
|
11749
|
+
BStackLogger.warn(`Error while setting up self-healing: ${err}. Disabling healing for this session.`);
|
|
11416
11750
|
}
|
|
11417
11751
|
}
|
|
11418
11752
|
}
|
|
@@ -11430,9 +11764,10 @@ var BrowserstackLauncherService = class {
|
|
|
11430
11764
|
constructor(_options, capabilities, _config) {
|
|
11431
11765
|
this._options = _options;
|
|
11432
11766
|
this._config = _config;
|
|
11433
|
-
|
|
11767
|
+
BStackLogger.clearLogFile();
|
|
11434
11768
|
PercyLogger.clearLogFile();
|
|
11435
11769
|
setupExitHandlers();
|
|
11770
|
+
configureCaCertificate(this._options);
|
|
11436
11771
|
if (!this._config) {
|
|
11437
11772
|
this._config = _options;
|
|
11438
11773
|
}
|
|
@@ -11454,12 +11789,13 @@ var BrowserstackLauncherService = class {
|
|
|
11454
11789
|
if (!isUndefined(process.env.TEST_REPORTING_BUILD_TAG)) {
|
|
11455
11790
|
process.env.TEST_OBSERVABILITY_BUILD_TAG = process.env.TEST_REPORTING_BUILD_TAG;
|
|
11456
11791
|
}
|
|
11457
|
-
|
|
11458
|
-
|
|
11459
|
-
|
|
11792
|
+
const isBrowserStackInfra = isBrowserstackInfra(_config, capabilities);
|
|
11793
|
+
this.browserStackConfig = config_default.getInstance(_options, _config, capabilities, isBrowserStackInfra);
|
|
11794
|
+
BStackLogger.debug(`_options data: ${JSON.stringify(_options)}`);
|
|
11795
|
+
BStackLogger.debug(`webdriver capabilities data: ${JSON.stringify(capabilities)}`);
|
|
11460
11796
|
const configCopy = JSON.parse(JSON.stringify(_config));
|
|
11461
11797
|
CrashReporter.recursivelyRedactKeysFromObject(configCopy, ["user", "username", "key", "accesskey", "password"]);
|
|
11462
|
-
|
|
11798
|
+
BStackLogger.debug(`_config data: ${JSON.stringify(configCopy)}`);
|
|
11463
11799
|
if (Array.isArray(capabilities)) {
|
|
11464
11800
|
capabilities.flatMap((c) => {
|
|
11465
11801
|
if ("alwaysMatch" in c) {
|
|
@@ -11546,9 +11882,11 @@ var BrowserstackLauncherService = class {
|
|
|
11546
11882
|
try {
|
|
11547
11883
|
CrashReporter.setConfigDetails(this._config, capabilities, this._options);
|
|
11548
11884
|
} catch (error) {
|
|
11549
|
-
|
|
11885
|
+
BStackLogger.error(`[Crash_Report_Upload] Config processing failed due to ${error}`);
|
|
11550
11886
|
}
|
|
11551
11887
|
}
|
|
11888
|
+
_options;
|
|
11889
|
+
_config;
|
|
11552
11890
|
browserstackLocal;
|
|
11553
11891
|
_buildName;
|
|
11554
11892
|
_projectName;
|
|
@@ -11576,7 +11914,7 @@ var BrowserstackLauncherService = class {
|
|
|
11576
11914
|
if (config.specs && Array.isArray(config.specs) && isValidEnabledValue(this._options.testOrchestrationOptions?.runSmartSelection?.enabled)) {
|
|
11577
11915
|
try {
|
|
11578
11916
|
const glob = (await import("glob")).sync;
|
|
11579
|
-
const
|
|
11917
|
+
const path22 = await import("node:path");
|
|
11580
11918
|
const expandedSpecs = [];
|
|
11581
11919
|
for (const specPattern of config.specs) {
|
|
11582
11920
|
if (typeof specPattern === "string") {
|
|
@@ -11593,21 +11931,21 @@ var BrowserstackLauncherService = class {
|
|
|
11593
11931
|
}) || [];
|
|
11594
11932
|
filenames.forEach((filename) => {
|
|
11595
11933
|
let absolutePath = filename;
|
|
11596
|
-
if (!
|
|
11597
|
-
absolutePath =
|
|
11934
|
+
if (!path22.isAbsolute(filename)) {
|
|
11935
|
+
absolutePath = path22.resolve(rootDir, filename);
|
|
11598
11936
|
}
|
|
11599
|
-
let relativePath =
|
|
11937
|
+
let relativePath = path22.relative(cwd, absolutePath);
|
|
11600
11938
|
relativePath = relativePath.replace(/\\/g, "/");
|
|
11601
11939
|
expandedSpecs.push(relativePath);
|
|
11602
11940
|
});
|
|
11603
11941
|
}
|
|
11604
11942
|
}
|
|
11605
11943
|
if (expandedSpecs.length > 0) {
|
|
11606
|
-
|
|
11944
|
+
BStackLogger.info(`Expanded specs from glob patterns to ${expandedSpecs.length} files`);
|
|
11607
11945
|
config.specs = expandedSpecs;
|
|
11608
11946
|
}
|
|
11609
11947
|
} catch (error) {
|
|
11610
|
-
|
|
11948
|
+
BStackLogger.error(`Failed to expand spec patterns: ${error}`);
|
|
11611
11949
|
}
|
|
11612
11950
|
}
|
|
11613
11951
|
try {
|
|
@@ -11618,11 +11956,11 @@ var BrowserstackLauncherService = class {
|
|
|
11618
11956
|
CLIUtils.setFrameworkDetail(WDIO_NAMING_PREFIX + config.framework, "WebdriverIO");
|
|
11619
11957
|
const binconfig = CLIUtils.getBinConfig(config, capabilities, this._options, this._buildTag);
|
|
11620
11958
|
await BrowserstackCLI.getInstance().bootstrap(this._options, config, binconfig);
|
|
11621
|
-
|
|
11959
|
+
BStackLogger.debug(`Is CLI running ${BrowserstackCLI.getInstance().isRunning()}`);
|
|
11622
11960
|
PerformanceTester.end(FRAMEWORK_EVENTS.START);
|
|
11623
11961
|
}
|
|
11624
11962
|
} catch (err) {
|
|
11625
|
-
|
|
11963
|
+
BStackLogger.error(`Error while starting CLI ${err}`);
|
|
11626
11964
|
PerformanceTester.end(FRAMEWORK_EVENTS.START, false, format4(err));
|
|
11627
11965
|
}
|
|
11628
11966
|
PerformanceTester.end(FRAMEWORK_EVENTS.INIT);
|
|
@@ -11641,13 +11979,13 @@ var BrowserstackLauncherService = class {
|
|
|
11641
11979
|
}
|
|
11642
11980
|
} catch (err) {
|
|
11643
11981
|
if (this._options.selfHeal === true) {
|
|
11644
|
-
|
|
11982
|
+
BStackLogger.warn(`Error while setting up Browserstack healing Extension ${err}. Disabling healing for this session.`);
|
|
11645
11983
|
}
|
|
11646
11984
|
}
|
|
11647
11985
|
}
|
|
11648
11986
|
if (!BrowserstackCLI.getInstance().isRunning()) {
|
|
11649
11987
|
if (!this._options.app) {
|
|
11650
|
-
|
|
11988
|
+
BStackLogger.debug("app is not defined in browserstack-service config, skipping ...");
|
|
11651
11989
|
} else {
|
|
11652
11990
|
let app = {};
|
|
11653
11991
|
const appConfig = this._options.app;
|
|
@@ -11656,10 +11994,10 @@ var BrowserstackLauncherService = class {
|
|
|
11656
11994
|
} catch (error) {
|
|
11657
11995
|
throw new SevereServiceError(error.message);
|
|
11658
11996
|
}
|
|
11659
|
-
if (VALID_APP_EXTENSION.includes(
|
|
11660
|
-
if (
|
|
11997
|
+
if (VALID_APP_EXTENSION.includes(path21.extname(app.app))) {
|
|
11998
|
+
if (fs15.existsSync(app.app)) {
|
|
11661
11999
|
const data = await this._uploadApp(app);
|
|
11662
|
-
|
|
12000
|
+
BStackLogger.info(`app upload completed: ${JSON.stringify(data)}`);
|
|
11663
12001
|
app.app = data.app_url;
|
|
11664
12002
|
} else if (app.customId) {
|
|
11665
12003
|
app.app = app.customId;
|
|
@@ -11667,7 +12005,7 @@ var BrowserstackLauncherService = class {
|
|
|
11667
12005
|
throw new SevereServiceError(`[Invalid app path] app path ${app.app} is not correct, Provide correct path to app under test`);
|
|
11668
12006
|
}
|
|
11669
12007
|
}
|
|
11670
|
-
|
|
12008
|
+
BStackLogger.info(`Using app: ${app.app}`);
|
|
11671
12009
|
this._updateCaps(capabilities, "app", app.app);
|
|
11672
12010
|
}
|
|
11673
12011
|
}
|
|
@@ -11680,7 +12018,7 @@ var BrowserstackLauncherService = class {
|
|
|
11680
12018
|
const shouldSetupPercy = this._options.percy || isUndefined(this._options.percy) && this._options.app;
|
|
11681
12019
|
let buildStartResponse = null;
|
|
11682
12020
|
if (!BrowserstackCLI.getInstance().isRunning() && (this._options.testObservability || this._accessibilityAutomation || shouldSetupPercy)) {
|
|
11683
|
-
|
|
12021
|
+
BStackLogger.debug("Sending launch start event");
|
|
11684
12022
|
buildStartResponse = await launchTestSession(this._options, this._config, {
|
|
11685
12023
|
projectName: this._projectName,
|
|
11686
12024
|
buildName: this._buildName,
|
|
@@ -11739,15 +12077,15 @@ var BrowserstackLauncherService = class {
|
|
|
11739
12077
|
if (typeof spec !== "string") {
|
|
11740
12078
|
return spec;
|
|
11741
12079
|
}
|
|
11742
|
-
const absolutePath =
|
|
11743
|
-
const relativePath =
|
|
12080
|
+
const absolutePath = path21.isAbsolute(spec) ? spec : path21.resolve(cwd, spec);
|
|
12081
|
+
const relativePath = path21.relative(rootDir, absolutePath);
|
|
11744
12082
|
return relativePath.replace(/\\/g, "/");
|
|
11745
12083
|
});
|
|
11746
12084
|
};
|
|
11747
12085
|
try {
|
|
11748
12086
|
const { applyOrchestrationIfEnabled: applyOrchestrationIfEnabled2 } = await Promise.resolve().then(() => (init_apply_orchestration(), apply_orchestration_exports));
|
|
11749
12087
|
if (config.specs && config.specs.length > 0 && this._options.testObservability && isValidEnabledValue(this._options.testOrchestrationOptions?.runSmartSelection?.enabled)) {
|
|
11750
|
-
|
|
12088
|
+
BStackLogger.info("Applying test orchestration");
|
|
11751
12089
|
const specs = config.specs.filter((spec) => typeof spec === "string");
|
|
11752
12090
|
console.log(`Specs before orchestration: ${specs}`);
|
|
11753
12091
|
const orderedSpecs = await applyOrchestrationIfEnabled2(specs, this._options);
|
|
@@ -11755,14 +12093,14 @@ var BrowserstackLauncherService = class {
|
|
|
11755
12093
|
const specsToConvert = orderedSpecs && orderedSpecs.length > 0 ? orderedSpecs : specs;
|
|
11756
12094
|
config.specs = convertToRootDirRelative(specsToConvert);
|
|
11757
12095
|
console.log(`Specs after orchestration: ${config.specs}`);
|
|
11758
|
-
|
|
12096
|
+
BStackLogger.info("Test specs updated with orchestrated order");
|
|
11759
12097
|
}
|
|
11760
12098
|
} catch (error) {
|
|
11761
|
-
|
|
12099
|
+
BStackLogger.error(`Error applying test orchestration: ${error}`);
|
|
11762
12100
|
if (config.specs && config.specs.length > 0) {
|
|
11763
12101
|
const specs = config.specs.filter((spec) => typeof spec === "string");
|
|
11764
12102
|
config.specs = convertToRootDirRelative(specs);
|
|
11765
|
-
|
|
12103
|
+
BStackLogger.debug(`Specs converted back to rootDir-relative after error: ${config.specs}`);
|
|
11766
12104
|
}
|
|
11767
12105
|
}
|
|
11768
12106
|
}
|
|
@@ -11770,7 +12108,7 @@ var BrowserstackLauncherService = class {
|
|
|
11770
12108
|
return;
|
|
11771
12109
|
}
|
|
11772
12110
|
if (!this._options.browserstackLocal) {
|
|
11773
|
-
return
|
|
12111
|
+
return BStackLogger.info("browserstackLocal is not enabled - skipping...");
|
|
11774
12112
|
}
|
|
11775
12113
|
const opts = {
|
|
11776
12114
|
key: this._config.key,
|
|
@@ -11783,7 +12121,7 @@ var BrowserstackLauncherService = class {
|
|
|
11783
12121
|
}
|
|
11784
12122
|
const obs = new PerformanceObserver2((list) => {
|
|
11785
12123
|
const entry = list.getEntries()[0];
|
|
11786
|
-
|
|
12124
|
+
BStackLogger.info(`Browserstack Local successfully started after ${entry.duration}ms`);
|
|
11787
12125
|
});
|
|
11788
12126
|
obs.observe({ entryTypes: ["measure"] });
|
|
11789
12127
|
let timer;
|
|
@@ -11816,13 +12154,13 @@ var BrowserstackLauncherService = class {
|
|
|
11816
12154
|
PerformanceTester.start(FRAMEWORK_EVENTS.STOP);
|
|
11817
12155
|
try {
|
|
11818
12156
|
const isCLIEnabled = BrowserstackCLI.getInstance().isRunning();
|
|
11819
|
-
|
|
11820
|
-
|
|
12157
|
+
BStackLogger.debug("Inside OnComplete hook..");
|
|
12158
|
+
BStackLogger.debug("Sending stop launch event");
|
|
11821
12159
|
try {
|
|
11822
12160
|
await (isCLIEnabled ? BrowserstackCLI.getInstance().stop() : stopBuildUpstream());
|
|
11823
12161
|
PerformanceTester.end(FRAMEWORK_EVENTS.STOP);
|
|
11824
12162
|
} catch (err) {
|
|
11825
|
-
|
|
12163
|
+
BStackLogger.error(`Error while stopping CLI ${err}`);
|
|
11826
12164
|
PerformanceTester.end(FRAMEWORK_EVENTS.STOP, false, format4(err));
|
|
11827
12165
|
}
|
|
11828
12166
|
if (process.env[BROWSERSTACK_OBSERVABILITY] && process.env[BROWSERSTACK_TESTHUB_UUID]) {
|
|
@@ -11838,16 +12176,16 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
11838
12176
|
return;
|
|
11839
12177
|
}
|
|
11840
12178
|
const duration = (/* @__PURE__ */ new Date()).getTime() - new Date(process.env.START_TIME).getTime();
|
|
11841
|
-
|
|
12179
|
+
BStackLogger.info(`Total duration is ${duration / 1e3} s`);
|
|
11842
12180
|
}
|
|
11843
|
-
|
|
12181
|
+
BStackLogger.info(`BrowserStack service run ended for id: ${this.browserStackConfig?.sdkRunID} testhub id: ${testOpsConfig_default.getInstance()?.buildHashedId}`);
|
|
11844
12182
|
await sendFinish(this.browserStackConfig, isCLIEnabled);
|
|
11845
12183
|
try {
|
|
11846
12184
|
PerformanceTester.start(EVENTS.SDK_SEND_LOGS);
|
|
11847
12185
|
await this._uploadServiceLogs();
|
|
11848
12186
|
PerformanceTester.end(EVENTS.SDK_SEND_LOGS);
|
|
11849
12187
|
} catch (error) {
|
|
11850
|
-
|
|
12188
|
+
BStackLogger.debug(`Failed to upload BrowserStack WDIO Service logs ${error}`);
|
|
11851
12189
|
PerformanceTester.end(EVENTS.SDK_SEND_LOGS, false, format4(error));
|
|
11852
12190
|
}
|
|
11853
12191
|
PerformanceTester.end(EVENTS.SDK_ON_STOP);
|
|
@@ -11857,9 +12195,9 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
11857
12195
|
PerformanceTester.end(EVENTS.SDK_ON_STOP, false, format4(error));
|
|
11858
12196
|
PerformanceTester.end(EVENTS.SDK_CLEANUP, false, format4(error));
|
|
11859
12197
|
await PerformanceTester.stopAndGenerate("performance-launcher.html");
|
|
11860
|
-
|
|
12198
|
+
BStackLogger.error(`Error in onComplete hook: ${error}`);
|
|
11861
12199
|
}
|
|
11862
|
-
|
|
12200
|
+
BStackLogger.clearLogger();
|
|
11863
12201
|
if (this._options.percy) {
|
|
11864
12202
|
await this.stopPercy();
|
|
11865
12203
|
PercyLogger.clearLogger();
|
|
@@ -11943,10 +12281,10 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
11943
12281
|
}
|
|
11944
12282
|
}
|
|
11945
12283
|
async _uploadApp(app) {
|
|
11946
|
-
|
|
12284
|
+
BStackLogger.info(`uploading app ${app.app} ${app.customId ? `and custom_id: ${app.customId}` : ""} to browserstack`);
|
|
11947
12285
|
const form = new FormData();
|
|
11948
12286
|
if (app.app) {
|
|
11949
|
-
const fileName =
|
|
12287
|
+
const fileName = path21.basename(app.app);
|
|
11950
12288
|
const fileBuffer = await readFile(app.app);
|
|
11951
12289
|
const fileBlob = new Blob([new Uint8Array(fileBuffer)]);
|
|
11952
12290
|
form.append("file", fileBlob, fileName);
|
|
@@ -11995,8 +12333,8 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
11995
12333
|
const clientBuildUuid = this._getClientBuildUuid();
|
|
11996
12334
|
const response = await uploadLogs(getBrowserStackUser(this._config), getBrowserStackKey(this._config), clientBuildUuid);
|
|
11997
12335
|
if (response) {
|
|
11998
|
-
|
|
11999
|
-
|
|
12336
|
+
BStackLogger.info(`Upload response: ${JSON.stringify(response, null, 2)}`);
|
|
12337
|
+
BStackLogger.logToFile(`Response - ${format4(response)}`, "debug");
|
|
12000
12338
|
}
|
|
12001
12339
|
}
|
|
12002
12340
|
_removeCliOnlyCapabilityOptions(capabilities) {
|
|
@@ -12129,7 +12467,7 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
12129
12467
|
});
|
|
12130
12468
|
}
|
|
12131
12469
|
} catch (error) {
|
|
12132
|
-
|
|
12470
|
+
BStackLogger.debug(`Exception while retrieving capability value. Error - ${error}`);
|
|
12133
12471
|
}
|
|
12134
12472
|
}
|
|
12135
12473
|
_updateCaps(capabilities, capType, value) {
|
|
@@ -12265,7 +12603,7 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
12265
12603
|
}
|
|
12266
12604
|
if ((!this._buildName || process.env.BROWSERSTACK_BUILD_NAME) && this._buildIdentifier) {
|
|
12267
12605
|
this._updateCaps(capabilities, "buildIdentifier");
|
|
12268
|
-
|
|
12606
|
+
BStackLogger.warn("Skipping buildIdentifier as buildName is not passed.");
|
|
12269
12607
|
return;
|
|
12270
12608
|
}
|
|
12271
12609
|
if (this._buildIdentifier && this._buildIdentifier.includes("${DATE_TIME}")) {
|
|
@@ -12308,16 +12646,16 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
12308
12646
|
* else returns corresponding value in json file (e.g. { "wdio-build": { "identifier" : 2 } } => 2 in this case)
|
|
12309
12647
|
*/
|
|
12310
12648
|
_getLocalBuildNumber() {
|
|
12311
|
-
const browserstackFolderPath =
|
|
12649
|
+
const browserstackFolderPath = path21.join(os7.homedir(), ".browserstack");
|
|
12312
12650
|
try {
|
|
12313
|
-
if (!
|
|
12314
|
-
|
|
12651
|
+
if (!fs15.existsSync(browserstackFolderPath)) {
|
|
12652
|
+
fs15.mkdirSync(browserstackFolderPath);
|
|
12315
12653
|
}
|
|
12316
|
-
const filePath =
|
|
12317
|
-
if (!
|
|
12318
|
-
|
|
12654
|
+
const filePath = path21.join(browserstackFolderPath, ".build-name-cache.json");
|
|
12655
|
+
if (!fs15.existsSync(filePath)) {
|
|
12656
|
+
fs15.appendFileSync(filePath, JSON.stringify({}));
|
|
12319
12657
|
}
|
|
12320
|
-
const buildCacheFileData =
|
|
12658
|
+
const buildCacheFileData = fs15.readFileSync(filePath);
|
|
12321
12659
|
const parsedBuildCacheFileData = JSON.parse(buildCacheFileData.toString());
|
|
12322
12660
|
if (this._buildName && this._buildName in parsedBuildCacheFileData) {
|
|
12323
12661
|
const prevIdentifier = parseInt(parsedBuildCacheFileData[this._buildName].identifier);
|
|
@@ -12336,16 +12674,16 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
12336
12674
|
if (!buildName || !filePath) {
|
|
12337
12675
|
return;
|
|
12338
12676
|
}
|
|
12339
|
-
const jsonContent = JSON.parse(
|
|
12677
|
+
const jsonContent = JSON.parse(fs15.readFileSync(filePath).toString());
|
|
12340
12678
|
jsonContent[buildName] = { "identifier": buildIdentifier };
|
|
12341
|
-
|
|
12679
|
+
fs15.writeFileSync(filePath, JSON.stringify(jsonContent));
|
|
12342
12680
|
}
|
|
12343
12681
|
_getClientBuildUuid() {
|
|
12344
12682
|
if (process.env[BROWSERSTACK_TESTHUB_UUID]) {
|
|
12345
12683
|
return process.env[BROWSERSTACK_TESTHUB_UUID];
|
|
12346
12684
|
}
|
|
12347
12685
|
const uuid = this.browserStackConfig?.sdkRunID;
|
|
12348
|
-
|
|
12686
|
+
BStackLogger.logToFile(`If facing any issues, please contact BrowserStack support with the Build Run Id - ${uuid}`, "info");
|
|
12349
12687
|
return uuid;
|
|
12350
12688
|
}
|
|
12351
12689
|
};
|
|
@@ -12367,6 +12705,7 @@ init_util();
|
|
|
12367
12705
|
init_insights_handler();
|
|
12368
12706
|
init_reporter();
|
|
12369
12707
|
init_constants();
|
|
12708
|
+
init_caCert();
|
|
12370
12709
|
init_crash_reporter();
|
|
12371
12710
|
|
|
12372
12711
|
// src/accessibility-handler.ts
|
|
@@ -12400,6 +12739,9 @@ var _AccessibilityHandler = class {
|
|
|
12400
12739
|
this._config = _config;
|
|
12401
12740
|
this._turboscale = isTrue(_turboscale);
|
|
12402
12741
|
}
|
|
12742
|
+
_browser;
|
|
12743
|
+
isAppAutomate;
|
|
12744
|
+
_framework;
|
|
12403
12745
|
_platformA11yMeta;
|
|
12404
12746
|
_caps;
|
|
12405
12747
|
_suiteFile;
|
|
@@ -12490,7 +12832,7 @@ var _AccessibilityHandler = class {
|
|
|
12490
12832
|
};
|
|
12491
12833
|
browserWithA11y.startA11yScanning = async () => {
|
|
12492
12834
|
if (this._testIdentifier === null) {
|
|
12493
|
-
|
|
12835
|
+
BStackLogger.warn("Accessibility scanning cannot be started from outside the test");
|
|
12494
12836
|
return;
|
|
12495
12837
|
}
|
|
12496
12838
|
AccessibilityHandler._a11yScanSessionMap[sessionId] = true;
|
|
@@ -12502,7 +12844,7 @@ var _AccessibilityHandler = class {
|
|
|
12502
12844
|
};
|
|
12503
12845
|
browserWithA11y.stopA11yScanning = async () => {
|
|
12504
12846
|
if (this._testIdentifier === null) {
|
|
12505
|
-
|
|
12847
|
+
BStackLogger.warn("Accessibility scanning cannot be stopped from outside the test");
|
|
12506
12848
|
return;
|
|
12507
12849
|
}
|
|
12508
12850
|
AccessibilityHandler._a11yScanSessionMap[sessionId] = false;
|
|
@@ -12521,7 +12863,7 @@ var _AccessibilityHandler = class {
|
|
|
12521
12863
|
const prevImpl = orig ? orig.bind(browser) : void 0;
|
|
12522
12864
|
browser.overwriteCommand(command.name, this.commandWrapper.bind(this, command, prevImpl), command.class === "Element");
|
|
12523
12865
|
} catch (error) {
|
|
12524
|
-
|
|
12866
|
+
BStackLogger.debug(`Exception in overwrite command ${command.name} - ${error}`);
|
|
12525
12867
|
}
|
|
12526
12868
|
});
|
|
12527
12869
|
PerformanceTester.end(CONFIG_EVENTS.ACCESSIBILITY);
|
|
@@ -12545,14 +12887,14 @@ var _AccessibilityHandler = class {
|
|
|
12545
12887
|
};
|
|
12546
12888
|
this._testMetadata[testIdentifier].accessibilityScanStarted = shouldScanTest;
|
|
12547
12889
|
if (shouldScanTest) {
|
|
12548
|
-
|
|
12890
|
+
BStackLogger.info("Automate test case execution has started.");
|
|
12549
12891
|
}
|
|
12550
12892
|
} catch (error) {
|
|
12551
|
-
|
|
12893
|
+
BStackLogger.error(`Exception in starting accessibility automation scan for this test case ${error}`);
|
|
12552
12894
|
}
|
|
12553
12895
|
}
|
|
12554
12896
|
async afterTest(suiteTitle, test) {
|
|
12555
|
-
|
|
12897
|
+
BStackLogger.debug("Accessibility after test hook. Before sending test stop event");
|
|
12556
12898
|
if (this._framework !== "mocha" || !this.shouldRunTestHooks(this._browser, this._accessibility)) {
|
|
12557
12899
|
return;
|
|
12558
12900
|
}
|
|
@@ -12564,17 +12906,17 @@ var _AccessibilityHandler = class {
|
|
|
12564
12906
|
return;
|
|
12565
12907
|
}
|
|
12566
12908
|
if (shouldScanTestForAccessibility2) {
|
|
12567
|
-
|
|
12909
|
+
BStackLogger.info("Automate test case execution has ended. Processing for accessibility testing is underway. ");
|
|
12568
12910
|
const dataForExtension = {
|
|
12569
12911
|
"thTestRunUuid": process.env.TEST_ANALYTICS_ID,
|
|
12570
12912
|
"thBuildUuid": process.env.BROWSERSTACK_TESTHUB_UUID,
|
|
12571
12913
|
"thJwtToken": process.env.BROWSERSTACK_TESTHUB_JWT
|
|
12572
12914
|
};
|
|
12573
12915
|
await this.sendTestStopEvent(this._browser, dataForExtension);
|
|
12574
|
-
|
|
12916
|
+
BStackLogger.info("Accessibility testing for this test case has ended.");
|
|
12575
12917
|
}
|
|
12576
12918
|
} catch (error) {
|
|
12577
|
-
|
|
12919
|
+
BStackLogger.error(`Accessibility results could not be processed for the test case ${test.title}. Error : ${error}`);
|
|
12578
12920
|
}
|
|
12579
12921
|
}
|
|
12580
12922
|
/**
|
|
@@ -12602,14 +12944,14 @@ var _AccessibilityHandler = class {
|
|
|
12602
12944
|
}
|
|
12603
12945
|
listener_default.setTestRunAccessibilityVar(this._accessibility && shouldScanScenario);
|
|
12604
12946
|
if (shouldScanScenario) {
|
|
12605
|
-
|
|
12947
|
+
BStackLogger.info("Automate test case execution has started.");
|
|
12606
12948
|
}
|
|
12607
12949
|
} catch (error) {
|
|
12608
|
-
|
|
12950
|
+
BStackLogger.error(`Exception in starting accessibility automation scan for this test case ${error}`);
|
|
12609
12951
|
}
|
|
12610
12952
|
}
|
|
12611
12953
|
async afterScenario(world) {
|
|
12612
|
-
|
|
12954
|
+
BStackLogger.debug("Accessibility after scenario hook. Before sending test stop event");
|
|
12613
12955
|
if (!this.shouldRunTestHooks(this._browser, this._accessibility)) {
|
|
12614
12956
|
return;
|
|
12615
12957
|
}
|
|
@@ -12622,17 +12964,17 @@ var _AccessibilityHandler = class {
|
|
|
12622
12964
|
return;
|
|
12623
12965
|
}
|
|
12624
12966
|
if (shouldScanTestForAccessibility2) {
|
|
12625
|
-
|
|
12967
|
+
BStackLogger.info("Automate test case execution has ended. Processing for accessibility testing is underway. ");
|
|
12626
12968
|
const dataForExtension = {
|
|
12627
12969
|
"thTestRunUuid": process.env.TEST_ANALYTICS_ID,
|
|
12628
12970
|
"thBuildUuid": process.env.BROWSERSTACK_TESTHUB_UUID,
|
|
12629
12971
|
"thJwtToken": process.env.BROWSERSTACK_TESTHUB_JWT
|
|
12630
12972
|
};
|
|
12631
12973
|
await this.sendTestStopEvent(this._browser, dataForExtension);
|
|
12632
|
-
|
|
12974
|
+
BStackLogger.info("Accessibility testing for this test case has ended.");
|
|
12633
12975
|
}
|
|
12634
12976
|
} catch (error) {
|
|
12635
|
-
|
|
12977
|
+
BStackLogger.error(`Accessibility results could not be processed for the test case ${pickleData.name}. Error : ${error}`);
|
|
12636
12978
|
}
|
|
12637
12979
|
}
|
|
12638
12980
|
/*
|
|
@@ -12640,14 +12982,14 @@ var _AccessibilityHandler = class {
|
|
|
12640
12982
|
*/
|
|
12641
12983
|
async commandWrapper(command, prevImpl, origFunction, ...args) {
|
|
12642
12984
|
if (this._sessionId && AccessibilityHandler._a11yScanSessionMap[this._sessionId] && (!command.name.includes("execute") || !AccessibilityHandler.shouldPatchExecuteScript(args.length ? args[0] : null))) {
|
|
12643
|
-
|
|
12985
|
+
BStackLogger.debug(`Performing scan for ${command.class} ${command.name}`);
|
|
12644
12986
|
await performA11yScan(this.isAppAutomate, this._browser, true, true, command.name);
|
|
12645
12987
|
}
|
|
12646
12988
|
const impl = prevImpl || origFunction;
|
|
12647
12989
|
return impl(...args);
|
|
12648
12990
|
}
|
|
12649
12991
|
async sendTestStopEvent(browser, dataForExtension) {
|
|
12650
|
-
|
|
12992
|
+
BStackLogger.debug("Performing scan before saving results");
|
|
12651
12993
|
if (AccessibilityHandler._a11yScanSessionMap[this._sessionId]) {
|
|
12652
12994
|
await PerformanceTester.measureWrapper(A11Y_EVENTS.PERFORM_SCAN, async () => {
|
|
12653
12995
|
await performA11yScan(this.isAppAutomate, browser, true, true);
|
|
@@ -12659,9 +13001,9 @@ var _AccessibilityHandler = class {
|
|
|
12659
13001
|
await PerformanceTester.measureWrapper(A11Y_EVENTS.SAVE_RESULTS, async () => {
|
|
12660
13002
|
if (accessibility_scripts_default.saveTestResults) {
|
|
12661
13003
|
const results = await executeAccessibilityScript(browser, accessibility_scripts_default.saveTestResults, dataForExtension);
|
|
12662
|
-
|
|
13004
|
+
BStackLogger.debug(util11.format(results));
|
|
12663
13005
|
} else {
|
|
12664
|
-
|
|
13006
|
+
BStackLogger.error("saveTestResults script is null or undefined");
|
|
12665
13007
|
}
|
|
12666
13008
|
})();
|
|
12667
13009
|
}
|
|
@@ -12738,6 +13080,7 @@ var BrowserstackService = class {
|
|
|
12738
13080
|
this._caps = _caps;
|
|
12739
13081
|
this._config = _config;
|
|
12740
13082
|
this._options = { ...DEFAULT_OPTIONS, ...options };
|
|
13083
|
+
configureCaCertificate(this._options);
|
|
12741
13084
|
if (!this._config) {
|
|
12742
13085
|
this._config = this._options;
|
|
12743
13086
|
}
|
|
@@ -12762,6 +13105,8 @@ var BrowserstackService = class {
|
|
|
12762
13105
|
process.env.PERCY_SNAPSHOT = "true";
|
|
12763
13106
|
}
|
|
12764
13107
|
}
|
|
13108
|
+
_caps;
|
|
13109
|
+
_config;
|
|
12765
13110
|
_sessionBaseUrl = "https://api.browserstack.com/automate/sessions";
|
|
12766
13111
|
_failReasons = [];
|
|
12767
13112
|
_hookFailReasons = [];
|
|
@@ -12771,6 +13116,8 @@ var BrowserstackService = class {
|
|
|
12771
13116
|
// Track last scenario for preferScenarioName feature
|
|
12772
13117
|
_scenariosRanCount = 0;
|
|
12773
13118
|
// Count of non-skipped scenarios
|
|
13119
|
+
_reloadHappened = false;
|
|
13120
|
+
// Set when browser.reloadSession() is called; surfaced as finishedMetadata on SDKTestSuccessful so reload-orphaned builds can be excluded from session-linking
|
|
12774
13121
|
_failureStatuses = ["failed", "ambiguous", "undefined", "unknown"];
|
|
12775
13122
|
_browser;
|
|
12776
13123
|
_suiteTitle;
|
|
@@ -12830,20 +13177,20 @@ var BrowserstackService = class {
|
|
|
12830
13177
|
NOT_ALLOWED_KEYS_IN_CAPS.forEach((key) => delete capabilities[`browserstack.${key}`]);
|
|
12831
13178
|
}
|
|
12832
13179
|
} catch (err) {
|
|
12833
|
-
|
|
13180
|
+
BStackLogger.error(`Error while tracking automation framework event: ${err}`);
|
|
12834
13181
|
}
|
|
12835
13182
|
} catch (err) {
|
|
12836
|
-
|
|
13183
|
+
BStackLogger.error(`Error while connecting to Browserstack CLI: ${err}`);
|
|
12837
13184
|
PerformanceTester.end(DRIVER_EVENT.INIT, false, util12.format(err));
|
|
12838
13185
|
throw err;
|
|
12839
13186
|
}
|
|
12840
13187
|
PerformanceTester.end(DRIVER_EVENT.INIT);
|
|
12841
13188
|
PerformanceTester.start(EVENTS.SDK_DEVICE_ALLOCATION);
|
|
12842
|
-
|
|
13189
|
+
BStackLogger.debug("Device allocation tracking started - waiting for WebDriverIO to create remote session");
|
|
12843
13190
|
}
|
|
12844
13191
|
async before(caps, specs, browser) {
|
|
12845
13192
|
PerformanceTester.end(EVENTS.SDK_DEVICE_ALLOCATION, true, "Device allocated and session created");
|
|
12846
|
-
|
|
13193
|
+
BStackLogger.debug("Device allocation tracking ended - remote session created successfully");
|
|
12847
13194
|
PerformanceTester.start(DRIVER_EVENT.PRE_INITIALIZE);
|
|
12848
13195
|
this._browser = browser ? browser : globalThis.browser;
|
|
12849
13196
|
PerformanceTester.browser = this._browser;
|
|
@@ -12852,7 +13199,7 @@ var BrowserstackService = class {
|
|
|
12852
13199
|
await ai_handler_default.selfHeal(this._options, caps, this._browser);
|
|
12853
13200
|
} catch (err) {
|
|
12854
13201
|
if (this._options.selfHeal === true) {
|
|
12855
|
-
|
|
13202
|
+
BStackLogger.warn(`Error while setting up self-healing: ${err}. Disabling healing for this session.`);
|
|
12856
13203
|
}
|
|
12857
13204
|
}
|
|
12858
13205
|
}
|
|
@@ -12882,13 +13229,13 @@ var BrowserstackService = class {
|
|
|
12882
13229
|
this._options.accessibilityOptions
|
|
12883
13230
|
);
|
|
12884
13231
|
if (isBrowserstackSession(this._browser) && BrowserstackCLI.getInstance().isRunning()) {
|
|
12885
|
-
|
|
13232
|
+
BStackLogger.info(`CLI is running, tracking accessibility event for before: ${sessionId}`);
|
|
12886
13233
|
} else {
|
|
12887
13234
|
await this._accessibilityHandler.before(sessionId);
|
|
12888
13235
|
}
|
|
12889
13236
|
listener_default.setAccessibilityOptions(this._options.accessibilityOptions);
|
|
12890
13237
|
} catch (err) {
|
|
12891
|
-
|
|
13238
|
+
BStackLogger.error(`[Accessibility Test Run] Error in service class before function: ${err}`);
|
|
12892
13239
|
}
|
|
12893
13240
|
if (shouldProcessEventForTesthub("")) {
|
|
12894
13241
|
patchConsoleLogs();
|
|
@@ -12899,7 +13246,7 @@ var BrowserstackService = class {
|
|
|
12899
13246
|
this._options
|
|
12900
13247
|
);
|
|
12901
13248
|
if (BrowserstackCLI.getInstance().isRunning()) {
|
|
12902
|
-
|
|
13249
|
+
BStackLogger.info(`CLI is running, tracking insights event for before: ${sessionId}`);
|
|
12903
13250
|
await BrowserstackCLI.getInstance().getAutomationFramework().trackEvent(AutomationFrameworkState.CREATE, HookState.POST, { browser: this._browser, hubUrl: this._config.hostname });
|
|
12904
13251
|
this._insightsHandler.setGitConfigPath();
|
|
12905
13252
|
PerformanceTester.end(DRIVER_EVENT.PRE_INITIALIZE);
|
|
@@ -12934,7 +13281,7 @@ var BrowserstackService = class {
|
|
|
12934
13281
|
});
|
|
12935
13282
|
}
|
|
12936
13283
|
} catch (err) {
|
|
12937
|
-
|
|
13284
|
+
BStackLogger.error(`Error in service class before function: ${err}`);
|
|
12938
13285
|
if (shouldProcessEventForTesthub("")) {
|
|
12939
13286
|
CrashReporter.uploadCrashReport(`Error in service class before function: ${err}`, err ? err.stack : "unknown error");
|
|
12940
13287
|
}
|
|
@@ -13118,7 +13465,7 @@ var BrowserstackService = class {
|
|
|
13118
13465
|
return;
|
|
13119
13466
|
}
|
|
13120
13467
|
} catch (error) {
|
|
13121
|
-
|
|
13468
|
+
BStackLogger.error(`Error in after hook: ${error}`);
|
|
13122
13469
|
PerformanceTester.end(DRIVER_EVENT.QUIT, false, util12.format(error));
|
|
13123
13470
|
PerformanceTester.end(HOOK_EVENTS.AFTER, false, util12.format(error));
|
|
13124
13471
|
await PerformanceTester.stopAndGenerate("performance-service.html");
|
|
@@ -13175,6 +13522,7 @@ var BrowserstackService = class {
|
|
|
13175
13522
|
if (!this._browser) {
|
|
13176
13523
|
return Promise.resolve();
|
|
13177
13524
|
}
|
|
13525
|
+
this._reloadHappened = true;
|
|
13178
13526
|
const { setSessionName, setSessionStatus } = this._options;
|
|
13179
13527
|
const ignoreHooksStatus = this._options.testObservabilityOptions?.ignoreHooksStatus === true;
|
|
13180
13528
|
let sessionStatus;
|
|
@@ -13189,14 +13537,14 @@ var BrowserstackService = class {
|
|
|
13189
13537
|
failureReason = hasReasons ? this._failReasons.join("\n") : void 0;
|
|
13190
13538
|
}
|
|
13191
13539
|
if (!this._browser.isMultiremote) {
|
|
13192
|
-
|
|
13540
|
+
BStackLogger.info(`Update (reloaded) job with sessionId ${oldSessionId}, ${sessionStatus}`);
|
|
13193
13541
|
} else {
|
|
13194
13542
|
const browserName = this._browser.instances.filter(
|
|
13195
13543
|
(browserName2) => this._browser && this._browser.getInstance(browserName2).sessionId === newSessionId
|
|
13196
13544
|
)[0];
|
|
13197
|
-
|
|
13545
|
+
BStackLogger.info(`Update (reloaded) multiremote job for browser "${browserName}" and sessionId ${oldSessionId}, ${sessionStatus}`);
|
|
13198
13546
|
}
|
|
13199
|
-
|
|
13547
|
+
BStackLogger.warn(`Session Reloaded: Old Session Id: ${oldSessionId}, New Session Id: ${newSessionId}`);
|
|
13200
13548
|
await this._insightsHandler?.sendCBTInfo();
|
|
13201
13549
|
if (setSessionStatus) {
|
|
13202
13550
|
await this._update(oldSessionId, {
|
|
@@ -13222,7 +13570,7 @@ var BrowserstackService = class {
|
|
|
13222
13570
|
}
|
|
13223
13571
|
_updateJob(requestBody) {
|
|
13224
13572
|
return this._multiRemoteAction((sessionId, browserName) => {
|
|
13225
|
-
|
|
13573
|
+
BStackLogger.info(
|
|
13226
13574
|
browserName ? `Update multiremote job for browser "${browserName}" and sessionId ${sessionId}` : `Update job with sessionId ${sessionId}`
|
|
13227
13575
|
);
|
|
13228
13576
|
return this._update(sessionId, requestBody);
|
|
@@ -13248,7 +13596,7 @@ var BrowserstackService = class {
|
|
|
13248
13596
|
return Promise.resolve();
|
|
13249
13597
|
}
|
|
13250
13598
|
const sessionUrl = `${this._sessionBaseUrl}/${sessionId}.json`;
|
|
13251
|
-
|
|
13599
|
+
BStackLogger.debug(`Updating Browserstack session at ${sessionUrl} with request body: `, requestBody);
|
|
13252
13600
|
const encodedAuth = Buffer.from(`${this._config.user}:${this._config.key}`, "utf8").toString("base64");
|
|
13253
13601
|
const headers = {
|
|
13254
13602
|
"Content-Type": "application/json; charset=utf-8",
|
|
@@ -13273,7 +13621,7 @@ var BrowserstackService = class {
|
|
|
13273
13621
|
}
|
|
13274
13622
|
await this._multiRemoteAction(async (sessionId, browserName) => {
|
|
13275
13623
|
const sessionUrl = `${this._sessionBaseUrl}/${sessionId}.json`;
|
|
13276
|
-
|
|
13624
|
+
BStackLogger.debug(`Requesting Browserstack session URL at ${sessionUrl}`);
|
|
13277
13625
|
let browserUrl;
|
|
13278
13626
|
const encodedAuth = Buffer.from(`${this._config.user}:${this._config.key}`, "utf8").toString("base64");
|
|
13279
13627
|
const headers = {
|
|
@@ -13300,7 +13648,7 @@ var BrowserstackService = class {
|
|
|
13300
13648
|
}
|
|
13301
13649
|
const capabilities = getBrowserCapabilities(this._browser, this._caps, browserName);
|
|
13302
13650
|
const browserString = getBrowserDescription(capabilities);
|
|
13303
|
-
|
|
13651
|
+
BStackLogger.info(`${browserString} session: ${browserUrl}`);
|
|
13304
13652
|
});
|
|
13305
13653
|
}
|
|
13306
13654
|
async _setSessionName(suiteTitle, test) {
|
|
@@ -13349,7 +13697,8 @@ var BrowserstackService = class {
|
|
|
13349
13697
|
}
|
|
13350
13698
|
saveWorkerData() {
|
|
13351
13699
|
saveWorkerData({
|
|
13352
|
-
usageStats: usageStats_default.getInstance().getDataToSave()
|
|
13700
|
+
usageStats: usageStats_default.getInstance().getDataToSave(),
|
|
13701
|
+
reloadHappened: this._reloadHappened
|
|
13353
13702
|
});
|
|
13354
13703
|
}
|
|
13355
13704
|
};
|