@wdio/browserstack-service 9.27.2 → 9.28.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 +235 -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 +962 -642
- package/build/insights-handler.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.map +1 -1
- package/build/types.d.ts +8 -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
|
@@ -23,7 +23,7 @@ var init_package = __esm({
|
|
|
23
23
|
"package.json"() {
|
|
24
24
|
package_default = {
|
|
25
25
|
name: "@wdio/browserstack-service",
|
|
26
|
-
version: "9.27.
|
|
26
|
+
version: "9.27.2",
|
|
27
27
|
description: "WebdriverIO service for better Browserstack integration",
|
|
28
28
|
author: "Adam Bjerstedt <abjerstedt@gmail.com>",
|
|
29
29
|
homepage: "https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-browserstack-service",
|
|
@@ -97,7 +97,7 @@ var init_package = __esm({
|
|
|
97
97
|
});
|
|
98
98
|
|
|
99
99
|
// 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;
|
|
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, 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
101
|
var init_constants = __esm({
|
|
102
102
|
"src/constants.ts"() {
|
|
103
103
|
"use strict";
|
|
@@ -157,6 +157,17 @@ var init_constants = __esm({
|
|
|
157
157
|
"HTTP": "http"
|
|
158
158
|
};
|
|
159
159
|
SUPPORTED_BROWSERS_FOR_AI = ["chrome", "microsoftedge", "firefox"];
|
|
160
|
+
SUPPORTED_BROWSERS_FOR_ACCESSIBILITY = ["chrome", "chromefortesting", "safari"];
|
|
161
|
+
MIN_BROWSER_VERSIONS_A11Y = {
|
|
162
|
+
chrome: 95,
|
|
163
|
+
chromefortesting: 141,
|
|
164
|
+
safari: 18.4
|
|
165
|
+
};
|
|
166
|
+
MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK = {
|
|
167
|
+
chrome: 100,
|
|
168
|
+
chromefortesting: 141,
|
|
169
|
+
safari: 18.4
|
|
170
|
+
};
|
|
160
171
|
TCG_URL = "https://tcg.browserstack.com";
|
|
161
172
|
TCG_INFO = {
|
|
162
173
|
tcgRegion: "use",
|
|
@@ -268,34 +279,155 @@ var init_apiUtils = __esm({
|
|
|
268
279
|
}
|
|
269
280
|
});
|
|
270
281
|
|
|
282
|
+
// src/caCert.ts
|
|
283
|
+
import { setGlobalDispatcher, Agent } from "undici";
|
|
284
|
+
import tls from "node:tls";
|
|
285
|
+
import fs from "node:fs";
|
|
286
|
+
import os from "node:os";
|
|
287
|
+
import path from "node:path";
|
|
288
|
+
function derToPem(der) {
|
|
289
|
+
const b64 = der.toString("base64").replace(/(.{64})/g, "$1\n");
|
|
290
|
+
return `-----BEGIN CERTIFICATE-----
|
|
291
|
+
${b64}${b64.endsWith("\n") ? "" : "\n"}-----END CERTIFICATE-----
|
|
292
|
+
`;
|
|
293
|
+
}
|
|
294
|
+
function loadCaCertsAsPem(buf) {
|
|
295
|
+
if (buf.includes("-----BEGIN CERTIFICATE-----")) {
|
|
296
|
+
return buf.toString("utf8").match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g) || [];
|
|
297
|
+
}
|
|
298
|
+
return [derToPem(buf)];
|
|
299
|
+
}
|
|
300
|
+
function resolveCaCertPath(options) {
|
|
301
|
+
let p = process.env.BROWSERSTACK_EXTRA_CA_CERTS;
|
|
302
|
+
if ((!p || !p.trim()) && options?.proxyCaCertificate) {
|
|
303
|
+
p = options.proxyCaCertificate;
|
|
304
|
+
}
|
|
305
|
+
if (!p || !String(p).trim()) {
|
|
306
|
+
return void 0;
|
|
307
|
+
}
|
|
308
|
+
p = String(p).trim();
|
|
309
|
+
try {
|
|
310
|
+
if (fs.existsSync(p) && fs.statSync(p).isFile()) {
|
|
311
|
+
return p;
|
|
312
|
+
}
|
|
313
|
+
BStackLogger.warn(`proxyCaCertificate: path does not exist or is not a file, falling back to system trust store: ${p}`);
|
|
314
|
+
} catch (e) {
|
|
315
|
+
BStackLogger.warn(`proxyCaCertificate: failed to stat cert path ${p}: ${e.message}`);
|
|
316
|
+
}
|
|
317
|
+
return void 0;
|
|
318
|
+
}
|
|
319
|
+
function getMergedCa() {
|
|
320
|
+
return mergedCa;
|
|
321
|
+
}
|
|
322
|
+
function configureCaCertificate(options) {
|
|
323
|
+
if (configured) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
try {
|
|
327
|
+
const certPath = resolveCaCertPath(options);
|
|
328
|
+
if (!certPath) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
const buf = fs.readFileSync(certPath);
|
|
332
|
+
const isPem = buf.includes("-----BEGIN CERTIFICATE-----");
|
|
333
|
+
const pemCerts = loadCaCertsAsPem(buf);
|
|
334
|
+
if (!pemCerts.length) {
|
|
335
|
+
BStackLogger.warn(`proxyCaCertificate: no certificate found in ${certPath}; falling back to system trust store.`);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
mergedCa = [...tls.rootCertificates, ...pemCerts];
|
|
339
|
+
setGlobalDispatcher(new Agent({ connect: { ca: mergedCa } }));
|
|
340
|
+
configured = true;
|
|
341
|
+
BStackLogger.info(`proxyCaCertificate: trusting custom CA from ${certPath} (merged with system roots).`);
|
|
342
|
+
try {
|
|
343
|
+
if (!process.env.NODE_EXTRA_CA_CERTS) {
|
|
344
|
+
let nodeExtra = certPath;
|
|
345
|
+
if (!isPem) {
|
|
346
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "browserstack_sdk_ca_"));
|
|
347
|
+
nodeExtra = path.join(tmpDir, "ca.pem");
|
|
348
|
+
const fd = fs.openSync(nodeExtra, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL | (fs.constants.O_NOFOLLOW || 0), 384);
|
|
349
|
+
try {
|
|
350
|
+
fs.writeFileSync(fd, pemCerts.join(""));
|
|
351
|
+
} finally {
|
|
352
|
+
fs.closeSync(fd);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
process.env.NODE_EXTRA_CA_CERTS = nodeExtra;
|
|
356
|
+
}
|
|
357
|
+
} catch (e) {
|
|
358
|
+
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}`);
|
|
359
|
+
}
|
|
360
|
+
} catch (e) {
|
|
361
|
+
BStackLogger.warn(`proxyCaCertificate: setup failed, falling back to system trust store: ${e.message}`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
var mergedCa, configured;
|
|
365
|
+
var init_caCert = __esm({
|
|
366
|
+
"src/caCert.ts"() {
|
|
367
|
+
"use strict";
|
|
368
|
+
init_bstackLogger();
|
|
369
|
+
configured = false;
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
|
|
271
373
|
// src/fetchWrapper.ts
|
|
272
|
-
import { fetch as undiciFetch, ProxyAgent } from "undici";
|
|
273
|
-
|
|
274
|
-
const
|
|
374
|
+
import { fetch as undiciFetch, ProxyAgent, Agent as Agent2 } from "undici";
|
|
375
|
+
function getDispatcher(proxyUrl, connectTimeoutMs) {
|
|
376
|
+
const ca = getMergedCa();
|
|
377
|
+
const key = `${proxyUrl ?? "direct"}:${connectTimeoutMs ?? "default"}:${ca ? "ca" : "noca"}`;
|
|
378
|
+
let dispatcher = dispatcherCache.get(key);
|
|
379
|
+
if (!dispatcher) {
|
|
380
|
+
const connect = {};
|
|
381
|
+
if (connectTimeoutMs) {
|
|
382
|
+
connect.timeout = connectTimeoutMs;
|
|
383
|
+
}
|
|
384
|
+
if (proxyUrl) {
|
|
385
|
+
dispatcher = new ProxyAgent({ uri: proxyUrl, connect, ...ca ? { requestTls: { ca } } : {} });
|
|
386
|
+
} else {
|
|
387
|
+
if (ca) {
|
|
388
|
+
connect.ca = ca;
|
|
389
|
+
}
|
|
390
|
+
dispatcher = new Agent2({ connect });
|
|
391
|
+
}
|
|
392
|
+
dispatcherCache.set(key, dispatcher);
|
|
393
|
+
}
|
|
394
|
+
return dispatcher;
|
|
395
|
+
}
|
|
396
|
+
async function fetchWrap(input, init, options) {
|
|
397
|
+
const res = await _fetch(input, init, options);
|
|
275
398
|
if (!res.ok) {
|
|
276
399
|
throw new ResponseError(`Error response from server ${res.status}: ${await res.text()}`, res);
|
|
277
400
|
}
|
|
278
401
|
return res;
|
|
279
402
|
}
|
|
280
|
-
function _fetch(input, init) {
|
|
403
|
+
function _fetch(input, init, options) {
|
|
404
|
+
const connectTimeoutMs = options?.connectTimeoutMs;
|
|
281
405
|
const proxyUrl = process.env.HTTP_PROXY || process.env.HTTPS_PROXY;
|
|
282
406
|
if (proxyUrl) {
|
|
283
407
|
const noProxy = process.env.NO_PROXY && process.env.NO_PROXY.trim() ? process.env.NO_PROXY.trim().split(/[\s,;]+/) : [];
|
|
284
408
|
const request = new Request(input);
|
|
285
409
|
const url3 = new URL(request.url);
|
|
286
410
|
if (!noProxy.some((str) => url3.hostname.endsWith(str))) {
|
|
411
|
+
const dispatcher = getDispatcher(proxyUrl, connectTimeoutMs);
|
|
287
412
|
return undiciFetch(
|
|
288
413
|
request.url,
|
|
289
|
-
{ ...init, dispatcher
|
|
414
|
+
{ ...init, dispatcher }
|
|
290
415
|
);
|
|
291
416
|
}
|
|
292
417
|
}
|
|
418
|
+
if (connectTimeoutMs) {
|
|
419
|
+
return undiciFetch(
|
|
420
|
+
new Request(input).url,
|
|
421
|
+
{ ...init, dispatcher: getDispatcher(void 0, connectTimeoutMs) }
|
|
422
|
+
);
|
|
423
|
+
}
|
|
293
424
|
return fetch(input, init);
|
|
294
425
|
}
|
|
295
|
-
var ResponseError;
|
|
426
|
+
var ResponseError, dispatcherCache;
|
|
296
427
|
var init_fetchWrapper = __esm({
|
|
297
428
|
"src/fetchWrapper.ts"() {
|
|
298
429
|
"use strict";
|
|
430
|
+
init_caCert();
|
|
299
431
|
ResponseError = class extends Error {
|
|
300
432
|
response;
|
|
301
433
|
constructor(message, res) {
|
|
@@ -303,6 +435,7 @@ var init_fetchWrapper = __esm({
|
|
|
303
435
|
this.response = res;
|
|
304
436
|
}
|
|
305
437
|
};
|
|
438
|
+
dispatcherCache = /* @__PURE__ */ new Map();
|
|
306
439
|
}
|
|
307
440
|
});
|
|
308
441
|
|
|
@@ -460,26 +593,26 @@ var init_constants2 = __esm({
|
|
|
460
593
|
});
|
|
461
594
|
|
|
462
595
|
// src/cli/cliLogger.ts
|
|
463
|
-
import
|
|
464
|
-
import
|
|
596
|
+
import path2 from "node:path";
|
|
597
|
+
import fs2 from "node:fs";
|
|
465
598
|
import chalk from "chalk";
|
|
466
599
|
import logger from "@wdio/logger";
|
|
467
|
-
var log,
|
|
600
|
+
var log, BStackLogger2;
|
|
468
601
|
var init_cliLogger = __esm({
|
|
469
602
|
"src/cli/cliLogger.ts"() {
|
|
470
603
|
"use strict";
|
|
471
604
|
init_constants();
|
|
472
605
|
init_util();
|
|
473
606
|
log = logger("@wdio/browserstack-service/cli");
|
|
474
|
-
|
|
475
|
-
static logFilePath =
|
|
476
|
-
static logFolderPath =
|
|
607
|
+
BStackLogger2 = class {
|
|
608
|
+
static logFilePath = path2.join(process.cwd(), LOGS_FILE);
|
|
609
|
+
static logFolderPath = path2.join(process.cwd(), "logs");
|
|
477
610
|
static logFileStream;
|
|
478
611
|
static logToFile(logMessage, logLevel) {
|
|
479
612
|
try {
|
|
480
613
|
if (!this.logFileStream) {
|
|
481
614
|
this.ensureLogsFolder();
|
|
482
|
-
this.logFileStream =
|
|
615
|
+
this.logFileStream = fs2.createWriteStream(this.logFilePath, { flags: "a" });
|
|
483
616
|
}
|
|
484
617
|
if (this.logFileStream && this.logFileStream.writable) {
|
|
485
618
|
this.logFileStream.write(this.formatLog(logMessage, logLevel));
|
|
@@ -523,13 +656,13 @@ var init_cliLogger = __esm({
|
|
|
523
656
|
this.logFileStream = null;
|
|
524
657
|
}
|
|
525
658
|
static clearLogFile() {
|
|
526
|
-
if (
|
|
527
|
-
|
|
659
|
+
if (fs2.existsSync(this.logFilePath)) {
|
|
660
|
+
fs2.truncateSync(this.logFilePath);
|
|
528
661
|
}
|
|
529
662
|
}
|
|
530
663
|
static ensureLogsFolder() {
|
|
531
|
-
if (!
|
|
532
|
-
|
|
664
|
+
if (!fs2.existsSync(this.logFolderPath)) {
|
|
665
|
+
fs2.mkdirSync(this.logFolderPath);
|
|
533
666
|
}
|
|
534
667
|
}
|
|
535
668
|
};
|
|
@@ -587,16 +720,16 @@ var init_testFrameworkConstants = __esm({
|
|
|
587
720
|
});
|
|
588
721
|
|
|
589
722
|
// src/cli/cliUtils.ts
|
|
590
|
-
import
|
|
723
|
+
import fs3 from "node:fs";
|
|
591
724
|
import fsp from "node:fs/promises";
|
|
592
725
|
import { platform, arch, homedir } from "node:os";
|
|
593
|
-
import
|
|
726
|
+
import path3 from "node:path";
|
|
594
727
|
import util, { promisify } from "node:util";
|
|
595
728
|
import { exec } from "node:child_process";
|
|
596
729
|
import { Readable } from "node:stream";
|
|
597
730
|
import yauzl from "yauzl";
|
|
598
731
|
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;
|
|
732
|
+
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
733
|
var init_cliUtils = __esm({
|
|
601
734
|
"src/cli/cliUtils.ts"() {
|
|
602
735
|
"use strict";
|
|
@@ -613,6 +746,9 @@ var init_cliUtils = __esm({
|
|
|
613
746
|
CLI_DOWNLOAD_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
614
747
|
CLI_DOWNLOAD_TMP_PREFIX = "downloaded_file_";
|
|
615
748
|
CLI_DOWNLOAD_TMP_SUFFIX = ".zip";
|
|
749
|
+
CLI_CONNECT_TIMEOUT_MS = Number(process.env.BROWSERSTACK_CLI_CONNECT_TIMEOUT_MS) || 60 * 1e3;
|
|
750
|
+
CLI_FETCH_MAX_ATTEMPTS = 3;
|
|
751
|
+
CLI_FETCH_RETRY_BASE_DELAY_MS = 500;
|
|
616
752
|
CLIUtils = class _CLIUtils {
|
|
617
753
|
static automationFrameworkDetail = {};
|
|
618
754
|
static testFrameworkDetail = {};
|
|
@@ -699,10 +835,10 @@ var init_cliUtils = __esm({
|
|
|
699
835
|
return "ECMAScript";
|
|
700
836
|
}
|
|
701
837
|
static async setupCliPath(config) {
|
|
702
|
-
|
|
838
|
+
BStackLogger2.debug("Configuring Cli path.");
|
|
703
839
|
const developmentBinaryPath = process.env.SDK_CLI_BIN_PATH || null;
|
|
704
840
|
if (!isNullOrEmpty(developmentBinaryPath)) {
|
|
705
|
-
|
|
841
|
+
BStackLogger2.debug(`Development Cli Path: ${developmentBinaryPath}`);
|
|
706
842
|
return developmentBinaryPath;
|
|
707
843
|
}
|
|
708
844
|
try {
|
|
@@ -716,10 +852,10 @@ var init_cliUtils = __esm({
|
|
|
716
852
|
cliDir,
|
|
717
853
|
config
|
|
718
854
|
);
|
|
719
|
-
|
|
855
|
+
BStackLogger2.debug(`Resolved binary path: ${finalBinaryPath}`);
|
|
720
856
|
return finalBinaryPath;
|
|
721
857
|
} catch (err) {
|
|
722
|
-
|
|
858
|
+
BStackLogger2.warn(
|
|
723
859
|
`Error in setting up cli path directory, Exception: ${util.format(err)}`
|
|
724
860
|
);
|
|
725
861
|
}
|
|
@@ -727,18 +863,18 @@ var init_cliUtils = __esm({
|
|
|
727
863
|
}
|
|
728
864
|
static async checkAndUpdateCli(existingCliPath, cliDir, config) {
|
|
729
865
|
if (process.env.BROWSERSTACK_TESTHUB_JWT) {
|
|
730
|
-
|
|
866
|
+
BStackLogger2.debug(
|
|
731
867
|
`Worker process detected, skipping CLI update. Using existing: ${existingCliPath}`
|
|
732
868
|
);
|
|
733
|
-
if (existingCliPath &&
|
|
869
|
+
if (existingCliPath && fs3.existsSync(existingCliPath)) {
|
|
734
870
|
return existingCliPath;
|
|
735
871
|
}
|
|
736
|
-
|
|
872
|
+
BStackLogger2.warn(
|
|
737
873
|
"Worker process has no existing CLI binary, attempting download as fallback."
|
|
738
874
|
);
|
|
739
875
|
}
|
|
740
876
|
PerformanceTester.start(EVENTS.SDK_CLI_CHECK_UPDATE);
|
|
741
|
-
|
|
877
|
+
BStackLogger2.info(`Current CLI Path Found: ${existingCliPath}`);
|
|
742
878
|
const queryParams = {
|
|
743
879
|
sdk_version: _CLIUtils.getSdkVersion(),
|
|
744
880
|
os: platform(),
|
|
@@ -748,7 +884,7 @@ var init_cliUtils = __esm({
|
|
|
748
884
|
};
|
|
749
885
|
if (!isNullOrEmpty(existingCliPath)) {
|
|
750
886
|
if (this.isBinaryBusy(existingCliPath)) {
|
|
751
|
-
|
|
887
|
+
BStackLogger2.warn(`Existing binary is currently in use, skipping update: ${existingCliPath}`);
|
|
752
888
|
PerformanceTester.end(EVENTS.SDK_CLI_CHECK_UPDATE);
|
|
753
889
|
return existingCliPath;
|
|
754
890
|
}
|
|
@@ -756,7 +892,7 @@ var init_cliUtils = __esm({
|
|
|
756
892
|
`${existingCliPath} version`
|
|
757
893
|
);
|
|
758
894
|
if (version3.toLowerCase().includes("text file busy")) {
|
|
759
|
-
|
|
895
|
+
BStackLogger2.warn(`Binary busy during version check, skipping update: ${existingCliPath}`);
|
|
760
896
|
PerformanceTester.end(EVENTS.SDK_CLI_CHECK_UPDATE);
|
|
761
897
|
return existingCliPath;
|
|
762
898
|
}
|
|
@@ -764,12 +900,12 @@ var init_cliUtils = __esm({
|
|
|
764
900
|
}
|
|
765
901
|
const response = await this.requestToUpdateCLI(queryParams, config);
|
|
766
902
|
if (nestedKeyValue(response, ["updated_cli_version"])) {
|
|
767
|
-
|
|
903
|
+
BStackLogger2.debug(
|
|
768
904
|
`Need to update binary, current binary version: ${queryParams.cli_version}`
|
|
769
905
|
);
|
|
770
906
|
const browserStackBinaryUrl = process.env.BROWSERSTACK_BINARY_URL || null;
|
|
771
907
|
if (!isNullOrEmpty(browserStackBinaryUrl)) {
|
|
772
|
-
|
|
908
|
+
BStackLogger2.debug(
|
|
773
909
|
`Using BROWSERSTACK_BINARY_URL: ${browserStackBinaryUrl}`
|
|
774
910
|
);
|
|
775
911
|
response.url = browserStackBinaryUrl;
|
|
@@ -790,13 +926,13 @@ var init_cliUtils = __esm({
|
|
|
790
926
|
if (isNullOrEmpty(writableDir)) {
|
|
791
927
|
throw new Error("No writable directory available for the CLI");
|
|
792
928
|
}
|
|
793
|
-
const cliDirPath =
|
|
794
|
-
if (!
|
|
929
|
+
const cliDirPath = path3.join(writableDir, "cli");
|
|
930
|
+
if (!fs3.existsSync(cliDirPath)) {
|
|
795
931
|
createDir(cliDirPath);
|
|
796
932
|
}
|
|
797
933
|
return cliDirPath;
|
|
798
934
|
} catch (err) {
|
|
799
|
-
|
|
935
|
+
BStackLogger2.error(
|
|
800
936
|
`Error in getting writable directory, writableDir=${util.format(err)}`
|
|
801
937
|
);
|
|
802
938
|
return "";
|
|
@@ -805,39 +941,39 @@ var init_cliUtils = __esm({
|
|
|
805
941
|
static getWritableDir() {
|
|
806
942
|
const writableDirOptions = [
|
|
807
943
|
process.env.BROWSERSTACK_FILES_DIR,
|
|
808
|
-
|
|
809
|
-
|
|
944
|
+
path3.join(homedir(), ".browserstack"),
|
|
945
|
+
path3.join("tmp", ".browserstack")
|
|
810
946
|
];
|
|
811
|
-
for (const
|
|
812
|
-
if (isNullOrEmpty(
|
|
947
|
+
for (const path22 of writableDirOptions) {
|
|
948
|
+
if (isNullOrEmpty(path22)) {
|
|
813
949
|
continue;
|
|
814
950
|
}
|
|
815
951
|
try {
|
|
816
|
-
if (
|
|
817
|
-
|
|
818
|
-
if (!isWritable(
|
|
819
|
-
|
|
820
|
-
const success = setReadWriteAccess(
|
|
952
|
+
if (fs3.existsSync(path22)) {
|
|
953
|
+
BStackLogger2.debug(`File ${path22} already exist`);
|
|
954
|
+
if (!isWritable(path22)) {
|
|
955
|
+
BStackLogger2.debug(`Giving write permission to ${path22}`);
|
|
956
|
+
const success = setReadWriteAccess(path22);
|
|
821
957
|
if (!isTrue(success)) {
|
|
822
|
-
|
|
823
|
-
`Unable to provide write permission to ${
|
|
958
|
+
BStackLogger2.warn(
|
|
959
|
+
`Unable to provide write permission to ${path22}`
|
|
824
960
|
);
|
|
825
961
|
}
|
|
826
962
|
}
|
|
827
963
|
} else {
|
|
828
|
-
|
|
829
|
-
createDir(
|
|
830
|
-
|
|
831
|
-
const success = setReadWriteAccess(
|
|
964
|
+
BStackLogger2.debug(`File does not exist: ${path22}`);
|
|
965
|
+
createDir(path22);
|
|
966
|
+
BStackLogger2.debug(`Giving write permission to ${path22}`);
|
|
967
|
+
const success = setReadWriteAccess(path22);
|
|
832
968
|
if (!isTrue(success)) {
|
|
833
|
-
|
|
834
|
-
`Unable to provide write permission to ${
|
|
969
|
+
BStackLogger2.warn(
|
|
970
|
+
`Unable to provide write permission to ${path22}`
|
|
835
971
|
);
|
|
836
972
|
}
|
|
837
973
|
}
|
|
838
|
-
return
|
|
974
|
+
return path22;
|
|
839
975
|
} catch (err) {
|
|
840
|
-
|
|
976
|
+
BStackLogger2.error(
|
|
841
977
|
`Unable to get writable directory, exception ${util.format(err)}`
|
|
842
978
|
);
|
|
843
979
|
}
|
|
@@ -846,16 +982,16 @@ var init_cliUtils = __esm({
|
|
|
846
982
|
}
|
|
847
983
|
static getExistingCliPath(cliDir) {
|
|
848
984
|
try {
|
|
849
|
-
if (!
|
|
985
|
+
if (!fs3.existsSync(cliDir) || !fs3.statSync(cliDir).isDirectory()) {
|
|
850
986
|
return "";
|
|
851
987
|
}
|
|
852
|
-
const allBinaries =
|
|
853
|
-
(filePath) =>
|
|
988
|
+
const allBinaries = fs3.readdirSync(cliDir).map((file) => path3.join(cliDir, file)).filter(
|
|
989
|
+
(filePath) => fs3.statSync(filePath).isFile() && path3.basename(filePath).startsWith("binary-")
|
|
854
990
|
);
|
|
855
991
|
if (allBinaries.length > 0) {
|
|
856
992
|
const latestBinary = allBinaries.map((filePath) => ({
|
|
857
993
|
filePath,
|
|
858
|
-
mtime:
|
|
994
|
+
mtime: fs3.statSync(filePath).mtime
|
|
859
995
|
})).reduce(
|
|
860
996
|
(latest, current) => {
|
|
861
997
|
if (!latest || !latest.mtime) {
|
|
@@ -872,7 +1008,7 @@ var init_cliUtils = __esm({
|
|
|
872
1008
|
}
|
|
873
1009
|
return "";
|
|
874
1010
|
} catch (err) {
|
|
875
|
-
|
|
1011
|
+
BStackLogger2.error(`Error while reading CLI path: ${util.format(err)}`);
|
|
876
1012
|
return "";
|
|
877
1013
|
}
|
|
878
1014
|
}
|
|
@@ -883,22 +1019,51 @@ var init_cliUtils = __esm({
|
|
|
883
1019
|
if (platform() === "darwin") {
|
|
884
1020
|
return false;
|
|
885
1021
|
}
|
|
886
|
-
if (!
|
|
1022
|
+
if (!fs3.existsSync(binaryPath)) {
|
|
887
1023
|
return false;
|
|
888
1024
|
}
|
|
889
1025
|
try {
|
|
890
|
-
const fd =
|
|
891
|
-
|
|
1026
|
+
const fd = fs3.openSync(binaryPath, "r+");
|
|
1027
|
+
fs3.closeSync(fd);
|
|
892
1028
|
return false;
|
|
893
1029
|
} catch (err) {
|
|
894
1030
|
if (BINARY_BUSY_ERROR_CODES.includes(err.code)) {
|
|
895
|
-
|
|
1031
|
+
BStackLogger2.debug(`Binary is busy: ${binaryPath}`);
|
|
896
1032
|
return true;
|
|
897
1033
|
}
|
|
898
|
-
|
|
1034
|
+
BStackLogger2.debug(`Error checking if binary is busy: ${err.message}`);
|
|
899
1035
|
return false;
|
|
900
1036
|
}
|
|
901
1037
|
}
|
|
1038
|
+
/**
|
|
1039
|
+
* fetch wrapper for CLI network calls that (a) raises undici's connect timeout
|
|
1040
|
+
* above the non-overridable 10s default of global fetch and (b) retries a few
|
|
1041
|
+
* times with linear backoff on transient connection failures. Both are needed
|
|
1042
|
+
* for reliability in constrained CI/containerised networks (SDK-6152).
|
|
1043
|
+
*/
|
|
1044
|
+
static fetchWithRetry = async (input, init, label) => {
|
|
1045
|
+
let lastError;
|
|
1046
|
+
for (let attempt = 1; attempt <= CLI_FETCH_MAX_ATTEMPTS; attempt++) {
|
|
1047
|
+
try {
|
|
1048
|
+
return await _fetch(input, init, { connectTimeoutMs: CLI_CONNECT_TIMEOUT_MS });
|
|
1049
|
+
} catch (err) {
|
|
1050
|
+
lastError = err;
|
|
1051
|
+
const reason = (
|
|
1052
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1053
|
+
err?.cause?.code || err?.code || err?.message
|
|
1054
|
+
);
|
|
1055
|
+
BStackLogger2.warn(
|
|
1056
|
+
`${label} attempt ${attempt}/${CLI_FETCH_MAX_ATTEMPTS} failed: ${reason}`
|
|
1057
|
+
);
|
|
1058
|
+
if (attempt < CLI_FETCH_MAX_ATTEMPTS) {
|
|
1059
|
+
await new Promise(
|
|
1060
|
+
(resolve) => setTimeout(resolve, CLI_FETCH_RETRY_BASE_DELAY_MS * attempt)
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
throw lastError;
|
|
1066
|
+
};
|
|
902
1067
|
static requestToUpdateCLI = async (queryParams, config) => {
|
|
903
1068
|
const params = new URLSearchParams(queryParams);
|
|
904
1069
|
const requestInit = {
|
|
@@ -907,12 +1072,13 @@ var init_cliUtils = __esm({
|
|
|
907
1072
|
Authorization: `Basic ${Buffer.from(`${getBrowserStackUser(config)}:${getBrowserStackKey(config)}`).toString("base64")}`
|
|
908
1073
|
}
|
|
909
1074
|
};
|
|
910
|
-
const response = await
|
|
1075
|
+
const response = await this.fetchWithRetry(
|
|
911
1076
|
`${APIUtils.BROWSERSTACK_AUTOMATE_API_URL}/${UPDATED_CLI_ENDPOINT}?${params.toString()}`,
|
|
912
|
-
requestInit
|
|
1077
|
+
requestInit,
|
|
1078
|
+
"update_cli request"
|
|
913
1079
|
);
|
|
914
1080
|
const jsonResponse = await response.json();
|
|
915
|
-
|
|
1081
|
+
BStackLogger2.debug(`response ${JSON.stringify(jsonResponse)}`);
|
|
916
1082
|
return jsonResponse;
|
|
917
1083
|
};
|
|
918
1084
|
static runShellCommand(cmdCommand, workingDir = "") {
|
|
@@ -934,11 +1100,11 @@ var init_cliUtils = __esm({
|
|
|
934
1100
|
});
|
|
935
1101
|
}
|
|
936
1102
|
static downloadLatestBinary = async (binDownloadUrl, cliDir) => {
|
|
937
|
-
const lockPath =
|
|
1103
|
+
const lockPath = path3.join(cliDir, "download.lock");
|
|
938
1104
|
const sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
939
1105
|
const parseLockFile = () => {
|
|
940
1106
|
try {
|
|
941
|
-
const content =
|
|
1107
|
+
const content = fs3.readFileSync(lockPath, "utf8").trim();
|
|
942
1108
|
const [pidLine, timestampLine] = content.split("\n");
|
|
943
1109
|
const pid = Number.parseInt(pidLine, 10);
|
|
944
1110
|
const timestamp = Number.parseInt(timestampLine, 10);
|
|
@@ -962,20 +1128,20 @@ var init_cliUtils = __esm({
|
|
|
962
1128
|
const start = Date.now();
|
|
963
1129
|
while (true) {
|
|
964
1130
|
try {
|
|
965
|
-
const fd =
|
|
1131
|
+
const fd = fs3.openSync(lockPath, "wx");
|
|
966
1132
|
try {
|
|
967
|
-
|
|
1133
|
+
fs3.writeFileSync(fd, `${process.pid}
|
|
968
1134
|
${Date.now()}
|
|
969
1135
|
`);
|
|
970
1136
|
} catch {
|
|
971
1137
|
}
|
|
972
1138
|
return () => {
|
|
973
1139
|
try {
|
|
974
|
-
|
|
1140
|
+
fs3.closeSync(fd);
|
|
975
1141
|
} catch {
|
|
976
1142
|
}
|
|
977
1143
|
try {
|
|
978
|
-
|
|
1144
|
+
fs3.unlinkSync(lockPath);
|
|
979
1145
|
} catch {
|
|
980
1146
|
}
|
|
981
1147
|
};
|
|
@@ -987,19 +1153,19 @@ ${Date.now()}
|
|
|
987
1153
|
const lockAge = Date.now() - lockMeta.timestamp;
|
|
988
1154
|
const running = isProcessRunning(lockMeta.pid);
|
|
989
1155
|
if (!running || lockAge > timeoutMs) {
|
|
990
|
-
|
|
1156
|
+
BStackLogger2.warn(
|
|
991
1157
|
`Stale CLI download lock detected (pid=${lockMeta.pid}, age=${lockAge}ms). Removing lock.`
|
|
992
1158
|
);
|
|
993
1159
|
try {
|
|
994
|
-
|
|
1160
|
+
fs3.unlinkSync(lockPath);
|
|
995
1161
|
} catch {
|
|
996
1162
|
}
|
|
997
1163
|
continue;
|
|
998
1164
|
}
|
|
999
1165
|
}
|
|
1000
1166
|
const existingBinary = _CLIUtils.getExistingCliPath(cliDir);
|
|
1001
|
-
if (existingBinary &&
|
|
1002
|
-
|
|
1167
|
+
if (existingBinary && fs3.existsSync(existingBinary) && fs3.statSync(existingBinary).size > 0) {
|
|
1168
|
+
BStackLogger2.debug(
|
|
1003
1169
|
`Binary appeared while waiting for lock: ${existingBinary}`
|
|
1004
1170
|
);
|
|
1005
1171
|
return { alreadyExists: existingBinary };
|
|
@@ -1020,16 +1186,16 @@ ${Date.now()}
|
|
|
1020
1186
|
try {
|
|
1021
1187
|
const now2 = Date.now();
|
|
1022
1188
|
const tmpExtractRe = /\.tmp\.\d+$/;
|
|
1023
|
-
for (const entry of
|
|
1189
|
+
for (const entry of fs3.readdirSync(cliDir)) {
|
|
1024
1190
|
const isDownloadZip = entry.startsWith(CLI_DOWNLOAD_TMP_PREFIX) && entry.endsWith(CLI_DOWNLOAD_TMP_SUFFIX);
|
|
1025
1191
|
const isExtractTmp = tmpExtractRe.test(entry);
|
|
1026
1192
|
if (!isDownloadZip && !isExtractTmp) {
|
|
1027
1193
|
continue;
|
|
1028
1194
|
}
|
|
1029
|
-
const filePath =
|
|
1195
|
+
const filePath = path3.join(cliDir, entry);
|
|
1030
1196
|
let stats;
|
|
1031
1197
|
try {
|
|
1032
|
-
stats =
|
|
1198
|
+
stats = fs3.statSync(filePath);
|
|
1033
1199
|
} catch {
|
|
1034
1200
|
continue;
|
|
1035
1201
|
}
|
|
@@ -1037,21 +1203,21 @@ ${Date.now()}
|
|
|
1037
1203
|
continue;
|
|
1038
1204
|
}
|
|
1039
1205
|
try {
|
|
1040
|
-
|
|
1206
|
+
fs3.unlinkSync(filePath);
|
|
1041
1207
|
} catch (err) {
|
|
1042
|
-
|
|
1208
|
+
BStackLogger2.debug(
|
|
1043
1209
|
`Failed to delete temp CLI file ${filePath}: ${util.format(err)}`
|
|
1044
1210
|
);
|
|
1045
1211
|
}
|
|
1046
1212
|
}
|
|
1047
1213
|
} catch (err) {
|
|
1048
|
-
|
|
1214
|
+
BStackLogger2.debug(
|
|
1049
1215
|
`Failed to scan temp CLI files in ${cliDir}: ${util.format(err)}`
|
|
1050
1216
|
);
|
|
1051
1217
|
}
|
|
1052
1218
|
};
|
|
1053
1219
|
PerformanceTester.start(EVENTS.SDK_CLI_DOWNLOAD);
|
|
1054
|
-
|
|
1220
|
+
BStackLogger2.debug(`Downloading SDK binary from: ${binDownloadUrl}`);
|
|
1055
1221
|
let downloadEnded = false;
|
|
1056
1222
|
const endDownload = (success = true, errMsg) => {
|
|
1057
1223
|
if (downloadEnded) {
|
|
@@ -1077,8 +1243,8 @@ ${Date.now()}
|
|
|
1077
1243
|
}
|
|
1078
1244
|
releaseLock = lockResult;
|
|
1079
1245
|
const existingBinary = _CLIUtils.getExistingCliPath(cliDir);
|
|
1080
|
-
if (existingBinary &&
|
|
1081
|
-
|
|
1246
|
+
if (existingBinary && fs3.existsSync(existingBinary) && fs3.statSync(existingBinary).size > 0) {
|
|
1247
|
+
BStackLogger2.debug(
|
|
1082
1248
|
`Binary already exists after acquiring lock: ${existingBinary}`
|
|
1083
1249
|
);
|
|
1084
1250
|
endDownload();
|
|
@@ -1086,11 +1252,11 @@ ${Date.now()}
|
|
|
1086
1252
|
return existingBinary;
|
|
1087
1253
|
}
|
|
1088
1254
|
cleanupTemporaryDownloads();
|
|
1089
|
-
const zipFilePath =
|
|
1255
|
+
const zipFilePath = path3.join(
|
|
1090
1256
|
cliDir,
|
|
1091
1257
|
`${CLI_DOWNLOAD_TMP_PREFIX}${process.pid}_${Date.now()}${CLI_DOWNLOAD_TMP_SUFFIX}`
|
|
1092
1258
|
);
|
|
1093
|
-
const downloadedFileStream =
|
|
1259
|
+
const downloadedFileStream = fs3.createWriteStream(zipFilePath);
|
|
1094
1260
|
return new Promise((resolve, reject) => {
|
|
1095
1261
|
const processDownload = async () => {
|
|
1096
1262
|
const abortController = new AbortController();
|
|
@@ -1100,9 +1266,11 @@ ${Date.now()}
|
|
|
1100
1266
|
);
|
|
1101
1267
|
let response;
|
|
1102
1268
|
try {
|
|
1103
|
-
response = await _fetch(
|
|
1104
|
-
|
|
1105
|
-
|
|
1269
|
+
response = await _fetch(
|
|
1270
|
+
binDownloadUrl,
|
|
1271
|
+
{ signal: abortController.signal },
|
|
1272
|
+
{ connectTimeoutMs: CLI_CONNECT_TIMEOUT_MS }
|
|
1273
|
+
);
|
|
1106
1274
|
} finally {
|
|
1107
1275
|
clearTimeout(timeout);
|
|
1108
1276
|
}
|
|
@@ -1110,7 +1278,7 @@ ${Date.now()}
|
|
|
1110
1278
|
throw new Error("No response body received");
|
|
1111
1279
|
}
|
|
1112
1280
|
downloadedFileStream.on("error", function(err) {
|
|
1113
|
-
|
|
1281
|
+
BStackLogger2.error(
|
|
1114
1282
|
`Got Error while downloading cli binary file: ${err}`
|
|
1115
1283
|
);
|
|
1116
1284
|
endDownload(false, util.format(err));
|
|
@@ -1139,7 +1307,7 @@ ${Date.now()}
|
|
|
1139
1307
|
}
|
|
1140
1308
|
);
|
|
1141
1309
|
} catch (err) {
|
|
1142
|
-
|
|
1310
|
+
BStackLogger2.error(
|
|
1143
1311
|
`Got Error in cli binary downloading request ${util.format(err)}`
|
|
1144
1312
|
);
|
|
1145
1313
|
endDownload(false, util.format(err));
|
|
@@ -1152,7 +1320,7 @@ ${Date.now()}
|
|
|
1152
1320
|
} catch (err) {
|
|
1153
1321
|
releaseLock?.();
|
|
1154
1322
|
endDownload(false, util.format(err));
|
|
1155
|
-
|
|
1323
|
+
BStackLogger2.debug(
|
|
1156
1324
|
`Failed to download binary, Exception: ${util.format(err)}`
|
|
1157
1325
|
);
|
|
1158
1326
|
return null;
|
|
@@ -1172,17 +1340,17 @@ ${Date.now()}
|
|
|
1172
1340
|
zipfile.readEntry();
|
|
1173
1341
|
return;
|
|
1174
1342
|
}
|
|
1175
|
-
const candidatePath =
|
|
1176
|
-
const resolvedCandidate =
|
|
1177
|
-
const resolvedDir =
|
|
1343
|
+
const candidatePath = path3.join(cliDir, entry.fileName);
|
|
1344
|
+
const resolvedCandidate = path3.resolve(candidatePath);
|
|
1345
|
+
const resolvedDir = path3.resolve(cliDir) + path3.sep;
|
|
1178
1346
|
if (!resolvedCandidate.startsWith(resolvedDir)) {
|
|
1179
1347
|
zipfile.close();
|
|
1180
1348
|
reject(new Error(`Zip-slip detected: entry "${entry.fileName}" resolves outside ${cliDir}`));
|
|
1181
1349
|
return;
|
|
1182
1350
|
}
|
|
1183
|
-
const isBinaryEntry =
|
|
1351
|
+
const isBinaryEntry = path3.basename(entry.fileName).startsWith("binary-");
|
|
1184
1352
|
if (!isBinaryEntry) {
|
|
1185
|
-
const directStream =
|
|
1353
|
+
const directStream = fs3.createWriteStream(candidatePath);
|
|
1186
1354
|
directStream.on("error", (writeErr) => {
|
|
1187
1355
|
zipfile.close();
|
|
1188
1356
|
reject(writeErr);
|
|
@@ -1204,8 +1372,8 @@ ${Date.now()}
|
|
|
1204
1372
|
return;
|
|
1205
1373
|
}
|
|
1206
1374
|
const finalPath = candidatePath;
|
|
1207
|
-
const tempPath =
|
|
1208
|
-
const writeStream =
|
|
1375
|
+
const tempPath = path3.join(cliDir, `${entry.fileName}.tmp.${process.pid}`);
|
|
1376
|
+
const writeStream = fs3.createWriteStream(tempPath);
|
|
1209
1377
|
let writeStreamErrored = false;
|
|
1210
1378
|
writeStream.on("error", (writeErr) => {
|
|
1211
1379
|
writeStreamErrored = true;
|
|
@@ -1226,7 +1394,7 @@ ${Date.now()}
|
|
|
1226
1394
|
if (renameErr.code !== "EXDEV") {
|
|
1227
1395
|
throw renameErr;
|
|
1228
1396
|
}
|
|
1229
|
-
|
|
1397
|
+
BStackLogger2.warn(`Atomic rename failed (cross-device), falling back to copy: ${renameErr.message}`);
|
|
1230
1398
|
await fsp.copyFile(tempPath, finalPath);
|
|
1231
1399
|
await fsp.unlink(tempPath).catch(() => {
|
|
1232
1400
|
});
|
|
@@ -1263,7 +1431,7 @@ ${Date.now()}
|
|
|
1263
1431
|
});
|
|
1264
1432
|
zipfile.once("end", () => {
|
|
1265
1433
|
fsp.unlink(zipFilePath).catch(() => {
|
|
1266
|
-
|
|
1434
|
+
BStackLogger2.warn(`Failed to delete zip file: ${zipFilePath}`);
|
|
1267
1435
|
});
|
|
1268
1436
|
if (!resolvedBinaryPath) {
|
|
1269
1437
|
zipfile.close();
|
|
@@ -1294,7 +1462,7 @@ ${Date.now()}
|
|
|
1294
1462
|
}
|
|
1295
1463
|
static setFrameworkDetail(testFramework, automationFramework) {
|
|
1296
1464
|
if (!testFramework || !automationFramework) {
|
|
1297
|
-
|
|
1465
|
+
BStackLogger2.debug(
|
|
1298
1466
|
`Test or Automation framework not provided testFramework=${testFramework}, automationFramework=${automationFramework}`
|
|
1299
1467
|
);
|
|
1300
1468
|
}
|
|
@@ -1376,12 +1544,12 @@ ${Date.now()}
|
|
|
1376
1544
|
|
|
1377
1545
|
// src/instrumentation/performance/performance-tester.ts
|
|
1378
1546
|
import { createObjectCsvWriter } from "csv-writer";
|
|
1379
|
-
import
|
|
1547
|
+
import fs4 from "node:fs";
|
|
1380
1548
|
import fsPromise from "node:fs/promises";
|
|
1381
1549
|
import { performance, PerformanceObserver } from "node:perf_hooks";
|
|
1382
1550
|
import util2 from "node:util";
|
|
1383
1551
|
import worker from "node:worker_threads";
|
|
1384
|
-
import
|
|
1552
|
+
import path4 from "node:path";
|
|
1385
1553
|
import { arch as arch2, hostname, platform as platform2, type, version } from "node:os";
|
|
1386
1554
|
var PerformanceTester;
|
|
1387
1555
|
var init_performance_tester = __esm({
|
|
@@ -1406,11 +1574,11 @@ var init_performance_tester = __esm({
|
|
|
1406
1574
|
static browser;
|
|
1407
1575
|
static scenarioThatRan;
|
|
1408
1576
|
static jsonReportDirName = "performance-report";
|
|
1409
|
-
static jsonReportDirPath =
|
|
1577
|
+
static jsonReportDirPath = path4.join(process.cwd(), "logs", this.jsonReportDirName);
|
|
1410
1578
|
static jsonReportFileName = `${this.jsonReportDirPath}/performance-report-${_PerformanceTester.getProcessId()}.json`;
|
|
1411
1579
|
static startMonitoring(csvName = "performance-report.csv") {
|
|
1412
|
-
if (!
|
|
1413
|
-
|
|
1580
|
+
if (!fs4.existsSync(this.jsonReportDirPath)) {
|
|
1581
|
+
fs4.mkdirSync(this.jsonReportDirPath, { recursive: true });
|
|
1414
1582
|
}
|
|
1415
1583
|
this._observer = new PerformanceObserver((list) => {
|
|
1416
1584
|
list.getEntries().filter((entry) => entry.entryType === "measure").forEach(
|
|
@@ -1420,10 +1588,10 @@ var init_performance_tester = __esm({
|
|
|
1420
1588
|
if (typeof finalEntry.startTime === "number" && typeof performance.timeOrigin === "number") {
|
|
1421
1589
|
const originalStartTime = finalEntry.startTime;
|
|
1422
1590
|
finalEntry.startTime = performance.timeOrigin + finalEntry.startTime;
|
|
1423
|
-
|
|
1591
|
+
BStackLogger.debug(`Timestamp conversion for ${entry.name}: ${originalStartTime} -> ${finalEntry.startTime} (timeOrigin: ${performance.timeOrigin})`);
|
|
1424
1592
|
}
|
|
1425
1593
|
} catch (e) {
|
|
1426
|
-
|
|
1594
|
+
BStackLogger.debug(`Error converting startTime to epoch: ${util2.format(e)}`);
|
|
1427
1595
|
}
|
|
1428
1596
|
if (this.details[entry.name]) {
|
|
1429
1597
|
finalEntry = Object.assign(finalEntry, this.details[entry.name]);
|
|
@@ -1463,7 +1631,7 @@ var init_performance_tester = __esm({
|
|
|
1463
1631
|
const timeTaken = methods.reduce((a, c) => {
|
|
1464
1632
|
return times[c] + (a || 0);
|
|
1465
1633
|
}, 0);
|
|
1466
|
-
|
|
1634
|
+
BStackLogger.debug(`Time for ${methods} is ${timeTaken}`);
|
|
1467
1635
|
return timeTaken;
|
|
1468
1636
|
}
|
|
1469
1637
|
static async stopAndGenerate(filename = "performance-own.html") {
|
|
@@ -1475,7 +1643,7 @@ var init_performance_tester = __esm({
|
|
|
1475
1643
|
const finalJSONStr = eventsJson.slice(1, -1) + ",";
|
|
1476
1644
|
await fsPromise.appendFile(this.jsonReportFileName, finalJSONStr);
|
|
1477
1645
|
} catch (er) {
|
|
1478
|
-
|
|
1646
|
+
BStackLogger.debug(`Failed to write events of the worker to ${this.jsonReportFileName}: ${util2.format(er)}`);
|
|
1479
1647
|
}
|
|
1480
1648
|
this._observer.disconnect();
|
|
1481
1649
|
if (!process.env[PERF_MEASUREMENT_ENV]) {
|
|
@@ -1484,12 +1652,12 @@ var init_performance_tester = __esm({
|
|
|
1484
1652
|
this.started = false;
|
|
1485
1653
|
this.generateCSV(this._events);
|
|
1486
1654
|
const content = this.generateReport(this._events);
|
|
1487
|
-
const dir =
|
|
1655
|
+
const dir = path4.join(process.cwd(), filename);
|
|
1488
1656
|
try {
|
|
1489
1657
|
await fsPromise.writeFile(dir, content);
|
|
1490
|
-
|
|
1658
|
+
BStackLogger.info(`Performance report is at ${path4}`);
|
|
1491
1659
|
} catch (err) {
|
|
1492
|
-
|
|
1660
|
+
BStackLogger.error(`Error in writing html ${util2.format(err)}`);
|
|
1493
1661
|
}
|
|
1494
1662
|
}
|
|
1495
1663
|
static generateReport(entries) {
|
|
@@ -1520,7 +1688,7 @@ var init_performance_tester = __esm({
|
|
|
1520
1688
|
time: value
|
|
1521
1689
|
};
|
|
1522
1690
|
});
|
|
1523
|
-
this._csvWriter.writeRecords(dat).then(() =>
|
|
1691
|
+
this._csvWriter.writeRecords(dat).then(() => BStackLogger.info("Performance CSV report generated successfully")).catch((error) => console.error(error));
|
|
1524
1692
|
}
|
|
1525
1693
|
static Measure(label, details = {}) {
|
|
1526
1694
|
const self = this;
|
|
@@ -1654,16 +1822,16 @@ var init_performance_tester = __esm({
|
|
|
1654
1822
|
this.start(EVENTS.SDK_SEND_KEY_METRICS);
|
|
1655
1823
|
try {
|
|
1656
1824
|
const workerId = `${process.pid}`;
|
|
1657
|
-
|
|
1825
|
+
BStackLogger.debug(`[Performance Upload] Starting upload for worker ${workerId}`);
|
|
1658
1826
|
this.start(EVENTS.SDK_KEY_METRICS_PREPARATION);
|
|
1659
1827
|
let measures = [];
|
|
1660
1828
|
if (await fsPromise.access(this.jsonReportDirPath).then(() => true).catch(() => false)) {
|
|
1661
|
-
const files = (await fsPromise.readdir(this.jsonReportDirPath)).map((file) =>
|
|
1829
|
+
const files = (await fsPromise.readdir(this.jsonReportDirPath)).map((file) => path4.resolve(this.jsonReportDirPath, file));
|
|
1662
1830
|
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
1831
|
}
|
|
1664
|
-
|
|
1832
|
+
BStackLogger.debug(`[Performance Upload] Total events from files: ${measures.length}`);
|
|
1665
1833
|
if (this._measuredEvents.length > 0) {
|
|
1666
|
-
|
|
1834
|
+
BStackLogger.debug(`[Performance Upload] Adding ${this._measuredEvents.length} in-memory events`);
|
|
1667
1835
|
measures = measures.concat(
|
|
1668
1836
|
this._measuredEvents.map((e) => {
|
|
1669
1837
|
if (typeof e.toJSON === "function") {
|
|
@@ -1724,10 +1892,10 @@ var init_performance_tester = __esm({
|
|
|
1724
1892
|
},
|
|
1725
1893
|
body: JSON.stringify(payload)
|
|
1726
1894
|
});
|
|
1727
|
-
|
|
1895
|
+
BStackLogger.debug(`[Performance Upload] Successfully uploaded to EDS: ${util2.format(await result.text())}`);
|
|
1728
1896
|
this.end(EVENTS.SDK_SEND_KEY_METRICS, true);
|
|
1729
1897
|
} catch (er) {
|
|
1730
|
-
|
|
1898
|
+
BStackLogger.debug(`[Performance Upload] Failed to upload events: ${util2.format(er)}`);
|
|
1731
1899
|
this.end(EVENTS.SDK_KEY_METRICS_PREPARATION, false, er);
|
|
1732
1900
|
this.end(EVENTS.SDK_SEND_KEY_METRICS, false, er);
|
|
1733
1901
|
}
|
|
@@ -1735,12 +1903,12 @@ var init_performance_tester = __esm({
|
|
|
1735
1903
|
if (await fsPromise.access(this.jsonReportDirPath).then(() => true, () => false)) {
|
|
1736
1904
|
const files = await fsPromise.readdir(this.jsonReportDirPath);
|
|
1737
1905
|
for (const file of files) {
|
|
1738
|
-
await fsPromise.unlink(
|
|
1906
|
+
await fsPromise.unlink(path4.join(this.jsonReportDirPath, file));
|
|
1739
1907
|
}
|
|
1740
|
-
|
|
1908
|
+
BStackLogger.debug(`[Performance Upload] Cleaned up ${files.length} temporary report files`);
|
|
1741
1909
|
}
|
|
1742
1910
|
} catch (er) {
|
|
1743
|
-
|
|
1911
|
+
BStackLogger.debug(`[Performance Upload] Failed to delete temporary files: ${util2.format(er)}`);
|
|
1744
1912
|
}
|
|
1745
1913
|
}
|
|
1746
1914
|
};
|
|
@@ -1748,7 +1916,7 @@ var init_performance_tester = __esm({
|
|
|
1748
1916
|
});
|
|
1749
1917
|
|
|
1750
1918
|
// src/testorchestration/testorcherstrationutils.ts
|
|
1751
|
-
import
|
|
1919
|
+
import fs5 from "node:fs";
|
|
1752
1920
|
var RUN_SMART_SELECTION, ALLOWED_ORCHESTRATION_KEYS, isPlainObject, asString, TestOrdering, OrchestrationUtils;
|
|
1753
1921
|
var init_testorcherstrationutils = __esm({
|
|
1754
1922
|
"src/testorchestration/testorcherstrationutils.ts"() {
|
|
@@ -1816,7 +1984,7 @@ var init_testorcherstrationutils = __esm({
|
|
|
1816
1984
|
for (const service of services) {
|
|
1817
1985
|
if (Array.isArray(service) && service[0] === "browserstack" && isPlainObject(service[1]) && isPlainObject(service[1].testOrchestrationOptions)) {
|
|
1818
1986
|
testOrchOptions = service[1].testOrchestrationOptions;
|
|
1819
|
-
|
|
1987
|
+
BStackLogger.debug("[constructor] Found testOrchestrationOptions in browserstack service config");
|
|
1820
1988
|
break;
|
|
1821
1989
|
}
|
|
1822
1990
|
}
|
|
@@ -1845,9 +2013,9 @@ var init_testorcherstrationutils = __esm({
|
|
|
1845
2013
|
}
|
|
1846
2014
|
});
|
|
1847
2015
|
}
|
|
1848
|
-
|
|
2016
|
+
BStackLogger.debug(`[_extractBuildDetails] Extracted - projectName: ${this.projectName}, buildName: ${this.buildName}, buildIdentifier: ${this.buildIdentifier}`);
|
|
1849
2017
|
} catch (error) {
|
|
1850
|
-
|
|
2018
|
+
BStackLogger.error(`[_extractBuildDetails] ${error}`);
|
|
1851
2019
|
}
|
|
1852
2020
|
}
|
|
1853
2021
|
_parseCapability(capability) {
|
|
@@ -1945,7 +2113,7 @@ var init_testorcherstrationutils = __esm({
|
|
|
1945
2113
|
this.projectName = projectName;
|
|
1946
2114
|
this.buildName = buildName;
|
|
1947
2115
|
this.buildIdentifier = buildIdentifier;
|
|
1948
|
-
|
|
2116
|
+
BStackLogger.debug(`[setBuildDetails] Set - projectName: ${this.projectName}, buildName: ${this.buildName}, buildIdentifier: ${this.buildIdentifier}`);
|
|
1949
2117
|
}
|
|
1950
2118
|
/**
|
|
1951
2119
|
* Set run smart selection
|
|
@@ -1955,27 +2123,27 @@ var init_testorcherstrationutils = __esm({
|
|
|
1955
2123
|
this.runSmartSelection = isValidEnabledValue(enabled);
|
|
1956
2124
|
this.smartSelectionMode = mode;
|
|
1957
2125
|
this.smartSelectionSource = [];
|
|
1958
|
-
|
|
2126
|
+
BStackLogger.debug(`Setting runSmartSelection: enabled=${this.runSmartSelection}, mode=${this.smartSelectionMode}`);
|
|
1959
2127
|
if (this.runSmartSelection) {
|
|
1960
2128
|
const validModes = [SMART_SELECTION_MODE_RELEVANT_FIRST, SMART_SELECTION_MODE_RELEVANT_ONLY];
|
|
1961
2129
|
if (!validModes.includes(this.smartSelectionMode)) {
|
|
1962
|
-
|
|
2130
|
+
BStackLogger.warn(`Invalid smart selection mode '${this.smartSelectionMode}' provided. Defaulting to '${SMART_SELECTION_MODE_RELEVANT_FIRST}'.`);
|
|
1963
2131
|
this.smartSelectionMode = SMART_SELECTION_MODE_RELEVANT_FIRST;
|
|
1964
2132
|
}
|
|
1965
2133
|
if (source === null) {
|
|
1966
2134
|
this.smartSelectionSource = null;
|
|
1967
|
-
|
|
2135
|
+
BStackLogger.debug("No source provided for smart selection; defaulting to null.");
|
|
1968
2136
|
} else if (Array.isArray(source)) {
|
|
1969
2137
|
this.smartSelectionSource = source;
|
|
1970
|
-
|
|
2138
|
+
BStackLogger.debug(`Smart selection source set to array: ${JSON.stringify(source)}`);
|
|
1971
2139
|
} else if (typeof source === "string" && source.endsWith(".json")) {
|
|
1972
2140
|
this.smartSelectionSource = this._loadSourceFromFile(source) || [];
|
|
1973
|
-
|
|
2141
|
+
BStackLogger.debug(`Smart selection source loaded from file: ${source}`);
|
|
1974
2142
|
}
|
|
1975
2143
|
this._setTestOrdering();
|
|
1976
2144
|
}
|
|
1977
2145
|
} catch (e) {
|
|
1978
|
-
|
|
2146
|
+
BStackLogger.error(`[_setRunSmartSelection] ${e}`);
|
|
1979
2147
|
}
|
|
1980
2148
|
}
|
|
1981
2149
|
/**
|
|
@@ -1985,17 +2153,17 @@ var init_testorcherstrationutils = __esm({
|
|
|
1985
2153
|
* @returns Formatted list of repository configurations
|
|
1986
2154
|
*/
|
|
1987
2155
|
_loadSourceFromFile(filePath) {
|
|
1988
|
-
if (!
|
|
1989
|
-
|
|
2156
|
+
if (!fs5.existsSync(filePath)) {
|
|
2157
|
+
BStackLogger.error(`Source file '${filePath}' does not exist.`);
|
|
1990
2158
|
return [];
|
|
1991
2159
|
}
|
|
1992
2160
|
let data = null;
|
|
1993
2161
|
try {
|
|
1994
|
-
const fileContent =
|
|
2162
|
+
const fileContent = fs5.readFileSync(filePath, "utf8");
|
|
1995
2163
|
data = JSON.parse(fileContent);
|
|
1996
2164
|
} catch (error) {
|
|
1997
2165
|
const message = error instanceof Error ? error.message : String(error);
|
|
1998
|
-
|
|
2166
|
+
BStackLogger.error(`Error parsing JSON from source file '${filePath}': ${message}`);
|
|
1999
2167
|
return [];
|
|
2000
2168
|
}
|
|
2001
2169
|
let featureBranchEnvMap = null;
|
|
@@ -2011,9 +2179,9 @@ var init_testorcherstrationutils = __esm({
|
|
|
2011
2179
|
return acc;
|
|
2012
2180
|
}, {});
|
|
2013
2181
|
} catch (error) {
|
|
2014
|
-
|
|
2182
|
+
BStackLogger.error(`Error parsing feature branch mappings: ${error}`);
|
|
2015
2183
|
}
|
|
2016
|
-
|
|
2184
|
+
BStackLogger.debug(`Feature branch mappings from env: ${JSON.stringify(envMap)}`);
|
|
2017
2185
|
return envMap;
|
|
2018
2186
|
};
|
|
2019
2187
|
featureBranchEnvMap = loadFeatureBranchMaps();
|
|
@@ -2035,23 +2203,23 @@ var init_testorcherstrationutils = __esm({
|
|
|
2035
2203
|
}
|
|
2036
2204
|
const typedRepoInfo = repoInfo;
|
|
2037
2205
|
if (!typedRepoInfo.url || typeof typedRepoInfo.url !== "string") {
|
|
2038
|
-
|
|
2206
|
+
BStackLogger.warn(`Repository URL is missing or invalid for source '${name}': ${JSON.stringify(repoInfo)}`);
|
|
2039
2207
|
continue;
|
|
2040
2208
|
}
|
|
2041
2209
|
if (typedRepoInfo.baseBranch !== void 0 && typeof typedRepoInfo.baseBranch !== "string") {
|
|
2042
|
-
|
|
2210
|
+
BStackLogger.warn(`Base branch must be a string for source '${name}': ${JSON.stringify(repoInfo)}`);
|
|
2043
2211
|
continue;
|
|
2044
2212
|
}
|
|
2045
2213
|
if (typedRepoInfo.featureBranch !== void 0 && typeof typedRepoInfo.featureBranch !== "string") {
|
|
2046
|
-
|
|
2214
|
+
BStackLogger.warn(`Feature branch must be a string for source '${name}': ${JSON.stringify(repoInfo)}`);
|
|
2047
2215
|
continue;
|
|
2048
2216
|
}
|
|
2049
2217
|
if (!namePattern.test(name)) {
|
|
2050
|
-
|
|
2218
|
+
BStackLogger.warn(`Invalid source identifier format for '${name}': ${JSON.stringify(repoInfo)}`);
|
|
2051
2219
|
continue;
|
|
2052
2220
|
}
|
|
2053
2221
|
if (name.length > 30 || name.length < 1) {
|
|
2054
|
-
|
|
2222
|
+
BStackLogger.warn(`Source identifier '${name}' must have a length between 1 and 30 characters.`);
|
|
2055
2223
|
continue;
|
|
2056
2224
|
}
|
|
2057
2225
|
const featureBranch = getFeatureBranch(name, typedRepoInfo);
|
|
@@ -2064,11 +2232,11 @@ var init_testorcherstrationutils = __esm({
|
|
|
2064
2232
|
filteredRepoInfo.baseBranch = typedRepoInfo.baseBranch;
|
|
2065
2233
|
}
|
|
2066
2234
|
if (!filteredRepoInfo.featureBranch || filteredRepoInfo.featureBranch === "") {
|
|
2067
|
-
|
|
2235
|
+
BStackLogger.warn(`Feature branch not specified for source '${name}': ${JSON.stringify(repoInfo)}`);
|
|
2068
2236
|
continue;
|
|
2069
2237
|
}
|
|
2070
2238
|
if (filteredRepoInfo.baseBranch && filteredRepoInfo.baseBranch === filteredRepoInfo.featureBranch) {
|
|
2071
|
-
|
|
2239
|
+
BStackLogger.warn(`Feature branch and base branch cannot be the same for source '${name}': ${JSON.stringify(repoInfo)}`);
|
|
2072
2240
|
continue;
|
|
2073
2241
|
}
|
|
2074
2242
|
formattedData.push(filteredRepoInfo);
|
|
@@ -2178,17 +2346,17 @@ var init_crash_reporter = __esm({
|
|
|
2178
2346
|
this.credentialsForCrashReportUpload = process.env.CREDENTIALS_FOR_CRASH_REPORTING !== void 0 ? JSON.parse(process.env.CREDENTIALS_FOR_CRASH_REPORTING) : this.credentialsForCrashReportUpload;
|
|
2179
2347
|
}
|
|
2180
2348
|
} catch (error) {
|
|
2181
|
-
return
|
|
2349
|
+
return BStackLogger.error(`[Crash_Report_Upload] Failed to parse user credentials while reporting crash due to ${error}`);
|
|
2182
2350
|
}
|
|
2183
2351
|
if (!this.credentialsForCrashReportUpload.username || !this.credentialsForCrashReportUpload.password) {
|
|
2184
|
-
return
|
|
2352
|
+
return BStackLogger.error("[Crash_Report_Upload] Failed to parse user credentials while reporting crash");
|
|
2185
2353
|
}
|
|
2186
2354
|
try {
|
|
2187
2355
|
if (Object.keys(this.userConfigForReporting).length === 0) {
|
|
2188
2356
|
this.userConfigForReporting = process.env.USER_CONFIG_FOR_REPORTING !== void 0 ? JSON.parse(process.env.USER_CONFIG_FOR_REPORTING) : {};
|
|
2189
2357
|
}
|
|
2190
2358
|
} catch (error) {
|
|
2191
|
-
|
|
2359
|
+
BStackLogger.error(`[Crash_Report_Upload] Failed to parse user config while reporting crash due to ${error}`);
|
|
2192
2360
|
this.userConfigForReporting = {};
|
|
2193
2361
|
}
|
|
2194
2362
|
const data = {
|
|
@@ -2220,9 +2388,9 @@ var init_crash_reporter = __esm({
|
|
|
2220
2388
|
body = JSON.stringify(JSON.parse(body));
|
|
2221
2389
|
} catch {
|
|
2222
2390
|
}
|
|
2223
|
-
|
|
2391
|
+
BStackLogger.debug(`[Crash_Report_Upload] Success response: ${body}`);
|
|
2224
2392
|
} else {
|
|
2225
|
-
|
|
2393
|
+
BStackLogger.error(`[Crash_Report_Upload] Failed due to ${response.body}`);
|
|
2226
2394
|
}
|
|
2227
2395
|
}
|
|
2228
2396
|
static recursivelyRedactKeysFromObject(obj, keys) {
|
|
@@ -2282,7 +2450,7 @@ var init_crash_reporter = __esm({
|
|
|
2282
2450
|
}
|
|
2283
2451
|
}
|
|
2284
2452
|
} catch (err) {
|
|
2285
|
-
|
|
2453
|
+
BStackLogger.error(`Error in parsing user config PII with error ${err ? err.stack || err : err}`);
|
|
2286
2454
|
return configWithoutPII;
|
|
2287
2455
|
}
|
|
2288
2456
|
configWithoutPII.services = finalServices;
|
|
@@ -2317,7 +2485,7 @@ var init_featureStats = __esm({
|
|
|
2317
2485
|
this.failed(groupId);
|
|
2318
2486
|
break;
|
|
2319
2487
|
default:
|
|
2320
|
-
|
|
2488
|
+
BStackLogger.debug("Request to mark usage for unknown status - " + status);
|
|
2321
2489
|
break;
|
|
2322
2490
|
}
|
|
2323
2491
|
}
|
|
@@ -2553,7 +2721,7 @@ var init_usageStats = __esm({
|
|
|
2553
2721
|
try {
|
|
2554
2722
|
usage.events = this.getEventsData();
|
|
2555
2723
|
} catch (e) {
|
|
2556
|
-
|
|
2724
|
+
BStackLogger.debug("exception in getFormattedData: " + e);
|
|
2557
2725
|
}
|
|
2558
2726
|
return usage;
|
|
2559
2727
|
}
|
|
@@ -2563,7 +2731,7 @@ var init_usageStats = __esm({
|
|
|
2563
2731
|
const usageStatsForWorker = _UsageStats.fromJSON(workerData.usageStats);
|
|
2564
2732
|
this.add(usageStatsForWorker);
|
|
2565
2733
|
} catch (e) {
|
|
2566
|
-
|
|
2734
|
+
BStackLogger.debug("Exception in adding workerData: " + e);
|
|
2567
2735
|
}
|
|
2568
2736
|
});
|
|
2569
2737
|
}
|
|
@@ -2617,9 +2785,9 @@ var init_usageStats = __esm({
|
|
|
2617
2785
|
});
|
|
2618
2786
|
|
|
2619
2787
|
// src/scripts/accessibility-scripts.ts
|
|
2620
|
-
import
|
|
2621
|
-
import
|
|
2622
|
-
import
|
|
2788
|
+
import path5 from "node:path";
|
|
2789
|
+
import fs6 from "node:fs";
|
|
2790
|
+
import os2 from "node:os";
|
|
2623
2791
|
var AccessibilityScripts, accessibility_scripts_default;
|
|
2624
2792
|
var init_accessibility_scripts = __esm({
|
|
2625
2793
|
"src/scripts/accessibility-scripts.ts"() {
|
|
@@ -2637,7 +2805,7 @@ var init_accessibility_scripts = __esm({
|
|
|
2637
2805
|
// don't allow to create instances from it other than through `checkAndGetInstance`
|
|
2638
2806
|
constructor() {
|
|
2639
2807
|
this.browserstackFolderPath = this.getWritableDir();
|
|
2640
|
-
this.commandsPath =
|
|
2808
|
+
this.commandsPath = path5.join(this.browserstackFolderPath, "commands.json");
|
|
2641
2809
|
}
|
|
2642
2810
|
static checkAndGetInstance() {
|
|
2643
2811
|
if (!_AccessibilityScripts.instance) {
|
|
@@ -2649,17 +2817,17 @@ var init_accessibility_scripts = __esm({
|
|
|
2649
2817
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2650
2818
|
getWritableDir() {
|
|
2651
2819
|
const orderedPaths = [
|
|
2652
|
-
|
|
2820
|
+
path5.join(os2.homedir(), ".browserstack"),
|
|
2653
2821
|
process.cwd(),
|
|
2654
|
-
|
|
2822
|
+
os2.tmpdir()
|
|
2655
2823
|
];
|
|
2656
2824
|
for (const orderedPath of orderedPaths) {
|
|
2657
2825
|
try {
|
|
2658
|
-
if (
|
|
2659
|
-
|
|
2826
|
+
if (fs6.existsSync(orderedPath)) {
|
|
2827
|
+
fs6.accessSync(orderedPath);
|
|
2660
2828
|
return orderedPath;
|
|
2661
2829
|
}
|
|
2662
|
-
|
|
2830
|
+
fs6.mkdirSync(orderedPath, { recursive: true });
|
|
2663
2831
|
return orderedPath;
|
|
2664
2832
|
} catch (error) {
|
|
2665
2833
|
}
|
|
@@ -2668,8 +2836,8 @@ var init_accessibility_scripts = __esm({
|
|
|
2668
2836
|
}
|
|
2669
2837
|
readFromExistingFile() {
|
|
2670
2838
|
try {
|
|
2671
|
-
if (
|
|
2672
|
-
const data =
|
|
2839
|
+
if (fs6.existsSync(this.commandsPath)) {
|
|
2840
|
+
const data = fs6.readFileSync(this.commandsPath, "utf8");
|
|
2673
2841
|
if (data) {
|
|
2674
2842
|
this.update(JSON.parse(data));
|
|
2675
2843
|
}
|
|
@@ -2692,10 +2860,10 @@ var init_accessibility_scripts = __esm({
|
|
|
2692
2860
|
}
|
|
2693
2861
|
}
|
|
2694
2862
|
store() {
|
|
2695
|
-
if (!
|
|
2696
|
-
|
|
2863
|
+
if (!fs6.existsSync(this.browserstackFolderPath)) {
|
|
2864
|
+
fs6.mkdirSync(this.browserstackFolderPath);
|
|
2697
2865
|
}
|
|
2698
|
-
|
|
2866
|
+
fs6.writeFileSync(this.commandsPath, JSON.stringify({
|
|
2699
2867
|
commands: this.commandsToWrap,
|
|
2700
2868
|
scripts: {
|
|
2701
2869
|
scan: this.performScan,
|
|
@@ -2714,10 +2882,10 @@ var init_accessibility_scripts = __esm({
|
|
|
2714
2882
|
// src/util.ts
|
|
2715
2883
|
import { hostname as hostname2, platform as platform3, type as type2, version as version2, arch as arch3, tmpdir } from "node:os";
|
|
2716
2884
|
import crypto from "node:crypto";
|
|
2717
|
-
import
|
|
2885
|
+
import fs7 from "node:fs";
|
|
2718
2886
|
import zlib from "node:zlib";
|
|
2719
2887
|
import { format, promisify as promisify2 } from "node:util";
|
|
2720
|
-
import
|
|
2888
|
+
import path6 from "node:path";
|
|
2721
2889
|
import util3 from "node:util";
|
|
2722
2890
|
import gitRepoInfo from "git-repo-info";
|
|
2723
2891
|
import gitconfig from "gitconfiglocal";
|
|
@@ -2758,7 +2926,7 @@ function getParentSuiteName(fullTitle, testSuiteTitle) {
|
|
|
2758
2926
|
return parentSuiteName.trim();
|
|
2759
2927
|
}
|
|
2760
2928
|
function processError(error, fn, args) {
|
|
2761
|
-
|
|
2929
|
+
BStackLogger.error(`Error in executing ${fn.name} with args ${args}: ${error}`);
|
|
2762
2930
|
let argsString;
|
|
2763
2931
|
try {
|
|
2764
2932
|
argsString = JSON.stringify(args);
|
|
@@ -2796,7 +2964,7 @@ async function nodeRequest(requestType, apiEndpoint, options, apiUrl, timeout =
|
|
|
2796
2964
|
clearTimeout(timeoutId);
|
|
2797
2965
|
return await response.json();
|
|
2798
2966
|
} catch (error) {
|
|
2799
|
-
|
|
2967
|
+
BStackLogger.debug(`Error in firing request ${apiUrl}/${apiEndpoint}: ${format(error)}`);
|
|
2800
2968
|
const isLogUpload = apiEndpoint === UPLOAD_LOGS_ENDPOINT;
|
|
2801
2969
|
if (error && error.response) {
|
|
2802
2970
|
const errorMessageJson = error.response.body ? JSON.parse(error.response.body.toString()) : null;
|
|
@@ -2804,9 +2972,9 @@ async function nodeRequest(requestType, apiEndpoint, options, apiUrl, timeout =
|
|
|
2804
2972
|
if (errorMessage) {
|
|
2805
2973
|
const message = `${errorMessage} - ${error.stack}`;
|
|
2806
2974
|
if (isLogUpload) {
|
|
2807
|
-
|
|
2975
|
+
BStackLogger.debug(message);
|
|
2808
2976
|
} else {
|
|
2809
|
-
|
|
2977
|
+
BStackLogger.error(message);
|
|
2810
2978
|
}
|
|
2811
2979
|
}
|
|
2812
2980
|
if (isLogUpload) {
|
|
@@ -2815,10 +2983,10 @@ async function nodeRequest(requestType, apiEndpoint, options, apiUrl, timeout =
|
|
|
2815
2983
|
throw error;
|
|
2816
2984
|
} else {
|
|
2817
2985
|
if (isLogUpload) {
|
|
2818
|
-
|
|
2986
|
+
BStackLogger.debug(`Failed to fire api request due to ${error} - ${error.stack}`);
|
|
2819
2987
|
return;
|
|
2820
2988
|
}
|
|
2821
|
-
|
|
2989
|
+
BStackLogger.debug(`Failed to fire api request due to ${error} - ${error.stack}`);
|
|
2822
2990
|
throw error;
|
|
2823
2991
|
}
|
|
2824
2992
|
}
|
|
@@ -3238,9 +3406,9 @@ async function batchAndPostEvents(eventUrl, kind, data) {
|
|
|
3238
3406
|
},
|
|
3239
3407
|
body: JSON.stringify(data)
|
|
3240
3408
|
});
|
|
3241
|
-
|
|
3409
|
+
BStackLogger.debug(`[${kind}] Success response: ${JSON.stringify(await response.json())}`);
|
|
3242
3410
|
} catch (error) {
|
|
3243
|
-
|
|
3411
|
+
BStackLogger.debug(`[${kind}] EXCEPTION IN ${kind} REQUEST TO TEST REPORTING AND ANALYTICS : ${error}`);
|
|
3244
3412
|
throw new Error("Exception in request " + error);
|
|
3245
3413
|
}
|
|
3246
3414
|
}
|
|
@@ -3278,7 +3446,7 @@ function getObservabilityBuild(options, bstackBuildName) {
|
|
|
3278
3446
|
if (options.testObservabilityOptions && options.testObservabilityOptions.buildName) {
|
|
3279
3447
|
return options.testObservabilityOptions.buildName;
|
|
3280
3448
|
}
|
|
3281
|
-
return bstackBuildName ||
|
|
3449
|
+
return bstackBuildName || path6.basename(path6.resolve(process.cwd()));
|
|
3282
3450
|
}
|
|
3283
3451
|
function getObservabilityBuildTags(options, bstackBuildTag) {
|
|
3284
3452
|
if (process.env.TEST_OBSERVABILITY_BUILD_TAG) {
|
|
@@ -3364,26 +3532,26 @@ async function uploadLogs(user, key, clientBuildUuid) {
|
|
|
3364
3532
|
if (!user || !key) {
|
|
3365
3533
|
success = false;
|
|
3366
3534
|
failure = "skipped: missing_credentials";
|
|
3367
|
-
|
|
3535
|
+
BStackLogger.debug("Uploading logs failed due to no credentials");
|
|
3368
3536
|
return;
|
|
3369
3537
|
}
|
|
3370
3538
|
const tmpDir = tmpdir();
|
|
3371
|
-
const tarPath =
|
|
3372
|
-
const tarGzPath =
|
|
3539
|
+
const tarPath = path6.join(tmpDir, "logs.tar");
|
|
3540
|
+
const tarGzPath = path6.join(tmpDir, "logs.tar.gz");
|
|
3373
3541
|
const filesToArchive = [
|
|
3374
|
-
|
|
3542
|
+
BStackLogger.logFilePath,
|
|
3375
3543
|
CLI_DEBUG_LOGS_FILE
|
|
3376
|
-
].filter((f) =>
|
|
3544
|
+
].filter((f) => fs7.existsSync(f));
|
|
3377
3545
|
const copiedFileNames = [];
|
|
3378
3546
|
const archiveAddFailures = [];
|
|
3379
3547
|
for (const f of filesToArchive) {
|
|
3380
3548
|
try {
|
|
3381
|
-
const dest =
|
|
3382
|
-
|
|
3383
|
-
copiedFileNames.push(
|
|
3549
|
+
const dest = path6.join(tmpDir, path6.basename(f));
|
|
3550
|
+
fs7.copyFileSync(f, dest);
|
|
3551
|
+
copiedFileNames.push(path6.basename(f));
|
|
3384
3552
|
} catch (copyErr) {
|
|
3385
3553
|
const msg = copyErr?.message || String(copyErr);
|
|
3386
|
-
archiveAddFailures.push(`${
|
|
3554
|
+
archiveAddFailures.push(`${path6.basename(f)}: ${msg}`);
|
|
3387
3555
|
}
|
|
3388
3556
|
}
|
|
3389
3557
|
if (archiveAddFailures.length > 0 && failure === void 0) {
|
|
@@ -3400,15 +3568,15 @@ async function uploadLogs(user, key, clientBuildUuid) {
|
|
|
3400
3568
|
copiedFileNames
|
|
3401
3569
|
);
|
|
3402
3570
|
await new Promise((resolve, reject) => {
|
|
3403
|
-
const source =
|
|
3404
|
-
const dest =
|
|
3571
|
+
const source = fs7.createReadStream(tarPath);
|
|
3572
|
+
const dest = fs7.createWriteStream(tarGzPath);
|
|
3405
3573
|
const gzip = zlib.createGzip({ level: 1 });
|
|
3406
3574
|
source.pipe(gzip).pipe(dest);
|
|
3407
3575
|
dest.on("finish", resolve);
|
|
3408
3576
|
dest.on("error", reject);
|
|
3409
3577
|
});
|
|
3410
3578
|
const formData = new FormData();
|
|
3411
|
-
const file = await
|
|
3579
|
+
const file = await fs7.openAsBlob(tarGzPath, { type: "application/x-gzip" });
|
|
3412
3580
|
formData.append("data", file, "logs.tar.gz");
|
|
3413
3581
|
formData.append("clientBuildUuid", clientBuildUuid);
|
|
3414
3582
|
const auth = Buffer.from(`${user}:${key}`).toString("base64");
|
|
@@ -3424,16 +3592,16 @@ async function uploadLogs(user, key, clientBuildUuid) {
|
|
|
3424
3592
|
requestOptions,
|
|
3425
3593
|
APIUtils.UPLOAD_LOGS_ADDRESS
|
|
3426
3594
|
);
|
|
3427
|
-
|
|
3428
|
-
|
|
3595
|
+
fs7.unlinkSync(tarPath);
|
|
3596
|
+
fs7.unlinkSync(tarGzPath);
|
|
3429
3597
|
for (const f of copiedFileNames) {
|
|
3430
|
-
const filePath =
|
|
3431
|
-
if (
|
|
3432
|
-
|
|
3598
|
+
const filePath = path6.join(tmpDir, f);
|
|
3599
|
+
if (fs7.existsSync(filePath)) {
|
|
3600
|
+
fs7.unlinkSync(filePath);
|
|
3433
3601
|
}
|
|
3434
3602
|
}
|
|
3435
|
-
if (
|
|
3436
|
-
|
|
3603
|
+
if (fs7.existsSync(CLI_DEBUG_LOGS_FILE)) {
|
|
3604
|
+
fs7.unlinkSync(CLI_DEBUG_LOGS_FILE);
|
|
3437
3605
|
}
|
|
3438
3606
|
if (!response) {
|
|
3439
3607
|
success = false;
|
|
@@ -3446,7 +3614,7 @@ async function uploadLogs(user, key, clientBuildUuid) {
|
|
|
3446
3614
|
} catch (error) {
|
|
3447
3615
|
success = false;
|
|
3448
3616
|
failure = `uploadLogs exception: ${getErrorString(error)}`;
|
|
3449
|
-
|
|
3617
|
+
BStackLogger.error(`Error while uploading logs: ${getErrorString(error)}`);
|
|
3450
3618
|
return null;
|
|
3451
3619
|
} finally {
|
|
3452
3620
|
PerformanceTester.end(eventName, success, failure);
|
|
@@ -3463,7 +3631,7 @@ function truncateString(field, truncateSizeInBytes) {
|
|
|
3463
3631
|
return truncatedString;
|
|
3464
3632
|
}
|
|
3465
3633
|
} catch (error) {
|
|
3466
|
-
|
|
3634
|
+
BStackLogger.debug(`Error while truncating field, nothing was truncated here: ${error}`);
|
|
3467
3635
|
}
|
|
3468
3636
|
return field;
|
|
3469
3637
|
}
|
|
@@ -3472,7 +3640,7 @@ function getSizeOfJsonObjectInBytes(jsonData) {
|
|
|
3472
3640
|
const buffer = Buffer.from(JSON.stringify(jsonData));
|
|
3473
3641
|
return buffer.length;
|
|
3474
3642
|
} catch (error) {
|
|
3475
|
-
|
|
3643
|
+
BStackLogger.debug(`Something went wrong while calculating size of JSON object: ${error}`);
|
|
3476
3644
|
}
|
|
3477
3645
|
return -1;
|
|
3478
3646
|
}
|
|
@@ -3482,7 +3650,7 @@ function checkAndTruncateVCSInfo(gitMetaData) {
|
|
|
3482
3650
|
const truncateSize = gitMetaDataSizeInBytes - MAX_GIT_META_DATA_SIZE_IN_BYTES;
|
|
3483
3651
|
const truncatedCommitMessage = truncateString(gitMetaData.commit_message, truncateSize);
|
|
3484
3652
|
gitMetaData.commit_message = truncatedCommitMessage;
|
|
3485
|
-
|
|
3653
|
+
BStackLogger.info(`The commit has been truncated. Size of commit after truncation is ${getSizeOfJsonObjectInBytes(gitMetaData) / 1024} KB`);
|
|
3486
3654
|
}
|
|
3487
3655
|
return gitMetaData;
|
|
3488
3656
|
}
|
|
@@ -3494,7 +3662,7 @@ function getObservabilityProduct(options, isAppAutomate) {
|
|
|
3494
3662
|
}
|
|
3495
3663
|
async function pollApi(url3, params, headers, upperLimit, startTime = Date.now()) {
|
|
3496
3664
|
params.timestamp = Math.round(Date.now() / 1e3);
|
|
3497
|
-
|
|
3665
|
+
BStackLogger.debug(`current timestamp ${params.timestamp}`);
|
|
3498
3666
|
try {
|
|
3499
3667
|
const response = await makeGetRequest(url3, params, headers);
|
|
3500
3668
|
const responseData = await response.json();
|
|
@@ -3506,9 +3674,9 @@ async function pollApi(url3, params, headers, upperLimit, startTime = Date.now()
|
|
|
3506
3674
|
} catch (error) {
|
|
3507
3675
|
if (error.response && error.response.status === 404) {
|
|
3508
3676
|
const nextPollTime = parseInt(error.response.headers.get("next_poll_time"), 10) * 1e3;
|
|
3509
|
-
|
|
3677
|
+
BStackLogger.debug(`timeInMillis ${nextPollTime}`);
|
|
3510
3678
|
if (isNaN(nextPollTime)) {
|
|
3511
|
-
|
|
3679
|
+
BStackLogger.warn("Invalid or missing `nextPollTime` header. Stopping polling.");
|
|
3512
3680
|
return {
|
|
3513
3681
|
data: {},
|
|
3514
3682
|
headers: error.response.headers,
|
|
@@ -3516,18 +3684,18 @@ async function pollApi(url3, params, headers, upperLimit, startTime = Date.now()
|
|
|
3516
3684
|
};
|
|
3517
3685
|
}
|
|
3518
3686
|
const elapsedTime = nextPollTime - Date.now();
|
|
3519
|
-
|
|
3687
|
+
BStackLogger.debug(
|
|
3520
3688
|
`elapsedTime ${elapsedTime} timeInMillis ${nextPollTime} upperLimit ${upperLimit}`
|
|
3521
3689
|
);
|
|
3522
3690
|
if (nextPollTime > upperLimit) {
|
|
3523
|
-
|
|
3691
|
+
BStackLogger.warn("Polling stopped due to upper time limit.");
|
|
3524
3692
|
return {
|
|
3525
3693
|
data: {},
|
|
3526
3694
|
headers: error.response.headers,
|
|
3527
3695
|
message: "Polling stopped due to upper time limit."
|
|
3528
3696
|
};
|
|
3529
3697
|
}
|
|
3530
|
-
|
|
3698
|
+
BStackLogger.debug(`Polling again in ${elapsedTime}ms with params:`, params);
|
|
3531
3699
|
await new Promise((resolve) => setTimeout(resolve, elapsedTime));
|
|
3532
3700
|
return pollApi(url3, params, headers, upperLimit, startTime);
|
|
3533
3701
|
} else if (error.response) {
|
|
@@ -3536,7 +3704,7 @@ async function pollApi(url3, params, headers, upperLimit, startTime = Date.now()
|
|
|
3536
3704
|
const parsedError = JSON.parse(error.response.json());
|
|
3537
3705
|
errorMessage = parsedError.message;
|
|
3538
3706
|
} catch {
|
|
3539
|
-
|
|
3707
|
+
BStackLogger.debug(`Error parsing pollApi request body ${error.response.body}`);
|
|
3540
3708
|
errorMessage = "Unknown error";
|
|
3541
3709
|
}
|
|
3542
3710
|
throw {
|
|
@@ -3545,7 +3713,7 @@ async function pollApi(url3, params, headers, upperLimit, startTime = Date.now()
|
|
|
3545
3713
|
message: errorMessage
|
|
3546
3714
|
};
|
|
3547
3715
|
} else {
|
|
3548
|
-
|
|
3716
|
+
BStackLogger.error(`Unexpected error occurred: ${error}`);
|
|
3549
3717
|
return { data: {}, headers: {}, message: "Unexpected error occurred." };
|
|
3550
3718
|
}
|
|
3551
3719
|
}
|
|
@@ -3654,28 +3822,28 @@ function nestedKeyValue(hash, keys) {
|
|
|
3654
3822
|
return keys.reduce((hash2, key) => isHash(hash2) ? hash2[key] : void 0, hash);
|
|
3655
3823
|
}
|
|
3656
3824
|
function removeDir(dir) {
|
|
3657
|
-
const list =
|
|
3825
|
+
const list = fs7.readdirSync(dir);
|
|
3658
3826
|
for (let i = 0; i < list.length; i++) {
|
|
3659
|
-
const filename =
|
|
3660
|
-
const stat =
|
|
3827
|
+
const filename = path6.join(dir, list[i]);
|
|
3828
|
+
const stat = fs7.statSync(filename);
|
|
3661
3829
|
if (filename === "." || filename === "..") {
|
|
3662
3830
|
} else if (stat.isDirectory()) {
|
|
3663
3831
|
removeDir(filename);
|
|
3664
3832
|
} else {
|
|
3665
|
-
|
|
3833
|
+
fs7.unlinkSync(filename);
|
|
3666
3834
|
}
|
|
3667
3835
|
}
|
|
3668
|
-
|
|
3836
|
+
fs7.rmdirSync(dir);
|
|
3669
3837
|
}
|
|
3670
3838
|
function createDir(dir) {
|
|
3671
|
-
if (
|
|
3839
|
+
if (fs7.existsSync(dir)) {
|
|
3672
3840
|
removeDir(dir);
|
|
3673
3841
|
}
|
|
3674
|
-
|
|
3842
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
3675
3843
|
}
|
|
3676
3844
|
function isWritable(dirPath) {
|
|
3677
3845
|
try {
|
|
3678
|
-
|
|
3846
|
+
fs7.accessSync(dirPath, fs7.constants.W_OK);
|
|
3679
3847
|
return true;
|
|
3680
3848
|
} catch {
|
|
3681
3849
|
return false;
|
|
@@ -3683,10 +3851,10 @@ function isWritable(dirPath) {
|
|
|
3683
3851
|
}
|
|
3684
3852
|
function setReadWriteAccess(dirPath) {
|
|
3685
3853
|
try {
|
|
3686
|
-
|
|
3687
|
-
|
|
3854
|
+
fs7.chmodSync(dirPath, 438);
|
|
3855
|
+
BStackLogger.debug(`Directory ${dirPath} is now read/write accessible.`);
|
|
3688
3856
|
} catch (err) {
|
|
3689
|
-
|
|
3857
|
+
BStackLogger.error(`Failed to set directory access: ${err.stack}`);
|
|
3690
3858
|
}
|
|
3691
3859
|
}
|
|
3692
3860
|
function getMochaTestHierarchy(test) {
|
|
@@ -3714,7 +3882,7 @@ function isMultiRemoteCaps(capabilities) {
|
|
|
3714
3882
|
(cap) => Object.values(cap).length > 0 && Object.values(cap).every((c) => c !== null && typeof c === "object" && c.capabilities)
|
|
3715
3883
|
);
|
|
3716
3884
|
}
|
|
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;
|
|
3885
|
+
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
3886
|
var init_util = __esm({
|
|
3719
3887
|
"src/util.ts"() {
|
|
3720
3888
|
"use strict";
|
|
@@ -3788,7 +3956,7 @@ var init_util = __esm({
|
|
|
3788
3956
|
};
|
|
3789
3957
|
if (scannerVersion) {
|
|
3790
3958
|
process.env.BSTACK_A11Y_SCANNER_VERSION = scannerVersion;
|
|
3791
|
-
|
|
3959
|
+
BStackLogger.debug(`Accessibility scannerVersion ${scannerVersion}`);
|
|
3792
3960
|
}
|
|
3793
3961
|
if (accessibilityToken) {
|
|
3794
3962
|
process.env.BSTACK_A11Y_JWT = accessibilityToken;
|
|
@@ -3860,7 +4028,7 @@ var init_util = __esm({
|
|
|
3860
4028
|
CrashReporter.userConfigForReporting = process.env.USER_CONFIG_FOR_REPORTING !== void 0 ? JSON.parse(process.env.USER_CONFIG_FOR_REPORTING) : {};
|
|
3861
4029
|
}
|
|
3862
4030
|
} catch (error) {
|
|
3863
|
-
return
|
|
4031
|
+
return BStackLogger.error(`[Crash_Report_Upload] Failed to parse user config while sending build start event due to ${error}`);
|
|
3864
4032
|
}
|
|
3865
4033
|
data.config = CrashReporter.userConfigForReporting;
|
|
3866
4034
|
try {
|
|
@@ -3877,8 +4045,8 @@ var init_util = __esm({
|
|
|
3877
4045
|
});
|
|
3878
4046
|
const jsonResponse = await response.json();
|
|
3879
4047
|
delete data?.accessibility?.settings?.includeEncodedExtension;
|
|
3880
|
-
|
|
3881
|
-
|
|
4048
|
+
BStackLogger.debug(`[Start_Build] Success response: ${JSON.stringify(jsonResponse)}`);
|
|
4049
|
+
BStackLogger.debug(`Test Plan Id sent in request: ${getTestPlanId(options)}`);
|
|
3882
4050
|
process.env[TESTOPS_BUILD_COMPLETED_ENV] = "true";
|
|
3883
4051
|
if (jsonResponse.jwt) {
|
|
3884
4052
|
process.env[BROWSERSTACK_TESTHUB_JWT] = jsonResponse.jwt;
|
|
@@ -3886,13 +4054,13 @@ var init_util = __esm({
|
|
|
3886
4054
|
if (jsonResponse.build_hashed_id) {
|
|
3887
4055
|
process.env[BROWSERSTACK_TESTHUB_UUID] = jsonResponse.build_hashed_id;
|
|
3888
4056
|
testOpsConfig_default.getInstance().buildHashedId = jsonResponse.build_hashed_id;
|
|
3889
|
-
|
|
4057
|
+
BStackLogger.info(`Testhub started with id: ${testOpsConfig_default.getInstance()?.buildHashedId}`);
|
|
3890
4058
|
}
|
|
3891
4059
|
processLaunchBuildResponse(jsonResponse, options);
|
|
3892
4060
|
launchBuildUsage.success();
|
|
3893
4061
|
return jsonResponse;
|
|
3894
4062
|
} catch (error) {
|
|
3895
|
-
|
|
4063
|
+
BStackLogger.debug(`TestHub build start failed: ${format(error)}`);
|
|
3896
4064
|
if (!error.success) {
|
|
3897
4065
|
launchBuildUsage.failed(error);
|
|
3898
4066
|
logBuildError(error);
|
|
@@ -3902,7 +4070,7 @@ var init_util = __esm({
|
|
|
3902
4070
|
}));
|
|
3903
4071
|
validateCapsWithAppA11y = (platformMeta) => {
|
|
3904
4072
|
if (platformMeta?.platform_name && String(platformMeta?.platform_name).toLowerCase() === "android" && (platformMeta?.platform_version && parseInt(platformMeta?.platform_version?.toString()) < 11)) {
|
|
3905
|
-
|
|
4073
|
+
BStackLogger.warn("App Accessibility Automation tests are supported on OS version 11 and above for Android devices.");
|
|
3906
4074
|
return false;
|
|
3907
4075
|
}
|
|
3908
4076
|
return true;
|
|
@@ -3910,38 +4078,79 @@ var init_util = __esm({
|
|
|
3910
4078
|
validateCapsWithA11y = (deviceName, platformMeta, chromeOptions) => {
|
|
3911
4079
|
try {
|
|
3912
4080
|
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.");
|
|
4081
|
+
BStackLogger.warn("Accessibility Automation will run only on Desktop browsers.");
|
|
3918
4082
|
return false;
|
|
3919
4083
|
}
|
|
4084
|
+
const browserName = platformMeta?.browser_name?.toLowerCase();
|
|
3920
4085
|
const browserVersion = platformMeta?.browser_version;
|
|
3921
|
-
|
|
3922
|
-
|
|
4086
|
+
const validBrowsers = SUPPORTED_BROWSERS_FOR_ACCESSIBILITY;
|
|
4087
|
+
if (!browserName || !validBrowsers.includes(browserName)) {
|
|
4088
|
+
BStackLogger.warn(`Accessibility Automation supports Chrome 95+, Chrome for Testing 141+, and Safari 18.4+. Current browser: ${browserName}`);
|
|
3923
4089
|
return false;
|
|
3924
4090
|
}
|
|
3925
|
-
if (
|
|
3926
|
-
|
|
3927
|
-
|
|
4091
|
+
if (browserName === "chrome" || browserName === "chromefortesting") {
|
|
4092
|
+
const minVersion = MIN_BROWSER_VERSIONS_A11Y[browserName];
|
|
4093
|
+
if (browserVersion && browserVersion !== "latest") {
|
|
4094
|
+
const version3 = parseInt(browserVersion.toString().split(".")[0] || "0", 10);
|
|
4095
|
+
if (version3 < minVersion) {
|
|
4096
|
+
BStackLogger.warn(`Accessibility Automation requires ${browserName === "chrome" ? "Chrome" : "Chrome for Testing"} version ${minVersion} or higher.`);
|
|
4097
|
+
return false;
|
|
4098
|
+
}
|
|
4099
|
+
}
|
|
4100
|
+
if (chromeOptions?.args?.includes("--headless")) {
|
|
4101
|
+
BStackLogger.warn("Accessibility Automation will not run on legacy headless mode. Switch to new headless mode or avoid using headless mode.");
|
|
4102
|
+
return false;
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
if (browserName === "safari") {
|
|
4106
|
+
if (browserVersion && browserVersion !== "latest") {
|
|
4107
|
+
const [currentMajor = 0, currentMinor = 0] = browserVersion.toString().split(".").map(Number);
|
|
4108
|
+
const [requiredMajor = 0, requiredMinor = 0] = MIN_BROWSER_VERSIONS_A11Y.safari.toString().split(".").map(Number);
|
|
4109
|
+
if (currentMajor < requiredMajor || currentMajor === requiredMajor && currentMinor < requiredMinor) {
|
|
4110
|
+
BStackLogger.warn(`Accessibility Automation requires Safari version ${MIN_BROWSER_VERSIONS_A11Y.safari} or higher.`);
|
|
4111
|
+
return false;
|
|
4112
|
+
}
|
|
4113
|
+
}
|
|
3928
4114
|
}
|
|
3929
4115
|
return true;
|
|
3930
4116
|
} catch (error) {
|
|
3931
|
-
|
|
4117
|
+
BStackLogger.debug(`Exception in checking capabilities compatibility with Accessibility. Error: ${error}`);
|
|
3932
4118
|
}
|
|
3933
4119
|
return false;
|
|
3934
4120
|
};
|
|
3935
4121
|
validateCapsWithNonBstackA11y = (browserName, browserVersion) => {
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
4122
|
+
try {
|
|
4123
|
+
const browser = browserName?.toLowerCase();
|
|
4124
|
+
const validBrowsers = ["chrome", "chromefortesting", "safari"];
|
|
4125
|
+
if (!browser || !validBrowsers.includes(browser)) {
|
|
4126
|
+
BStackLogger.warn("Accessibility Automation on non-BrowserStack infrastructure supports Chrome 100+, Chrome for Testing 141+, and Safari 18.4+.");
|
|
4127
|
+
return false;
|
|
4128
|
+
}
|
|
4129
|
+
if (browser === "chrome" || browser === "chromefortesting") {
|
|
4130
|
+
const minVersion = MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK[browser];
|
|
4131
|
+
if (browserVersion && browserVersion !== "latest") {
|
|
4132
|
+
const version3 = parseInt(browserVersion.toString().split(".")[0] || "0", 10);
|
|
4133
|
+
if (version3 < minVersion) {
|
|
4134
|
+
BStackLogger.warn(`Accessibility Automation requires ${browser === "chrome" ? "Chrome" : "Chrome for Testing"} version ${minVersion}+ on non-BrowserStack infrastructure.`);
|
|
4135
|
+
return false;
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
}
|
|
4139
|
+
if (browser === "safari") {
|
|
4140
|
+
if (browserVersion && browserVersion !== "latest") {
|
|
4141
|
+
const [currentMajor = 0, currentMinor = 0] = browserVersion.toString().split(".").map(Number);
|
|
4142
|
+
const [requiredMajor = 0, requiredMinor = 0] = MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK.safari.toString().split(".").map(Number);
|
|
4143
|
+
if (currentMajor < requiredMajor || currentMajor === requiredMajor && currentMinor < requiredMinor) {
|
|
4144
|
+
BStackLogger.warn(`Accessibility Automation requires Safari version ${MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK.safari}+ on non-BrowserStack infrastructure.`);
|
|
4145
|
+
return false;
|
|
4146
|
+
}
|
|
4147
|
+
}
|
|
4148
|
+
}
|
|
4149
|
+
return true;
|
|
4150
|
+
} catch (error) {
|
|
4151
|
+
BStackLogger.debug(`Exception in checking capabilities compatibility with Accessibility. Error: ${error}`);
|
|
3943
4152
|
}
|
|
3944
|
-
return
|
|
4153
|
+
return false;
|
|
3945
4154
|
};
|
|
3946
4155
|
shouldScanTestForAccessibility = (suiteTitle, testTitle, accessibilityOptions, world, isCucumber) => {
|
|
3947
4156
|
try {
|
|
@@ -3959,7 +4168,7 @@ var init_util = __esm({
|
|
|
3959
4168
|
const included = includeTags?.length === 0 || includeTags?.some((include) => fullTestName.includes(include));
|
|
3960
4169
|
return !excluded && included;
|
|
3961
4170
|
} catch (error) {
|
|
3962
|
-
|
|
4171
|
+
BStackLogger.debug(`Error while validating test case for accessibility before scanning. Error : ${error}`);
|
|
3963
4172
|
}
|
|
3964
4173
|
return false;
|
|
3965
4174
|
};
|
|
@@ -3968,7 +4177,7 @@ var init_util = __esm({
|
|
|
3968
4177
|
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
4178
|
return accessibilityFlag && hasA11yJwtToken;
|
|
3970
4179
|
} catch (error) {
|
|
3971
|
-
|
|
4180
|
+
BStackLogger.debug(`Exception in verifying the Accessibility session with error : ${error}`);
|
|
3972
4181
|
}
|
|
3973
4182
|
return false;
|
|
3974
4183
|
};
|
|
@@ -3999,43 +4208,43 @@ var init_util = __esm({
|
|
|
3999
4208
|
};
|
|
4000
4209
|
performA11yScan = async (isAppAutomate, browser, isBrowserStackSession, isAccessibility, commandName, testName) => {
|
|
4001
4210
|
if (!isAccessibilityAutomationSession(isAccessibility)) {
|
|
4002
|
-
|
|
4211
|
+
BStackLogger.warn("Not an Accessibility Automation session, cannot perform Accessibility scan.");
|
|
4003
4212
|
return;
|
|
4004
4213
|
}
|
|
4005
4214
|
try {
|
|
4006
4215
|
if (isAppAccessibilityAutomationSession(isAccessibility, isAppAutomate)) {
|
|
4007
4216
|
const results = await browser.execute(formatString(accessibility_scripts_default.performScan, JSON.stringify(_getParamsForAppAccessibility(commandName, testName))), {});
|
|
4008
|
-
|
|
4217
|
+
BStackLogger.debug(util3.format(results));
|
|
4009
4218
|
return results;
|
|
4010
4219
|
}
|
|
4011
4220
|
if (accessibility_scripts_default.performScan) {
|
|
4012
4221
|
const results = await executeAccessibilityScript(browser, accessibility_scripts_default.performScan, { method: commandName || "" });
|
|
4013
4222
|
return results;
|
|
4014
4223
|
}
|
|
4015
|
-
|
|
4224
|
+
BStackLogger.error("AccessibilityScripts.performScan is null");
|
|
4016
4225
|
return;
|
|
4017
4226
|
} catch (err) {
|
|
4018
|
-
|
|
4227
|
+
BStackLogger.error("Accessibility Scan could not be performed : " + err);
|
|
4019
4228
|
return;
|
|
4020
4229
|
}
|
|
4021
4230
|
};
|
|
4022
4231
|
getA11yResults = PerformanceTester.measureWrapper(A11Y_EVENTS.GET_RESULTS, async (isAppAutomate, browser, isBrowserStackSession, isAccessibility) => {
|
|
4023
4232
|
if (!isAccessibilityAutomationSession(isAccessibility)) {
|
|
4024
|
-
|
|
4233
|
+
BStackLogger.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results.");
|
|
4025
4234
|
return [];
|
|
4026
4235
|
}
|
|
4027
4236
|
try {
|
|
4028
|
-
|
|
4237
|
+
BStackLogger.debug("Performing scan before getting results");
|
|
4029
4238
|
await performA11yScan(isAppAutomate, browser, isBrowserStackSession, isAccessibility);
|
|
4030
4239
|
if (accessibility_scripts_default.getResults) {
|
|
4031
4240
|
const results = await executeAccessibilityScript(browser, accessibility_scripts_default.getResults);
|
|
4032
4241
|
return results;
|
|
4033
4242
|
}
|
|
4034
|
-
|
|
4243
|
+
BStackLogger.error("AccessibilityScripts.getResults is null");
|
|
4035
4244
|
return [];
|
|
4036
4245
|
} catch (error) {
|
|
4037
|
-
|
|
4038
|
-
|
|
4246
|
+
BStackLogger.error("No accessibility results were found.");
|
|
4247
|
+
BStackLogger.debug(`getA11yResults Failed. Error: ${error}`);
|
|
4039
4248
|
return [];
|
|
4040
4249
|
}
|
|
4041
4250
|
});
|
|
@@ -4044,18 +4253,18 @@ var init_util = __esm({
|
|
|
4044
4253
|
return [];
|
|
4045
4254
|
}
|
|
4046
4255
|
if (!isAppAccessibilityAutomationSession(isAccessibility, isAppAutomate)) {
|
|
4047
|
-
|
|
4256
|
+
BStackLogger.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results summary.");
|
|
4048
4257
|
return [];
|
|
4049
4258
|
}
|
|
4050
4259
|
try {
|
|
4051
4260
|
const apiUrl = `${APIUtils.APP_ALLY_ENDPOINT}/${APP_ALLY_ISSUES_ENDPOINT}`;
|
|
4052
4261
|
const apiRespone = await getAppA11yResultResponse(apiUrl, isAppAutomate, browser, testName, isBrowserStackSession, isAccessibility, sessionId);
|
|
4053
4262
|
const result = apiRespone?.data?.data?.issues;
|
|
4054
|
-
|
|
4263
|
+
BStackLogger.debug(`Polling Result: ${JSON.stringify(result)}`);
|
|
4055
4264
|
return result;
|
|
4056
4265
|
} catch (error) {
|
|
4057
|
-
|
|
4058
|
-
|
|
4266
|
+
BStackLogger.error("No accessibility summary was found.");
|
|
4267
|
+
BStackLogger.debug(`getAppA11yResults Failed. Error: ${error}`);
|
|
4059
4268
|
return [];
|
|
4060
4269
|
}
|
|
4061
4270
|
});
|
|
@@ -4064,46 +4273,46 @@ var init_util = __esm({
|
|
|
4064
4273
|
return {};
|
|
4065
4274
|
}
|
|
4066
4275
|
if (!isAppAccessibilityAutomationSession(isAccessibility, isAppAutomate)) {
|
|
4067
|
-
|
|
4276
|
+
BStackLogger.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results summary.");
|
|
4068
4277
|
return {};
|
|
4069
4278
|
}
|
|
4070
4279
|
try {
|
|
4071
4280
|
const apiUrl = `${APIUtils.APP_ALLY_ENDPOINT}/${APP_ALLY_ISSUES_SUMMARY_ENDPOINT}`;
|
|
4072
4281
|
const apiRespone = await getAppA11yResultResponse(apiUrl, isAppAutomate, browser, testName, isBrowserStackSession, isAccessibility, sessionId);
|
|
4073
4282
|
const result = apiRespone?.data?.data?.summary;
|
|
4074
|
-
|
|
4283
|
+
BStackLogger.debug(`Polling Result: ${JSON.stringify(result)}`);
|
|
4075
4284
|
return result;
|
|
4076
4285
|
} catch {
|
|
4077
|
-
|
|
4286
|
+
BStackLogger.error("No accessibility summary was found.");
|
|
4078
4287
|
return {};
|
|
4079
4288
|
}
|
|
4080
4289
|
});
|
|
4081
4290
|
getAppA11yResultResponse = async (apiUrl, isAppAutomate, browser, testName, isBrowserStackSession, isAccessibility, sessionId) => {
|
|
4082
|
-
|
|
4291
|
+
BStackLogger.debug("Performing scan before getting results summary");
|
|
4083
4292
|
await performA11yScan(isAppAutomate, browser, isBrowserStackSession, isAccessibility, void 0, testName);
|
|
4084
4293
|
const upperTimeLimit = process.env.BSTACK_A11Y_POLLING_TIMEOUT ? Date.now() + parseInt(process.env.BSTACK_A11Y_POLLING_TIMEOUT) * 1e3 : Date.now() + 3e4;
|
|
4085
4294
|
const params = { test_run_uuid: process.env.TEST_ANALYTICS_ID, session_id: sessionId, timestamp: Date.now() };
|
|
4086
4295
|
const header = { Authorization: `Bearer ${process.env.BSTACK_A11Y_JWT}` };
|
|
4087
4296
|
const apiRespone = await pollApi(apiUrl, params, header, upperTimeLimit);
|
|
4088
|
-
|
|
4297
|
+
BStackLogger.debug(`Polling Result: ${JSON.stringify(apiRespone)}`);
|
|
4089
4298
|
return apiRespone;
|
|
4090
4299
|
};
|
|
4091
4300
|
getA11yResultsSummary = PerformanceTester.measureWrapper(A11Y_EVENTS.GET_RESULTS_SUMMARY, async (isAppAutomate, browser, isBrowserStackSession, isAccessibility) => {
|
|
4092
4301
|
if (!isAccessibilityAutomationSession(isAccessibility)) {
|
|
4093
|
-
|
|
4302
|
+
BStackLogger.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results summary.");
|
|
4094
4303
|
return {};
|
|
4095
4304
|
}
|
|
4096
4305
|
try {
|
|
4097
|
-
|
|
4306
|
+
BStackLogger.debug("Performing scan before getting results summary");
|
|
4098
4307
|
await performA11yScan(isAppAutomate, browser, isBrowserStackSession, isAccessibility);
|
|
4099
4308
|
if (accessibility_scripts_default.getResultsSummary) {
|
|
4100
4309
|
const summaryResults = await executeAccessibilityScript(browser, accessibility_scripts_default.getResultsSummary);
|
|
4101
4310
|
return summaryResults;
|
|
4102
4311
|
}
|
|
4103
|
-
|
|
4312
|
+
BStackLogger.error("AccessibilityScripts.getResultsSummary is null");
|
|
4104
4313
|
return {};
|
|
4105
4314
|
} catch {
|
|
4106
|
-
|
|
4315
|
+
BStackLogger.error("No accessibility summary was found.");
|
|
4107
4316
|
return {};
|
|
4108
4317
|
}
|
|
4109
4318
|
});
|
|
@@ -4119,7 +4328,7 @@ var init_util = __esm({
|
|
|
4119
4328
|
}
|
|
4120
4329
|
if (!process.env[BROWSERSTACK_TESTHUB_JWT]) {
|
|
4121
4330
|
stopBuildUsage.failed("Token/buildID is undefined, build creation might have failed");
|
|
4122
|
-
|
|
4331
|
+
BStackLogger.debug("[STOP_BUILD] Missing Authentication Token/ Build ID");
|
|
4123
4332
|
return {
|
|
4124
4333
|
status: "error",
|
|
4125
4334
|
message: "Token/buildID is undefined, build creation might have failed"
|
|
@@ -4138,7 +4347,7 @@ var init_util = __esm({
|
|
|
4138
4347
|
},
|
|
4139
4348
|
body: JSON.stringify(data)
|
|
4140
4349
|
});
|
|
4141
|
-
|
|
4350
|
+
BStackLogger.debug(`[STOP_BUILD] Success response: ${await response.text()}`);
|
|
4142
4351
|
stopBuildUsage.success();
|
|
4143
4352
|
return {
|
|
4144
4353
|
status: "success",
|
|
@@ -4146,7 +4355,7 @@ var init_util = __esm({
|
|
|
4146
4355
|
};
|
|
4147
4356
|
} catch (error) {
|
|
4148
4357
|
stopBuildUsage.failed(error);
|
|
4149
|
-
|
|
4358
|
+
BStackLogger.debug(`[STOP_BUILD] Failed. Error: ${error}`);
|
|
4150
4359
|
return {
|
|
4151
4360
|
status: "error",
|
|
4152
4361
|
message: error.message
|
|
@@ -4157,7 +4366,7 @@ var init_util = __esm({
|
|
|
4157
4366
|
const BSTestOpsPatcher = new logPatcher_default({});
|
|
4158
4367
|
Object.keys(consoleHolder).forEach((method) => {
|
|
4159
4368
|
if (!(method in console) || method === "Console" || typeof console[method] !== "function") {
|
|
4160
|
-
|
|
4369
|
+
BStackLogger.debug(`Skipping method: ${method}, exists: ${method in console}, type: ${typeof console[method]}`);
|
|
4161
4370
|
return;
|
|
4162
4371
|
}
|
|
4163
4372
|
const origMethod = console[method].bind(console);
|
|
@@ -4170,7 +4379,7 @@ var init_util = __esm({
|
|
|
4170
4379
|
BSTestOpsPatcher[method](...args);
|
|
4171
4380
|
}
|
|
4172
4381
|
} catch (error) {
|
|
4173
|
-
|
|
4382
|
+
BStackLogger.debug(`Error while patching console logs : ${error}`);
|
|
4174
4383
|
origMethod(...args);
|
|
4175
4384
|
}
|
|
4176
4385
|
};
|
|
@@ -4204,18 +4413,57 @@ var init_util = __esm({
|
|
|
4204
4413
|
const keys = ["platformVersion", "platform_version", "osVersion", "os_version"];
|
|
4205
4414
|
for (const key of keys) {
|
|
4206
4415
|
if (caps?.[key]) {
|
|
4207
|
-
|
|
4416
|
+
BStackLogger.debug(`Got ${key} from driver caps`);
|
|
4208
4417
|
return String(caps?.[key]);
|
|
4209
4418
|
} else if (bstackOptions && bstackOptions?.[key]) {
|
|
4210
|
-
|
|
4419
|
+
BStackLogger.debug(`Got ${key} from user bstack options`);
|
|
4211
4420
|
return String(bstackOptions?.[key]);
|
|
4212
4421
|
} else if (userCaps[key]) {
|
|
4213
|
-
|
|
4422
|
+
BStackLogger.debug(`Got ${key} from user caps`);
|
|
4214
4423
|
return String(userCaps[key]);
|
|
4215
4424
|
}
|
|
4216
4425
|
}
|
|
4217
4426
|
return void 0;
|
|
4218
4427
|
});
|
|
4428
|
+
getResolvedDeviceName = o11yErrorHandler(function getResolvedDeviceName2(driverCaps, requestedCaps) {
|
|
4429
|
+
const flattenMultiremote = (caps) => {
|
|
4430
|
+
if (!caps) {
|
|
4431
|
+
return [];
|
|
4432
|
+
}
|
|
4433
|
+
const obj = caps;
|
|
4434
|
+
if (obj["deviceModel"] || obj["appium:deviceModel"] || obj["deviceName"] || obj["bstack:options"]) {
|
|
4435
|
+
return [caps];
|
|
4436
|
+
}
|
|
4437
|
+
return Object.values(obj).filter((v) => v !== null && typeof v === "object" && "capabilities" in v).map((v) => v.capabilities).filter(Boolean);
|
|
4438
|
+
};
|
|
4439
|
+
const sources = [
|
|
4440
|
+
...flattenMultiremote(driverCaps),
|
|
4441
|
+
...flattenMultiremote(requestedCaps)
|
|
4442
|
+
];
|
|
4443
|
+
if (!sources.length) {
|
|
4444
|
+
return void 0;
|
|
4445
|
+
}
|
|
4446
|
+
const pickString = (obj, key) => {
|
|
4447
|
+
const v = obj?.[key];
|
|
4448
|
+
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
4449
|
+
};
|
|
4450
|
+
const paths = [
|
|
4451
|
+
(c) => pickString(c, "deviceModel"),
|
|
4452
|
+
(c) => pickString(c, "appium:deviceModel"),
|
|
4453
|
+
(c) => pickString(c["bstack:options"], "deviceName"),
|
|
4454
|
+
(c) => pickString(c, "appium:deviceName"),
|
|
4455
|
+
(c) => pickString(c, "deviceName")
|
|
4456
|
+
];
|
|
4457
|
+
for (const path22 of paths) {
|
|
4458
|
+
for (const src of sources) {
|
|
4459
|
+
const v = path22(src);
|
|
4460
|
+
if (v) {
|
|
4461
|
+
return v;
|
|
4462
|
+
}
|
|
4463
|
+
}
|
|
4464
|
+
}
|
|
4465
|
+
return void 0;
|
|
4466
|
+
});
|
|
4219
4467
|
getBasicAuthHeader = (username, password) => {
|
|
4220
4468
|
const encodedAuth = Buffer.from(`${username}:${password}`, "utf8").toString("base64");
|
|
4221
4469
|
return `Basic ${encodedAuth}`;
|
|
@@ -4259,20 +4507,20 @@ var init_util = __esm({
|
|
|
4259
4507
|
});
|
|
4260
4508
|
|
|
4261
4509
|
// src/bstackLogger.ts
|
|
4262
|
-
import
|
|
4263
|
-
import
|
|
4510
|
+
import path7 from "node:path";
|
|
4511
|
+
import fs8 from "node:fs";
|
|
4264
4512
|
import chalk2 from "chalk";
|
|
4265
4513
|
import logger2 from "@wdio/logger";
|
|
4266
|
-
var log2,
|
|
4514
|
+
var log2, BStackLogger;
|
|
4267
4515
|
var init_bstackLogger = __esm({
|
|
4268
4516
|
"src/bstackLogger.ts"() {
|
|
4269
4517
|
"use strict";
|
|
4270
4518
|
init_constants();
|
|
4271
4519
|
init_util();
|
|
4272
4520
|
log2 = logger2("@wdio/browserstack-service");
|
|
4273
|
-
|
|
4274
|
-
static logFilePath =
|
|
4275
|
-
static logFolderPath =
|
|
4521
|
+
BStackLogger = class {
|
|
4522
|
+
static logFilePath = path7.join(process.cwd(), LOGS_FILE);
|
|
4523
|
+
static logFolderPath = path7.join(process.cwd(), "logs");
|
|
4276
4524
|
static logFileStream;
|
|
4277
4525
|
static redactCredentials(logMessage) {
|
|
4278
4526
|
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 +4530,7 @@ var init_bstackLogger = __esm({
|
|
|
4282
4530
|
const redactedMessage = this.redactCredentials(logMessage);
|
|
4283
4531
|
if (!this.logFileStream) {
|
|
4284
4532
|
this.ensureLogsFolder();
|
|
4285
|
-
this.logFileStream =
|
|
4533
|
+
this.logFileStream = fs8.createWriteStream(this.logFilePath, { flags: "a" });
|
|
4286
4534
|
}
|
|
4287
4535
|
if (this.logFileStream && this.logFileStream.writable) {
|
|
4288
4536
|
this.logFileStream.write(this.formatLog(redactedMessage, logLevel));
|
|
@@ -4331,13 +4579,13 @@ var init_bstackLogger = __esm({
|
|
|
4331
4579
|
this.logFileStream = null;
|
|
4332
4580
|
}
|
|
4333
4581
|
static clearLogFile() {
|
|
4334
|
-
if (
|
|
4335
|
-
|
|
4582
|
+
if (fs8.existsSync(this.logFilePath)) {
|
|
4583
|
+
fs8.truncateSync(this.logFilePath);
|
|
4336
4584
|
}
|
|
4337
4585
|
}
|
|
4338
4586
|
static ensureLogsFolder() {
|
|
4339
|
-
if (!
|
|
4340
|
-
|
|
4587
|
+
if (!fs8.existsSync(this.logFolderPath)) {
|
|
4588
|
+
fs8.mkdirSync(this.logFolderPath);
|
|
4341
4589
|
}
|
|
4342
4590
|
}
|
|
4343
4591
|
};
|
|
@@ -4355,7 +4603,7 @@ var init_utils = __esm({
|
|
|
4355
4603
|
getProductMap = (config) => {
|
|
4356
4604
|
const entries = [
|
|
4357
4605
|
["observability", config.testObservability.enabled],
|
|
4358
|
-
["accessibility", config.accessibility],
|
|
4606
|
+
["accessibility", !!config.accessibility],
|
|
4359
4607
|
["percy", config.percy],
|
|
4360
4608
|
["automate", config.automate],
|
|
4361
4609
|
["app_automate", config.appAutomate]
|
|
@@ -4384,7 +4632,7 @@ var init_utils = __esm({
|
|
|
4384
4632
|
};
|
|
4385
4633
|
logBuildError = (error, product = "") => {
|
|
4386
4634
|
if (!error || !error.errors) {
|
|
4387
|
-
|
|
4635
|
+
BStackLogger.error(`${product.toUpperCase()} Build creation failed ${error}`);
|
|
4388
4636
|
return;
|
|
4389
4637
|
}
|
|
4390
4638
|
for (const errorJson of error.errors) {
|
|
@@ -4393,16 +4641,16 @@ var init_utils = __esm({
|
|
|
4393
4641
|
if (errorMessage) {
|
|
4394
4642
|
switch (errorType) {
|
|
4395
4643
|
case "ERROR_INVALID_CREDENTIALS":
|
|
4396
|
-
|
|
4644
|
+
BStackLogger.error(errorMessage);
|
|
4397
4645
|
break;
|
|
4398
4646
|
case "ERROR_ACCESS_DENIED":
|
|
4399
|
-
|
|
4647
|
+
BStackLogger.info(errorMessage);
|
|
4400
4648
|
break;
|
|
4401
4649
|
case "ERROR_SDK_DEPRECATED":
|
|
4402
|
-
|
|
4650
|
+
BStackLogger.error(errorMessage);
|
|
4403
4651
|
break;
|
|
4404
4652
|
default:
|
|
4405
|
-
|
|
4653
|
+
BStackLogger.error(errorMessage);
|
|
4406
4654
|
}
|
|
4407
4655
|
}
|
|
4408
4656
|
}
|
|
@@ -4421,8 +4669,8 @@ var init_utils = __esm({
|
|
|
4421
4669
|
});
|
|
4422
4670
|
|
|
4423
4671
|
// src/Percy/PercyLogger.ts
|
|
4424
|
-
import
|
|
4425
|
-
import
|
|
4672
|
+
import path8 from "node:path";
|
|
4673
|
+
import fs9 from "node:fs";
|
|
4426
4674
|
import chalk3 from "chalk";
|
|
4427
4675
|
import logger3 from "@wdio/logger";
|
|
4428
4676
|
var log3, PercyLogger;
|
|
@@ -4433,16 +4681,16 @@ var init_PercyLogger = __esm({
|
|
|
4433
4681
|
init_util();
|
|
4434
4682
|
log3 = logger3("@wdio/browserstack-service");
|
|
4435
4683
|
PercyLogger = class {
|
|
4436
|
-
static logFilePath =
|
|
4437
|
-
static logFolderPath =
|
|
4684
|
+
static logFilePath = path8.join(process.cwd(), PERCY_LOGS_FILE);
|
|
4685
|
+
static logFolderPath = path8.join(process.cwd(), "logs");
|
|
4438
4686
|
static logFileStream;
|
|
4439
4687
|
static logToFile(logMessage, logLevel) {
|
|
4440
4688
|
try {
|
|
4441
4689
|
if (!this.logFileStream) {
|
|
4442
|
-
if (!
|
|
4443
|
-
|
|
4690
|
+
if (!fs9.existsSync(this.logFolderPath)) {
|
|
4691
|
+
fs9.mkdirSync(this.logFolderPath);
|
|
4444
4692
|
}
|
|
4445
|
-
this.logFileStream =
|
|
4693
|
+
this.logFileStream = fs9.createWriteStream(this.logFilePath, { flags: "a" });
|
|
4446
4694
|
}
|
|
4447
4695
|
if (this.logFileStream && this.logFileStream.writable) {
|
|
4448
4696
|
this.logFileStream.write(this.formatLog(logMessage, logLevel));
|
|
@@ -4486,8 +4734,8 @@ var init_PercyLogger = __esm({
|
|
|
4486
4734
|
this.logFileStream = null;
|
|
4487
4735
|
}
|
|
4488
4736
|
static clearLogFile() {
|
|
4489
|
-
if (
|
|
4490
|
-
|
|
4737
|
+
if (fs9.existsSync(this.logFilePath)) {
|
|
4738
|
+
fs9.truncateSync(this.logFilePath);
|
|
4491
4739
|
}
|
|
4492
4740
|
}
|
|
4493
4741
|
};
|
|
@@ -4495,7 +4743,7 @@ var init_PercyLogger = __esm({
|
|
|
4495
4743
|
});
|
|
4496
4744
|
|
|
4497
4745
|
// src/cli/grpcClient.ts
|
|
4498
|
-
import
|
|
4746
|
+
import path13 from "node:path";
|
|
4499
4747
|
import util5, { promisify as promisify3 } from "node:util";
|
|
4500
4748
|
import {
|
|
4501
4749
|
SDKClient,
|
|
@@ -4528,7 +4776,7 @@ var init_grpcClient = __esm({
|
|
|
4528
4776
|
listenAddress;
|
|
4529
4777
|
channel = null;
|
|
4530
4778
|
client = null;
|
|
4531
|
-
logger =
|
|
4779
|
+
logger = BStackLogger2;
|
|
4532
4780
|
constructor() {
|
|
4533
4781
|
}
|
|
4534
4782
|
/**
|
|
@@ -4620,7 +4868,7 @@ var init_grpcClient = __esm({
|
|
|
4620
4868
|
sdkLanguage: CLIUtils.getSdkLanguage(),
|
|
4621
4869
|
sdkVersion: packageVersion,
|
|
4622
4870
|
pathProject: process.cwd(),
|
|
4623
|
-
pathConfig:
|
|
4871
|
+
pathConfig: path13.resolve(process.cwd(), "browserstack.yml"),
|
|
4624
4872
|
cliArgs: process.argv.slice(2),
|
|
4625
4873
|
frameworks: [automationFrameworkDetail.name, testFrameworkDetail.name],
|
|
4626
4874
|
frameworkVersions,
|
|
@@ -5066,7 +5314,7 @@ var init_baseModule = __esm({
|
|
|
5066
5314
|
this.platformIndex = platformIndex;
|
|
5067
5315
|
this.client = client;
|
|
5068
5316
|
this.config = config;
|
|
5069
|
-
|
|
5317
|
+
BStackLogger2.debug(`Configured module ${this.getModuleName()} with binSessionId=${binSessionId}, platformIndex=${platformIndex}`);
|
|
5070
5318
|
}
|
|
5071
5319
|
};
|
|
5072
5320
|
}
|
|
@@ -5337,7 +5585,7 @@ var init_testFramework = __esm({
|
|
|
5337
5585
|
* @returns {void}
|
|
5338
5586
|
*/
|
|
5339
5587
|
trackEvent(testFrameworkState, hookState, args = {}) {
|
|
5340
|
-
|
|
5588
|
+
BStackLogger2.info(`trackEvent: testFrameworkState=${testFrameworkState}; hookState=${hookState}; args=${args}`);
|
|
5341
5589
|
}
|
|
5342
5590
|
/**
|
|
5343
5591
|
* run test hooks
|
|
@@ -5347,7 +5595,7 @@ var init_testFramework = __esm({
|
|
|
5347
5595
|
* @param {*} args
|
|
5348
5596
|
*/
|
|
5349
5597
|
async runHooks(instance, testFrameworkState, hookState, args = {}) {
|
|
5350
|
-
|
|
5598
|
+
BStackLogger2.info(`runHooks: instance=${instance} automationFrameworkState=${testFrameworkState} hookState=${hookState}`);
|
|
5351
5599
|
const hookRegistryKey = CLIUtils.getHookRegistryKey(testFrameworkState, hookState);
|
|
5352
5600
|
await eventDispatcher.notifyObserver(hookRegistryKey, args);
|
|
5353
5601
|
}
|
|
@@ -5611,7 +5859,7 @@ var init_automationFramework = __esm({
|
|
|
5611
5859
|
* @returns {void}
|
|
5612
5860
|
*/
|
|
5613
5861
|
async trackEvent(automationFrameworkState, hookState, args = {}) {
|
|
5614
|
-
|
|
5862
|
+
BStackLogger2.info(`trackEvent: automationFrameworkState=${automationFrameworkState} hookState=${hookState} args=${args}`);
|
|
5615
5863
|
}
|
|
5616
5864
|
/**
|
|
5617
5865
|
*
|
|
@@ -5621,7 +5869,7 @@ var init_automationFramework = __esm({
|
|
|
5621
5869
|
* @param {*} args
|
|
5622
5870
|
*/
|
|
5623
5871
|
async runHooks(instance, automationFrameworkState, hookState, args = {}) {
|
|
5624
|
-
|
|
5872
|
+
BStackLogger2.info(`runHooks: automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
|
|
5625
5873
|
const hookRegistryKey = CLIUtils.getHookRegistryKey(automationFrameworkState, hookState);
|
|
5626
5874
|
await eventDispatcher.notifyObserver(hookRegistryKey, args);
|
|
5627
5875
|
}
|
|
@@ -5639,7 +5887,7 @@ var init_automationFramework = __esm({
|
|
|
5639
5887
|
* @returns {void}
|
|
5640
5888
|
*/
|
|
5641
5889
|
static setTrackedInstance(context, instance) {
|
|
5642
|
-
|
|
5890
|
+
BStackLogger2.debug(`setTrackedInstance: ${context.getId()}`);
|
|
5643
5891
|
_AutomationFramework.instances.set(context.getId(), instance);
|
|
5644
5892
|
}
|
|
5645
5893
|
/**
|
|
@@ -5647,7 +5895,7 @@ var init_automationFramework = __esm({
|
|
|
5647
5895
|
* @returns {TrackedInstance} The tracked instance
|
|
5648
5896
|
*/
|
|
5649
5897
|
static getTrackedInstance() {
|
|
5650
|
-
|
|
5898
|
+
BStackLogger2.debug(`getTrackedInstance: ${CLIUtils.getCurrentInstanceName()}`);
|
|
5651
5899
|
const context = TrackedInstance.createContext(CLIUtils.getCurrentInstanceName());
|
|
5652
5900
|
return _AutomationFramework.instances.get(context.getId());
|
|
5653
5901
|
}
|
|
@@ -5775,7 +6023,7 @@ var init_automateModule = __esm({
|
|
|
5775
6023
|
init_automationFrameworkState();
|
|
5776
6024
|
init_fetchWrapper();
|
|
5777
6025
|
AutomateModule = class _AutomateModule extends BaseModule {
|
|
5778
|
-
logger =
|
|
6026
|
+
logger = BStackLogger2;
|
|
5779
6027
|
browserStackConfig;
|
|
5780
6028
|
sessionMap = /* @__PURE__ */ new Map();
|
|
5781
6029
|
static MODULE_NAME = "AutomateModule";
|
|
@@ -6091,7 +6339,7 @@ var init_testFrameworkInstance = __esm({
|
|
|
6091
6339
|
|
|
6092
6340
|
// src/cli/frameworks/wdioMochaTestFramework.ts
|
|
6093
6341
|
import { v4 as uuidv42 } from "uuid";
|
|
6094
|
-
import
|
|
6342
|
+
import path14 from "node:path";
|
|
6095
6343
|
var WdioMochaTestFramework;
|
|
6096
6344
|
var init_wdioMochaTestFramework = __esm({
|
|
6097
6345
|
"src/cli/frameworks/wdioMochaTestFramework.ts"() {
|
|
@@ -6125,11 +6373,11 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6125
6373
|
* @param {*} args
|
|
6126
6374
|
*/
|
|
6127
6375
|
async trackEvent(testFrameworkState, hookState, args = {}) {
|
|
6128
|
-
|
|
6376
|
+
BStackLogger2.info(`trackEvent: testFrameworkState=${testFrameworkState} hookState=${hookState}`);
|
|
6129
6377
|
await super.trackEvent(testFrameworkState, hookState, args);
|
|
6130
6378
|
const instance = this.resolveInstance(testFrameworkState, hookState, args);
|
|
6131
6379
|
if (instance === null) {
|
|
6132
|
-
|
|
6380
|
+
BStackLogger2.error(`trackEvent: instance not found for testFrameworkState=${testFrameworkState} hookState=${hookState}`);
|
|
6133
6381
|
return;
|
|
6134
6382
|
}
|
|
6135
6383
|
try {
|
|
@@ -6141,7 +6389,7 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6141
6389
|
if (!TestFramework.getState(instance, TestFrameworkConstants.KEY_TEST_ID) && hookState === HookState.PRE && testFrameworkState === TestFrameworkState.TEST) {
|
|
6142
6390
|
const test = args.test;
|
|
6143
6391
|
const testData = await this.getTestData(instance, test);
|
|
6144
|
-
|
|
6392
|
+
BStackLogger2.info(`trackEvent: instanceData=${JSON.stringify(Object.fromEntries(instance.getAllData()))}`);
|
|
6145
6393
|
instance.updateMultipleEntries(testData);
|
|
6146
6394
|
}
|
|
6147
6395
|
if (testFrameworkState === TestFrameworkState.TEST) {
|
|
@@ -6159,13 +6407,13 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6159
6407
|
logEntry.uuid = TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOK_ID);
|
|
6160
6408
|
this.loadLogEntries(instance, testFrameworkState, hookState, logEntry);
|
|
6161
6409
|
} else if (testFrameworkState === TestFrameworkState.LOG_REPORT && hookState === HookState.POST) {
|
|
6162
|
-
|
|
6410
|
+
BStackLogger2.info("trackEvent: load test results");
|
|
6163
6411
|
this.loadTestResult(instance, args);
|
|
6164
6412
|
}
|
|
6165
6413
|
await this.trackHookEvents(instance, testFrameworkState, hookState, args);
|
|
6166
|
-
|
|
6414
|
+
BStackLogger2.debug(`trackEvent: tracked instance data=${JSON.stringify(Object.fromEntries(instance.getAllData()))}`);
|
|
6167
6415
|
} catch (error) {
|
|
6168
|
-
|
|
6416
|
+
BStackLogger2.error(`trackEvent: Error in tracking events: ${error} hookState=${hookState} testFrameworkState=${testFrameworkState}`);
|
|
6169
6417
|
}
|
|
6170
6418
|
args.instance = instance;
|
|
6171
6419
|
await this.runHooks(instance, testFrameworkState, hookState, args);
|
|
@@ -6179,7 +6427,7 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6179
6427
|
*/
|
|
6180
6428
|
resolveInstance(testFrameworkState, hookState, args = {}) {
|
|
6181
6429
|
let instance = null;
|
|
6182
|
-
|
|
6430
|
+
BStackLogger2.info(`resolveInstance: resolving instance for testFrameworkState=${testFrameworkState} hookState=${hookState}`);
|
|
6183
6431
|
if (testFrameworkState === TestFrameworkState.INIT_TEST || testFrameworkState === TestFrameworkState.NONE) {
|
|
6184
6432
|
this.trackWdioMochaInstance(testFrameworkState, args);
|
|
6185
6433
|
}
|
|
@@ -6196,7 +6444,7 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6196
6444
|
const target = CLIUtils.getCurrentInstanceName();
|
|
6197
6445
|
const trackedContext = TrackedInstance.createContext(target);
|
|
6198
6446
|
let instance = null;
|
|
6199
|
-
|
|
6447
|
+
BStackLogger2.info(`trackWdioMochaInstance: created instance for target=${target}, state=${testFrameworkState}, args=${args}`);
|
|
6200
6448
|
instance = new TestFrameworkInstance(
|
|
6201
6449
|
trackedContext,
|
|
6202
6450
|
this.getTestFrameworks(),
|
|
@@ -6219,7 +6467,7 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6219
6467
|
process.env[TEST_ANALYTICS_ID] = instanceEntries[TestFrameworkConstants.KEY_TEST_UUID];
|
|
6220
6468
|
instance.updateMultipleEntries(instanceEntries);
|
|
6221
6469
|
TestFramework.setTrackedInstance(trackedContext, instance);
|
|
6222
|
-
|
|
6470
|
+
BStackLogger2.info(`trackWdioMochaInstance: saved instance contextId=${trackedContext.getId()} target=${target}`);
|
|
6223
6471
|
}
|
|
6224
6472
|
async getTestData(instance, test) {
|
|
6225
6473
|
const framework = TestFramework.getState(instance, TestFrameworkConstants.KEY_TEST_FRAMEWORK_NAME);
|
|
@@ -6230,8 +6478,8 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6230
6478
|
[TestFrameworkConstants.KEY_TEST_ID]: getUniqueIdentifier(test, framework),
|
|
6231
6479
|
[TestFrameworkConstants.KEY_TEST_NAME]: test.title || test.description,
|
|
6232
6480
|
[TestFrameworkConstants.KEY_TEST_CODE]: test.body || "",
|
|
6233
|
-
[TestFrameworkConstants.KEY_TEST_FILE_PATH]: gitConfig?.root && filename ?
|
|
6234
|
-
[TestFrameworkConstants.KEY_TEST_LOCATION]: filename ?
|
|
6481
|
+
[TestFrameworkConstants.KEY_TEST_FILE_PATH]: gitConfig?.root && filename ? path14.relative(gitConfig.root, filename) : void 0,
|
|
6482
|
+
[TestFrameworkConstants.KEY_TEST_LOCATION]: filename ? path14.relative(process.cwd(), filename) : void 0,
|
|
6235
6483
|
[TestFrameworkConstants.KEY_TEST_SCOPE]: fullTitle,
|
|
6236
6484
|
[TestFrameworkConstants.KEY_TEST_SCOPES]: getMochaTestHierarchy(test)
|
|
6237
6485
|
};
|
|
@@ -6284,7 +6532,7 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6284
6532
|
if (lastActiveHook) {
|
|
6285
6533
|
const hookLogs = lastActiveHook[TestFrameworkConstants.KEY_HOOK_LOGS];
|
|
6286
6534
|
hookLogs.push(logRecord);
|
|
6287
|
-
|
|
6535
|
+
BStackLogger2.debug(`hooks after update logs ${TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOKS_STARTED)} ${TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOKS_FINISHED)}`);
|
|
6288
6536
|
return;
|
|
6289
6537
|
}
|
|
6290
6538
|
const entries = TestFramework.getState(instance, TestFrameworkConstants.KEY_TEST_LOGS);
|
|
@@ -6385,15 +6633,15 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6385
6633
|
[TestFrameworkConstants.KEY_EVENT_STARTED_AT]: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6386
6634
|
[TestFrameworkConstants.KEY_HOOK_LOGS]: [],
|
|
6387
6635
|
[TestFrameworkConstants.KEY_HOOK_NAME]: test.title || test.description,
|
|
6388
|
-
[TestFrameworkConstants.KEY_TEST_FILE_PATH]: gitConfig?.root && filename ?
|
|
6389
|
-
[TestFrameworkConstants.KEY_TEST_LOCATION]: filename ?
|
|
6636
|
+
[TestFrameworkConstants.KEY_TEST_FILE_PATH]: gitConfig?.root && filename ? path14.relative(gitConfig.root, filename) : void 0,
|
|
6637
|
+
[TestFrameworkConstants.KEY_TEST_LOCATION]: filename ? path14.relative(process.cwd(), filename) : void 0
|
|
6390
6638
|
};
|
|
6391
6639
|
hooksStarted.get(key)?.push(hook);
|
|
6392
6640
|
updates[_WdioMochaTestFramework.KEY_HOOK_LAST_STARTED] = key;
|
|
6393
|
-
|
|
6641
|
+
BStackLogger2.info(`Hook Started in PRE key = ${key} & hook = ${JSON.stringify(hook)}`);
|
|
6394
6642
|
} else if (hookState === HookState.POST) {
|
|
6395
6643
|
const hooksList = hooksStarted.get(key) || [];
|
|
6396
|
-
|
|
6644
|
+
BStackLogger2.info(`Hook List in Post ${JSON.stringify(hooksList)}`);
|
|
6397
6645
|
if (hooksList.length > 0) {
|
|
6398
6646
|
const hook = hooksList.pop();
|
|
6399
6647
|
const result = testResult.status;
|
|
@@ -6406,7 +6654,7 @@ var init_wdioMochaTestFramework = __esm({
|
|
|
6406
6654
|
}
|
|
6407
6655
|
}
|
|
6408
6656
|
instance.updateMultipleEntries(updates);
|
|
6409
|
-
|
|
6657
|
+
BStackLogger2.info(`trackHookEvents: hook state=${key}.${hookState}, hooks started=${JSON.stringify(hooksStarted)}, hooks finished=${JSON.stringify(hooksFinished)}`);
|
|
6410
6658
|
}
|
|
6411
6659
|
};
|
|
6412
6660
|
}
|
|
@@ -6430,7 +6678,7 @@ var init_testHubModule = __esm({
|
|
|
6430
6678
|
init_automationFramework();
|
|
6431
6679
|
init_automationFrameworkConstants();
|
|
6432
6680
|
TestHubModule = class _TestHubModule extends BaseModule {
|
|
6433
|
-
logger =
|
|
6681
|
+
logger = BStackLogger2;
|
|
6434
6682
|
testhubConfig;
|
|
6435
6683
|
name;
|
|
6436
6684
|
static MODULE_NAME = "TestHubModule";
|
|
@@ -6703,11 +6951,11 @@ var init_wdioAutomationFramework = __esm({
|
|
|
6703
6951
|
* @param {*} args
|
|
6704
6952
|
*/
|
|
6705
6953
|
async trackEvent(automationFrameworkState, hookState, args = {}) {
|
|
6706
|
-
|
|
6954
|
+
BStackLogger2.info(`trackEvent: automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
|
|
6707
6955
|
await super.trackEvent(automationFrameworkState, hookState, args);
|
|
6708
6956
|
const instance = this.resolveInstance(automationFrameworkState, hookState, args);
|
|
6709
6957
|
if (instance === null) {
|
|
6710
|
-
|
|
6958
|
+
BStackLogger2.error(`trackEvent: instance not found for automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
|
|
6711
6959
|
return;
|
|
6712
6960
|
}
|
|
6713
6961
|
args.instance = instance;
|
|
@@ -6722,7 +6970,7 @@ var init_wdioAutomationFramework = __esm({
|
|
|
6722
6970
|
*/
|
|
6723
6971
|
resolveInstance(automationFrameworkState, hookState, args = {}) {
|
|
6724
6972
|
let instance = null;
|
|
6725
|
-
|
|
6973
|
+
BStackLogger2.info(`resolveInstance: resolving instance for automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
|
|
6726
6974
|
if (automationFrameworkState === AutomationFrameworkState.CREATE || automationFrameworkState === AutomationFrameworkState.NONE) {
|
|
6727
6975
|
this.trackWebdriverIOInstance(automationFrameworkState, args);
|
|
6728
6976
|
}
|
|
@@ -6738,13 +6986,13 @@ var init_wdioAutomationFramework = __esm({
|
|
|
6738
6986
|
// !args.browser &&
|
|
6739
6987
|
AutomationFramework.getTrackedInstance()
|
|
6740
6988
|
) {
|
|
6741
|
-
|
|
6989
|
+
BStackLogger2.info("trackWebdriverIOInstance: instance already exists");
|
|
6742
6990
|
return;
|
|
6743
6991
|
}
|
|
6744
6992
|
const target = CLIUtils.getCurrentInstanceName();
|
|
6745
6993
|
const trackedContext = TrackedInstance.createContext(target);
|
|
6746
6994
|
let instance = null;
|
|
6747
|
-
|
|
6995
|
+
BStackLogger2.info(`trackWebdriverIOInstance: created instance for target=${target}, state=${automationFrameworkState}, args=${args}`);
|
|
6748
6996
|
instance = new AutomationFrameworkInstance(
|
|
6749
6997
|
trackedContext,
|
|
6750
6998
|
this.getAutomationFrameworkName(),
|
|
@@ -6752,7 +7000,7 @@ var init_wdioAutomationFramework = __esm({
|
|
|
6752
7000
|
automationFrameworkState
|
|
6753
7001
|
);
|
|
6754
7002
|
AutomationFramework.setTrackedInstance(trackedContext, instance);
|
|
6755
|
-
|
|
7003
|
+
BStackLogger2.info(`trackWebdriverIOInstance: saved instance contextId=${trackedContext.getId()} target=${target}`);
|
|
6756
7004
|
}
|
|
6757
7005
|
};
|
|
6758
7006
|
}
|
|
@@ -6778,7 +7026,7 @@ var init_webdriverIOModule = __esm({
|
|
|
6778
7026
|
browserVersion;
|
|
6779
7027
|
platforms;
|
|
6780
7028
|
testRunId;
|
|
6781
|
-
logger =
|
|
7029
|
+
logger = BStackLogger2;
|
|
6782
7030
|
static MODULE_NAME = "WebdriverIOModule";
|
|
6783
7031
|
/**
|
|
6784
7032
|
* Create a new WebdriverIOModule
|
|
@@ -6906,7 +7154,7 @@ var init_accessibilityModule = __esm({
|
|
|
6906
7154
|
init_constants2();
|
|
6907
7155
|
init_grpcClient();
|
|
6908
7156
|
AccessibilityModule = class extends BaseModule {
|
|
6909
|
-
logger =
|
|
7157
|
+
logger = BStackLogger2;
|
|
6910
7158
|
name;
|
|
6911
7159
|
scriptInstance;
|
|
6912
7160
|
accessibility = false;
|
|
@@ -7190,7 +7438,7 @@ var init_accessibilityModule = __esm({
|
|
|
7190
7438
|
formatString(this.scriptInstance.performScan, JSON.stringify(_getParamsForAppAccessibility(commandName, testName))),
|
|
7191
7439
|
{}
|
|
7192
7440
|
);
|
|
7193
|
-
|
|
7441
|
+
BStackLogger2.debug(util9.format(results2));
|
|
7194
7442
|
return results2;
|
|
7195
7443
|
}
|
|
7196
7444
|
const results = await browser.executeAsync(
|
|
@@ -7313,7 +7561,7 @@ var init_observabilityModule = __esm({
|
|
|
7313
7561
|
init_cliLogger();
|
|
7314
7562
|
init_util();
|
|
7315
7563
|
ObservabilityModule = class _ObservabilityModule extends BaseModule {
|
|
7316
|
-
logger =
|
|
7564
|
+
logger = BStackLogger2;
|
|
7317
7565
|
observabilityConfig;
|
|
7318
7566
|
name;
|
|
7319
7567
|
static MODULE_NAME = "ObservabilityModule";
|
|
@@ -7416,22 +7664,22 @@ var init_request_handler = __esm({
|
|
|
7416
7664
|
throw new Error("Test Reporting and Analytics build start not completed yet.");
|
|
7417
7665
|
}
|
|
7418
7666
|
this.queue.push(event);
|
|
7419
|
-
|
|
7667
|
+
BStackLogger.debug(`Added data to request queue. Queue length = ${this.queue.length}`);
|
|
7420
7668
|
const shouldProceed = this.shouldProceed();
|
|
7421
7669
|
if (shouldProceed) {
|
|
7422
7670
|
this.sendBatch().catch((e) => {
|
|
7423
|
-
|
|
7671
|
+
BStackLogger.debug("Exception in sending batch: " + e);
|
|
7424
7672
|
});
|
|
7425
7673
|
}
|
|
7426
7674
|
}
|
|
7427
7675
|
async shutdown() {
|
|
7428
|
-
|
|
7676
|
+
BStackLogger.debug("shutdown started");
|
|
7429
7677
|
this.removeEventBatchPolling("Shutting down");
|
|
7430
7678
|
while (this.queue.length > 0) {
|
|
7431
7679
|
const data = this.queue.splice(0, DATA_BATCH_SIZE);
|
|
7432
7680
|
await this.callCallback(data, "SHUTDOWN_QUEUE");
|
|
7433
7681
|
}
|
|
7434
|
-
|
|
7682
|
+
BStackLogger.debug("shutdown ended");
|
|
7435
7683
|
}
|
|
7436
7684
|
startEventBatchPolling() {
|
|
7437
7685
|
this.pollEventBatchInterval = setInterval(this.sendBatch.bind(this), DATA_BATCH_INTERVAL);
|
|
@@ -7441,11 +7689,11 @@ var init_request_handler = __esm({
|
|
|
7441
7689
|
if (data.length === 0) {
|
|
7442
7690
|
return;
|
|
7443
7691
|
}
|
|
7444
|
-
|
|
7692
|
+
BStackLogger.debug(`Sending data from request queue. Data length = ${data.length}, Queue length after removal = ${this.queue.length}`);
|
|
7445
7693
|
await this.callCallback(data, "INTERVAL_QUEUE");
|
|
7446
7694
|
}
|
|
7447
7695
|
callCallback = async (data, kind) => {
|
|
7448
|
-
|
|
7696
|
+
BStackLogger.debug("calling callback with kind " + kind);
|
|
7449
7697
|
await this.callback?.(data);
|
|
7450
7698
|
};
|
|
7451
7699
|
resetEventBatchPolling() {
|
|
@@ -7454,13 +7702,13 @@ var init_request_handler = __esm({
|
|
|
7454
7702
|
}
|
|
7455
7703
|
removeEventBatchPolling(tag) {
|
|
7456
7704
|
if (this.pollEventBatchInterval) {
|
|
7457
|
-
|
|
7705
|
+
BStackLogger.debug(`${tag} request queue`);
|
|
7458
7706
|
clearInterval(this.pollEventBatchInterval);
|
|
7459
7707
|
}
|
|
7460
7708
|
}
|
|
7461
7709
|
shouldProceed() {
|
|
7462
7710
|
if (_RequestQueueHandler.tearDownInvoked) {
|
|
7463
|
-
|
|
7711
|
+
BStackLogger.debug("Force request-queue shutdown, as test run event is received after teardown");
|
|
7464
7712
|
return true;
|
|
7465
7713
|
}
|
|
7466
7714
|
return this.queue.length >= DATA_BATCH_SIZE;
|
|
@@ -7483,7 +7731,7 @@ async function uploadEventData(eventData, eventUrl = DATA_EVENT_ENDPOINT) {
|
|
|
7483
7731
|
throw new Error("Build start not completed yet");
|
|
7484
7732
|
}
|
|
7485
7733
|
if (!process.env[BROWSERSTACK_TESTHUB_JWT]) {
|
|
7486
|
-
|
|
7734
|
+
BStackLogger.debug(`[${logTag}] Missing Authentication Token/ Build ID`);
|
|
7487
7735
|
throw new Error("Token/buildID is undefined, build creation might have failed");
|
|
7488
7736
|
}
|
|
7489
7737
|
try {
|
|
@@ -7496,9 +7744,9 @@ async function uploadEventData(eventData, eventUrl = DATA_EVENT_ENDPOINT) {
|
|
|
7496
7744
|
},
|
|
7497
7745
|
body: JSON.stringify(eventData)
|
|
7498
7746
|
});
|
|
7499
|
-
|
|
7747
|
+
BStackLogger.debug(`[${logTag}] Success response: ${JSON.stringify(await data.json())}`);
|
|
7500
7748
|
} catch (error) {
|
|
7501
|
-
|
|
7749
|
+
BStackLogger.debug(`[${logTag}] Failed. Error: ${format3(error)}`);
|
|
7502
7750
|
throw error;
|
|
7503
7751
|
}
|
|
7504
7752
|
}
|
|
@@ -7561,7 +7809,7 @@ var init_listener = __esm({
|
|
|
7561
7809
|
await this.uploadPending();
|
|
7562
7810
|
await this.teardown();
|
|
7563
7811
|
} catch (e) {
|
|
7564
|
-
|
|
7812
|
+
BStackLogger.debug("Exception in onWorkerEnd: " + e);
|
|
7565
7813
|
}
|
|
7566
7814
|
}
|
|
7567
7815
|
async uploadPending(waitTimeout = DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS, waitInterval = DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS) {
|
|
@@ -7572,10 +7820,10 @@ var init_listener = __esm({
|
|
|
7572
7820
|
return this.uploadPending(waitTimeout - waitInterval);
|
|
7573
7821
|
}
|
|
7574
7822
|
async teardown() {
|
|
7575
|
-
|
|
7823
|
+
BStackLogger.debug("teardown started");
|
|
7576
7824
|
RequestQueueHandler.tearDownInvoked = true;
|
|
7577
7825
|
await this.requestBatcher?.shutdown();
|
|
7578
|
-
|
|
7826
|
+
BStackLogger.debug("teardown ended");
|
|
7579
7827
|
}
|
|
7580
7828
|
hookStarted(hookData) {
|
|
7581
7829
|
try {
|
|
@@ -7683,7 +7931,7 @@ var init_listener = __esm({
|
|
|
7683
7931
|
}
|
|
7684
7932
|
markLogs(status, data) {
|
|
7685
7933
|
if (!data) {
|
|
7686
|
-
|
|
7934
|
+
BStackLogger.debug("No log data");
|
|
7687
7935
|
return;
|
|
7688
7936
|
}
|
|
7689
7937
|
try {
|
|
@@ -7692,7 +7940,7 @@ var init_listener = __esm({
|
|
|
7692
7940
|
this.logEvents.mark(status, LOG_KIND_USAGE_MAP[kind] || kind);
|
|
7693
7941
|
}
|
|
7694
7942
|
} catch (e) {
|
|
7695
|
-
|
|
7943
|
+
BStackLogger.debug("Exception in marking logs status " + e);
|
|
7696
7944
|
throw e;
|
|
7697
7945
|
}
|
|
7698
7946
|
}
|
|
@@ -7710,14 +7958,14 @@ var init_listener = __esm({
|
|
|
7710
7958
|
}
|
|
7711
7959
|
if (!this.requestBatcher) {
|
|
7712
7960
|
this.requestBatcher = RequestQueueHandler.getInstance(async (data) => {
|
|
7713
|
-
|
|
7961
|
+
BStackLogger.debug("callback: called with events " + data.length);
|
|
7714
7962
|
try {
|
|
7715
7963
|
this.pendingUploads += 1;
|
|
7716
7964
|
await batchAndPostEvents(DATA_BATCH_ENDPOINT, "BATCH_DATA", data);
|
|
7717
|
-
|
|
7965
|
+
BStackLogger.debug("callback: marking events success " + data.length);
|
|
7718
7966
|
this.eventsSuccess(data);
|
|
7719
7967
|
} catch {
|
|
7720
|
-
|
|
7968
|
+
BStackLogger.debug("callback: marking events failed " + data.length);
|
|
7721
7969
|
this.eventsFailed(data);
|
|
7722
7970
|
} finally {
|
|
7723
7971
|
this.pendingUploads -= 1;
|
|
@@ -7774,7 +8022,7 @@ var init_listener = __esm({
|
|
|
7774
8022
|
});
|
|
7775
8023
|
|
|
7776
8024
|
// src/reporter.ts
|
|
7777
|
-
import
|
|
8025
|
+
import path15 from "node:path";
|
|
7778
8026
|
import WDIOReporter from "@wdio/reporter";
|
|
7779
8027
|
import * as url from "node:url";
|
|
7780
8028
|
import { v4 as uuidv43 } from "uuid";
|
|
@@ -7867,7 +8115,7 @@ var init_reporter = __esm({
|
|
|
7867
8115
|
filename = this._suiteName || suiteStats.file;
|
|
7868
8116
|
}
|
|
7869
8117
|
} catch {
|
|
7870
|
-
|
|
8118
|
+
BStackLogger.debug("Error in decoding file name of suite");
|
|
7871
8119
|
}
|
|
7872
8120
|
}
|
|
7873
8121
|
this._suiteName = filename;
|
|
@@ -7997,9 +8245,9 @@ var init_reporter = __esm({
|
|
|
7997
8245
|
scope,
|
|
7998
8246
|
scopes,
|
|
7999
8247
|
identifier,
|
|
8000
|
-
file_name: suiteFileName ?
|
|
8001
|
-
location: suiteFileName ?
|
|
8002
|
-
vc_filepath: this._gitConfigPath && suiteFileName ?
|
|
8248
|
+
file_name: suiteFileName ? path15.relative(process.cwd(), suiteFileName) : void 0,
|
|
8249
|
+
location: suiteFileName ? path15.relative(process.cwd(), suiteFileName) : void 0,
|
|
8250
|
+
vc_filepath: this._gitConfigPath && suiteFileName ? path15.relative(this._gitConfigPath, suiteFileName) : void 0,
|
|
8003
8251
|
started_at: testStats.start && testStats.start.toISOString(),
|
|
8004
8252
|
finished_at: testStats.end && testStats.end.toISOString(),
|
|
8005
8253
|
framework,
|
|
@@ -8012,13 +8260,15 @@ var init_reporter = __esm({
|
|
|
8012
8260
|
if (eventType.startsWith("TestRun") || eventType === "HookRunStarted") {
|
|
8013
8261
|
const cloudProvider = getCloudProvider({ options: { hostname: this._config?.hostname } });
|
|
8014
8262
|
testData.integrations = {};
|
|
8263
|
+
const liveBrowserCaps = globalThis?.browser?.capabilities;
|
|
8015
8264
|
testData.integrations[cloudProvider] = {
|
|
8016
8265
|
capabilities: this._capabilities,
|
|
8017
8266
|
session_id: this._sessionId,
|
|
8018
8267
|
browser: this._capabilities?.browserName,
|
|
8019
8268
|
browser_version: this._capabilities?.browserVersion,
|
|
8020
8269
|
platform: this._capabilities?.platformName,
|
|
8021
|
-
platform_version: getPlatformVersion(this._capabilities, this._userCaps)
|
|
8270
|
+
platform_version: getPlatformVersion(this._capabilities, this._userCaps),
|
|
8271
|
+
device: getResolvedDeviceName(liveBrowserCaps, this._userCaps)
|
|
8022
8272
|
};
|
|
8023
8273
|
}
|
|
8024
8274
|
if (eventType === "TestRunFinished" || eventType === "HookRunFinished") {
|
|
@@ -8048,7 +8298,7 @@ var init_reporter = __esm({
|
|
|
8048
8298
|
});
|
|
8049
8299
|
|
|
8050
8300
|
// src/insights-handler.ts
|
|
8051
|
-
import
|
|
8301
|
+
import path16 from "node:path";
|
|
8052
8302
|
import { v4 as uuidv44 } from "uuid";
|
|
8053
8303
|
var _InsightsHandler, InsightsHandler, insights_handler_default;
|
|
8054
8304
|
var init_insights_handler = __esm({
|
|
@@ -8328,9 +8578,9 @@ var init_insights_handler = __esm({
|
|
|
8328
8578
|
test_run_id: hookData.testRunId,
|
|
8329
8579
|
scope: feature?.name,
|
|
8330
8580
|
scopes: [feature?.name || ""],
|
|
8331
|
-
file_name: uri ?
|
|
8332
|
-
location: uri ?
|
|
8333
|
-
vc_filepath: this._gitConfigPath && uri ?
|
|
8581
|
+
file_name: uri ? path16.relative(process.cwd(), uri) : void 0,
|
|
8582
|
+
location: uri ? path16.relative(process.cwd(), uri) : void 0,
|
|
8583
|
+
vc_filepath: this._gitConfigPath && uri ? path16.relative(this._gitConfigPath, uri) : void 0,
|
|
8334
8584
|
result: "pending",
|
|
8335
8585
|
framework: this._framework
|
|
8336
8586
|
};
|
|
@@ -8495,7 +8745,7 @@ var init_insights_handler = __esm({
|
|
|
8495
8745
|
this.listener.logCreated([stdLog]);
|
|
8496
8746
|
}
|
|
8497
8747
|
} catch (error) {
|
|
8498
|
-
|
|
8748
|
+
BStackLogger.debug(`Exception in uploading log data to Test Reporting and Analytics with error : ${error}`);
|
|
8499
8749
|
}
|
|
8500
8750
|
};
|
|
8501
8751
|
async browserCommand(commandType, args, test) {
|
|
@@ -8628,9 +8878,9 @@ var init_insights_handler = __esm({
|
|
|
8628
8878
|
scope: fullTitle,
|
|
8629
8879
|
scopes: this.getHierarchy(test),
|
|
8630
8880
|
identifier: fullTitle,
|
|
8631
|
-
file_name: filename ?
|
|
8632
|
-
location: filename ?
|
|
8633
|
-
vc_filepath: this._gitConfigPath && filename ?
|
|
8881
|
+
file_name: filename ? path16.relative(process.cwd(), filename) : void 0,
|
|
8882
|
+
location: filename ? path16.relative(process.cwd(), filename) : void 0,
|
|
8883
|
+
vc_filepath: this._gitConfigPath && filename ? path16.relative(this._gitConfigPath, filename) : void 0,
|
|
8634
8884
|
started_at: testMetaData.startedAt,
|
|
8635
8885
|
finished_at: testMetaData.finishedAt,
|
|
8636
8886
|
result: "pending",
|
|
@@ -8740,9 +8990,9 @@ var init_insights_handler = __esm({
|
|
|
8740
8990
|
scope: fullNameWithExamples,
|
|
8741
8991
|
scopes: [feature?.name || ""],
|
|
8742
8992
|
identifier: scenario?.name,
|
|
8743
|
-
file_name: feature && feature.path ?
|
|
8744
|
-
location: feature && feature.path ?
|
|
8745
|
-
vc_filepath: this._gitConfigPath && feature?.path ?
|
|
8993
|
+
file_name: feature && feature.path ? path16.relative(process.cwd(), feature.path) : void 0,
|
|
8994
|
+
location: feature && feature.path ? path16.relative(process.cwd(), feature.path) : void 0,
|
|
8995
|
+
vc_filepath: this._gitConfigPath && feature?.path ? path16.relative(this._gitConfigPath, feature?.path) : void 0,
|
|
8746
8996
|
framework: this._framework,
|
|
8747
8997
|
result: "pending",
|
|
8748
8998
|
meta: {
|
|
@@ -8795,7 +9045,7 @@ var init_insights_handler = __esm({
|
|
|
8795
9045
|
return testData;
|
|
8796
9046
|
}
|
|
8797
9047
|
async flushCBTDataQueue() {
|
|
8798
|
-
|
|
9048
|
+
BStackLogger.debug(`Flushing CBT Data Queue ${this.currentTestId}`);
|
|
8799
9049
|
if (isUndefined(this.currentTestId)) {
|
|
8800
9050
|
return;
|
|
8801
9051
|
}
|
|
@@ -8815,7 +9065,7 @@ var init_insights_handler = __esm({
|
|
|
8815
9065
|
uuid: "",
|
|
8816
9066
|
integrations: integrationsData
|
|
8817
9067
|
};
|
|
8818
|
-
|
|
9068
|
+
BStackLogger.debug(`Sending CBT Data ${this.currentTestId} ${JSON.stringify(cbtData)}`);
|
|
8819
9069
|
if (this.currentTestId !== void 0) {
|
|
8820
9070
|
cbtData.uuid = this.currentTestId;
|
|
8821
9071
|
this.listener.cbtSessionCreated(cbtData);
|
|
@@ -8826,8 +9076,8 @@ var init_insights_handler = __esm({
|
|
|
8826
9076
|
getIntegrationsObject() {
|
|
8827
9077
|
const caps = this._browser?.capabilities;
|
|
8828
9078
|
const sessionId = this._browser?.sessionId;
|
|
8829
|
-
|
|
8830
|
-
|
|
9079
|
+
BStackLogger.debug(`Driver capabilities used for integration object: ${JSON.stringify(caps)}`);
|
|
9080
|
+
BStackLogger.debug(`User capabilities used for integration object: ${JSON.stringify(this._userCaps)}`);
|
|
8831
9081
|
return {
|
|
8832
9082
|
capabilities: caps,
|
|
8833
9083
|
session_id: sessionId,
|
|
@@ -8835,7 +9085,8 @@ var init_insights_handler = __esm({
|
|
|
8835
9085
|
browser_version: caps?.browserVersion,
|
|
8836
9086
|
platform: caps?.platformName,
|
|
8837
9087
|
product: this._platformMeta?.product,
|
|
8838
|
-
platform_version: getPlatformVersion(caps, this._userCaps)
|
|
9088
|
+
platform_version: getPlatformVersion(caps, this._userCaps),
|
|
9089
|
+
device: getResolvedDeviceName(caps, this._userCaps)
|
|
8839
9090
|
};
|
|
8840
9091
|
}
|
|
8841
9092
|
getIdentifier(test) {
|
|
@@ -9128,7 +9379,7 @@ var init_percyModule = __esm({
|
|
|
9128
9379
|
init_Percy_Handler();
|
|
9129
9380
|
init_testFrameworkConstants();
|
|
9130
9381
|
PercyModule = class _PercyModule extends BaseModule {
|
|
9131
|
-
logger =
|
|
9382
|
+
logger = BStackLogger2;
|
|
9132
9383
|
browser;
|
|
9133
9384
|
static MODULE_NAME = "PercyModule";
|
|
9134
9385
|
percyHandler;
|
|
@@ -9249,7 +9500,7 @@ var init_cli = __esm({
|
|
|
9249
9500
|
cliParams = null;
|
|
9250
9501
|
automationFramework = null;
|
|
9251
9502
|
SDK_CLI_BIN_PATH = null;
|
|
9252
|
-
logger =
|
|
9503
|
+
logger = BStackLogger2;
|
|
9253
9504
|
options;
|
|
9254
9505
|
constructor() {
|
|
9255
9506
|
this.initialized = false;
|
|
@@ -9308,7 +9559,7 @@ var init_cli = __esm({
|
|
|
9308
9559
|
const response = await GrpcClient.getInstance().startBinSession(this.wdioConfig);
|
|
9309
9560
|
const redactedStartResponse = JSON.parse(JSON.stringify(response));
|
|
9310
9561
|
CrashReporter.recursivelyRedactKeysFromObject(redactedStartResponse, ["user", "username", "key", "accesskey", "password"]);
|
|
9311
|
-
|
|
9562
|
+
BStackLogger2.debug(`start: startBinSession response=${JSON.stringify(redactedStartResponse)}`);
|
|
9312
9563
|
this.loadModules(response);
|
|
9313
9564
|
this.isMainConnected = true;
|
|
9314
9565
|
}
|
|
@@ -9320,6 +9571,7 @@ var init_cli = __esm({
|
|
|
9320
9571
|
this.binSessionId = startBinResponse.binSessionId;
|
|
9321
9572
|
this.logger.info(`loadModules: binSessionId=${this.binSessionId}`);
|
|
9322
9573
|
this.setConfig(startBinResponse);
|
|
9574
|
+
this.logBuildErrors(startBinResponse);
|
|
9323
9575
|
APIUtils.updateURLSForGRR(this.config.apis);
|
|
9324
9576
|
this.setupTestFramework();
|
|
9325
9577
|
this.setupAutomationFramework();
|
|
@@ -9341,17 +9593,6 @@ var init_cli = __esm({
|
|
|
9341
9593
|
}
|
|
9342
9594
|
this.modules[ObservabilityModule.MODULE_NAME] = new ObservabilityModule(startBinResponse.observability);
|
|
9343
9595
|
}
|
|
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
9596
|
this.modules[TestHubModule.MODULE_NAME] = new TestHubModule(startBinResponse.testhub);
|
|
9356
9597
|
if (startBinResponse.accessibility?.success) {
|
|
9357
9598
|
process.env[BROWSERSTACK_ACCESSIBILITY] = "true";
|
|
@@ -9366,6 +9607,28 @@ var init_cli = __esm({
|
|
|
9366
9607
|
}
|
|
9367
9608
|
this.configureModules();
|
|
9368
9609
|
}
|
|
9610
|
+
/**
|
|
9611
|
+
* Log any build errors the binary reported via testhub.errors. The
|
|
9612
|
+
* field is a JSON-encoded { [errorKey]: { message, type } } map. Called
|
|
9613
|
+
* early in loadModules so the user sees the actionable cause (e.g.
|
|
9614
|
+
* invalid credentials) before any downstream bootstrap step that
|
|
9615
|
+
* depends on a fully populated config.
|
|
9616
|
+
*/
|
|
9617
|
+
logBuildErrors(startBinResponse) {
|
|
9618
|
+
const rawErrors = startBinResponse.testhub?.errors;
|
|
9619
|
+
if (!rawErrors || !rawErrors.length) {
|
|
9620
|
+
return;
|
|
9621
|
+
}
|
|
9622
|
+
try {
|
|
9623
|
+
const errors = JSON.parse(Buffer.from(rawErrors).toString());
|
|
9624
|
+
for (const [code, detail] of Object.entries(errors)) {
|
|
9625
|
+
const { message } = detail;
|
|
9626
|
+
BStackLogger2.error(`[Build] ${code}: ${message}`);
|
|
9627
|
+
}
|
|
9628
|
+
} catch (e) {
|
|
9629
|
+
BStackLogger2.debug(`Failed to parse testhub errors: ${e}`);
|
|
9630
|
+
}
|
|
9631
|
+
}
|
|
9369
9632
|
/**
|
|
9370
9633
|
* Configure modules
|
|
9371
9634
|
* @returns {Promise<void>}
|
|
@@ -9490,7 +9753,7 @@ var init_cli = __esm({
|
|
|
9490
9753
|
try {
|
|
9491
9754
|
if (this.isMainConnected) {
|
|
9492
9755
|
const response = await GrpcClient.getInstance().stopBinSession();
|
|
9493
|
-
|
|
9756
|
+
BStackLogger2.debug(`stop: stopBinSession response=${JSON.stringify(response)}`);
|
|
9494
9757
|
}
|
|
9495
9758
|
await this.unConfigureModules();
|
|
9496
9759
|
if (this.process && this.process.pid) {
|
|
@@ -9672,8 +9935,8 @@ var init_cli = __esm({
|
|
|
9672
9935
|
});
|
|
9673
9936
|
|
|
9674
9937
|
// src/testorchestration/helpers.ts
|
|
9675
|
-
import
|
|
9676
|
-
import
|
|
9938
|
+
import os6 from "node:os";
|
|
9939
|
+
import path19 from "node:path";
|
|
9677
9940
|
import { spawnSync } from "node:child_process";
|
|
9678
9941
|
import logger4 from "@wdio/logger";
|
|
9679
9942
|
function isValidGitRef(ref) {
|
|
@@ -9699,11 +9962,11 @@ function safeGitCommand(args, cwd) {
|
|
|
9699
9962
|
}
|
|
9700
9963
|
function getHostInfo() {
|
|
9701
9964
|
return {
|
|
9702
|
-
hostname:
|
|
9965
|
+
hostname: os6.hostname(),
|
|
9703
9966
|
platform: process.platform,
|
|
9704
9967
|
architecture: process.arch,
|
|
9705
|
-
release:
|
|
9706
|
-
username:
|
|
9968
|
+
release: os6.release(),
|
|
9969
|
+
username: os6.userInfo().username
|
|
9707
9970
|
};
|
|
9708
9971
|
}
|
|
9709
9972
|
function isValidGitResult(result) {
|
|
@@ -9794,7 +10057,7 @@ function getGitMetadataForAISelection(folders = []) {
|
|
|
9794
10057
|
if (folders === null) {
|
|
9795
10058
|
folders = [process.cwd()];
|
|
9796
10059
|
}
|
|
9797
|
-
const uniqueFolders = [...new Set(folders.map((f) =>
|
|
10060
|
+
const uniqueFolders = [...new Set(folders.map((f) => path19.resolve(f)))];
|
|
9798
10061
|
log4.debug(`Processing ${uniqueFolders.length} unique folders out of ${folders.length} total`);
|
|
9799
10062
|
const results = [];
|
|
9800
10063
|
for (const folder of uniqueFolders) {
|
|
@@ -9951,14 +10214,14 @@ var init_request_utils = __esm({
|
|
|
9951
10214
|
* Makes a request to the test orchestration split tests endpoint
|
|
9952
10215
|
*/
|
|
9953
10216
|
static async testOrchestrationSplitTests(reqEndpoint, data) {
|
|
9954
|
-
|
|
10217
|
+
BStackLogger.debug("Processing Request for testOrchestrationSplitTests");
|
|
9955
10218
|
return _RequestUtils.makeOrchestrationRequest("POST", reqEndpoint, { data });
|
|
9956
10219
|
}
|
|
9957
10220
|
/**
|
|
9958
10221
|
* Gets ordered tests from the test orchestration
|
|
9959
10222
|
*/
|
|
9960
10223
|
static async getTestOrchestrationOrderedTests(reqEndpoint) {
|
|
9961
|
-
|
|
10224
|
+
BStackLogger.debug("Processing Request for getTestOrchestrationOrderedTests");
|
|
9962
10225
|
return _RequestUtils.makeOrchestrationRequest("GET", reqEndpoint, {});
|
|
9963
10226
|
}
|
|
9964
10227
|
/**
|
|
@@ -9995,13 +10258,13 @@ var init_request_utils = __esm({
|
|
|
9995
10258
|
throw new Error(`Unsupported HTTP method: ${method}`);
|
|
9996
10259
|
}
|
|
9997
10260
|
const response = await fetchWrap(urlObject.toString(), requestInit);
|
|
9998
|
-
|
|
10261
|
+
BStackLogger.debug(`Orchestration request made to URL: ${urlObject.toString()} with method: ${method}`);
|
|
9999
10262
|
const rawBody = await response.text();
|
|
10000
10263
|
let responseObj = rawBody;
|
|
10001
10264
|
try {
|
|
10002
10265
|
responseObj = rawBody ? JSON.parse(rawBody) : {};
|
|
10003
10266
|
} catch (error) {
|
|
10004
|
-
|
|
10267
|
+
BStackLogger.debug(`Failed to parse JSON response: ${error} - ${rawBody}`);
|
|
10005
10268
|
}
|
|
10006
10269
|
if (responseObj && typeof responseObj === "object" && !Array.isArray(responseObj)) {
|
|
10007
10270
|
return {
|
|
@@ -10012,7 +10275,7 @@ var init_request_utils = __esm({
|
|
|
10012
10275
|
}
|
|
10013
10276
|
return typeof responseObj === "string" ? responseObj : rawBody;
|
|
10014
10277
|
} catch (error) {
|
|
10015
|
-
|
|
10278
|
+
BStackLogger.error(`Orchestration request failed: ${error} - ${url3}`);
|
|
10016
10279
|
return null;
|
|
10017
10280
|
}
|
|
10018
10281
|
}
|
|
@@ -10021,7 +10284,7 @@ var init_request_utils = __esm({
|
|
|
10021
10284
|
});
|
|
10022
10285
|
|
|
10023
10286
|
// src/testorchestration/test-ordering-server.ts
|
|
10024
|
-
import
|
|
10287
|
+
import path20 from "node:path";
|
|
10025
10288
|
function isSplitTestsResponse(value) {
|
|
10026
10289
|
return typeof value === "object" && value !== null;
|
|
10027
10290
|
}
|
|
@@ -10055,7 +10318,7 @@ var init_test_ordering_server = __esm({
|
|
|
10055
10318
|
* Initiates the split tests request and stores the response data for polling.
|
|
10056
10319
|
*/
|
|
10057
10320
|
async splitTests(testFiles, orchestrationStrategy, orchestrationMetadata = "{}") {
|
|
10058
|
-
|
|
10321
|
+
BStackLogger.debug(`[splitTests] Initiating split tests with strategy: ${orchestrationStrategy}`);
|
|
10059
10322
|
try {
|
|
10060
10323
|
let prDetails = [];
|
|
10061
10324
|
const parsedMetadata = JSON.parse(orchestrationMetadata);
|
|
@@ -10065,7 +10328,7 @@ var init_test_ordering_server = __esm({
|
|
|
10065
10328
|
const multiRepoSource = parsedMetadata.run_smart_selection?.source;
|
|
10066
10329
|
prDetails = getGitMetadataForAISelection(multiRepoSource);
|
|
10067
10330
|
}
|
|
10068
|
-
|
|
10331
|
+
BStackLogger.debug(`PR Details for AI Selection: ${JSON.stringify(prDetails)}`);
|
|
10069
10332
|
const payload = {
|
|
10070
10333
|
tests: testFiles.map((f) => ({ filePath: f })),
|
|
10071
10334
|
orchestrationStrategy,
|
|
@@ -10073,23 +10336,23 @@ var init_test_ordering_server = __esm({
|
|
|
10073
10336
|
nodeIndex: parseInt(process.env.BROWSERSTACK_NODE_INDEX || "0"),
|
|
10074
10337
|
totalNodes: parseInt(process.env.BROWSERSTACK_TOTAL_NODE_COUNT || "1"),
|
|
10075
10338
|
projectName: this.config.testObservabilityOptions?.projectName || "",
|
|
10076
|
-
buildName: this.config.testObservabilityOptions?.buildName ||
|
|
10339
|
+
buildName: this.config.testObservabilityOptions?.buildName || path20.basename(process.cwd()),
|
|
10077
10340
|
buildRunIdentifier: process.env.BROWSERSTACK_BUILD_RUN_IDENTIFIER || "",
|
|
10078
10341
|
hostInfo: getHostInfo(),
|
|
10079
10342
|
prDetails
|
|
10080
10343
|
};
|
|
10081
|
-
|
|
10344
|
+
BStackLogger.info(`[splitTests] Split tests payload: ${JSON.stringify(payload)}`);
|
|
10082
10345
|
const response = await RequestUtils.testOrchestrationSplitTests(this.ORDERING_ENDPOINT, payload);
|
|
10083
10346
|
if (isSplitTestsResponse(response)) {
|
|
10084
10347
|
this.requestData = this._processSplitTestsResponse(response);
|
|
10085
|
-
|
|
10348
|
+
BStackLogger.debug(`[splitTests] Split tests response: ${JSON.stringify(this.requestData)}`);
|
|
10086
10349
|
} else if (response) {
|
|
10087
|
-
|
|
10350
|
+
BStackLogger.error("[splitTests] Received unexpected response format from split tests request.");
|
|
10088
10351
|
} else {
|
|
10089
|
-
|
|
10352
|
+
BStackLogger.error("[splitTests] Failed to get split tests response.");
|
|
10090
10353
|
}
|
|
10091
10354
|
} catch (error) {
|
|
10092
|
-
|
|
10355
|
+
BStackLogger.error(`[splitTests] Exception in sending test files:: ${error}`);
|
|
10093
10356
|
}
|
|
10094
10357
|
}
|
|
10095
10358
|
/**
|
|
@@ -10107,7 +10370,7 @@ var init_test_ordering_server = __esm({
|
|
|
10107
10370
|
const resultUrl = normalizeUrl(response.resultUrl);
|
|
10108
10371
|
const timeoutUrl = normalizeUrl(response.timeoutUrl);
|
|
10109
10372
|
if (response.timeout === void 0 || response.timeoutInterval === void 0 || response.timeoutUrl === void 0 || response.resultUrl === void 0) {
|
|
10110
|
-
|
|
10373
|
+
BStackLogger.debug("[process_split_tests_response] Received null value(s) for some attributes in split tests API response");
|
|
10111
10374
|
}
|
|
10112
10375
|
return {
|
|
10113
10376
|
timeout,
|
|
@@ -10121,7 +10384,7 @@ var init_test_ordering_server = __esm({
|
|
|
10121
10384
|
*/
|
|
10122
10385
|
async getOrderedTestFiles() {
|
|
10123
10386
|
if (!this.requestData) {
|
|
10124
|
-
|
|
10387
|
+
BStackLogger.error("[getOrderedTestFiles] No request data available to fetch ordered test files.");
|
|
10125
10388
|
return null;
|
|
10126
10389
|
}
|
|
10127
10390
|
let testFilesJsonList = null;
|
|
@@ -10145,10 +10408,10 @@ var init_test_ordering_server = __esm({
|
|
|
10145
10408
|
break;
|
|
10146
10409
|
}
|
|
10147
10410
|
await new Promise((resolve) => setTimeout(resolve, timeoutInterval * 1e3));
|
|
10148
|
-
|
|
10411
|
+
BStackLogger.debug(`[getOrderedTestFiles] Fetching ordered tests from result URL after waiting for ${timeoutInterval} seconds.`);
|
|
10149
10412
|
}
|
|
10150
10413
|
if (timeoutUrl && !testFilesJsonList) {
|
|
10151
|
-
|
|
10414
|
+
BStackLogger.debug("[getOrderedTestFiles] Fetching ordered tests from timeout URL");
|
|
10152
10415
|
const response = await RequestUtils.getTestOrchestrationOrderedTests(timeoutUrl);
|
|
10153
10416
|
if (isSplitTestsResponse(response) && Array.isArray(response.tests)) {
|
|
10154
10417
|
testFilesJsonList = response.tests;
|
|
@@ -10165,10 +10428,10 @@ var init_test_ordering_server = __esm({
|
|
|
10165
10428
|
if (!testFilesJsonList) {
|
|
10166
10429
|
return null;
|
|
10167
10430
|
}
|
|
10168
|
-
|
|
10431
|
+
BStackLogger.debug(`[getOrderedTestFiles] Ordered test files received: ${JSON.stringify(testFiles)}`);
|
|
10169
10432
|
return testFiles;
|
|
10170
10433
|
} catch (error) {
|
|
10171
|
-
|
|
10434
|
+
BStackLogger.error(`[getOrderedTestFiles] Exception in fetching ordered test files: ${error}`);
|
|
10172
10435
|
return null;
|
|
10173
10436
|
}
|
|
10174
10437
|
}
|
|
@@ -10260,10 +10523,10 @@ var init_testorcherstrationhandler = __esm({
|
|
|
10260
10523
|
return;
|
|
10261
10524
|
}
|
|
10262
10525
|
if (this.config.projectName === void 0 || this.config.buildName === void 0) {
|
|
10263
|
-
|
|
10526
|
+
BStackLogger.info("Test Reordering can't work as buildName or projectName is null. Please set a non-null value.");
|
|
10264
10527
|
}
|
|
10265
10528
|
if (!this._isObservabilityEnabled()) {
|
|
10266
|
-
|
|
10529
|
+
BStackLogger.info("Test Reordering can't work as testReporting is disabled. Please enable it from browserstack.yml file.");
|
|
10267
10530
|
}
|
|
10268
10531
|
}
|
|
10269
10532
|
/**
|
|
@@ -10272,7 +10535,7 @@ var init_testorcherstrationhandler = __esm({
|
|
|
10272
10535
|
async reorderTestFiles(testFiles) {
|
|
10273
10536
|
try {
|
|
10274
10537
|
if (!testFiles || testFiles.length === 0) {
|
|
10275
|
-
|
|
10538
|
+
BStackLogger.debug("[reorderTestFiles] No test files provided for ordering.");
|
|
10276
10539
|
return null;
|
|
10277
10540
|
}
|
|
10278
10541
|
let orchestrationStrategy = null;
|
|
@@ -10281,16 +10544,16 @@ var init_testorcherstrationhandler = __esm({
|
|
|
10281
10544
|
orchestrationStrategy = this.orchestrationUtils.getTestOrderingName();
|
|
10282
10545
|
}
|
|
10283
10546
|
if (orchestrationStrategy === null) {
|
|
10284
|
-
|
|
10547
|
+
BStackLogger.error("Orchestration strategy is None. Cannot proceed with test orchestration session.");
|
|
10285
10548
|
return null;
|
|
10286
10549
|
}
|
|
10287
|
-
|
|
10550
|
+
BStackLogger.info(`Reordering test files with orchestration strategy: ${orchestrationStrategy}`);
|
|
10288
10551
|
let orderedTestFiles = [];
|
|
10289
10552
|
if (BrowserstackCLI.getInstance().isRunning()) {
|
|
10290
|
-
|
|
10553
|
+
BStackLogger.info("Using CLI flow for test files orchestration.");
|
|
10291
10554
|
orderedTestFiles = await GrpcClient.getInstance().testOrchestrationSession(testFiles, orchestrationStrategy, JSON.stringify(orchestrationMetadata)) || [];
|
|
10292
10555
|
} else {
|
|
10293
|
-
|
|
10556
|
+
BStackLogger.info("Using SDK flow for test files orchestration.");
|
|
10294
10557
|
await this.testOrderingServerHandler.splitTests(testFiles, orchestrationStrategy, JSON.stringify(orchestrationMetadata));
|
|
10295
10558
|
orderedTestFiles = await this.testOrderingServerHandler.getOrderedTestFiles() || [];
|
|
10296
10559
|
}
|
|
@@ -10301,7 +10564,7 @@ var init_testorcherstrationhandler = __esm({
|
|
|
10301
10564
|
this.addToOrderingInstrumentationData("splitTestsAPICallCount", this.testOrderingServerHandler.getSplitTestsApiCallCount());
|
|
10302
10565
|
return orderedTestFiles;
|
|
10303
10566
|
} catch (error) {
|
|
10304
|
-
|
|
10567
|
+
BStackLogger.debug(`[reorderTestFiles] Error in ordering test classes: ${error}`);
|
|
10305
10568
|
}
|
|
10306
10569
|
return null;
|
|
10307
10570
|
}
|
|
@@ -10331,22 +10594,22 @@ import { performance as performance3 } from "node:perf_hooks";
|
|
|
10331
10594
|
async function applyOrchestrationIfEnabled(specs, config) {
|
|
10332
10595
|
const orchestrationHandler = TestOrchestrationHandler.getInstance(config);
|
|
10333
10596
|
if (!orchestrationHandler) {
|
|
10334
|
-
|
|
10597
|
+
BStackLogger.debug("Orchestration handler is not initialized. Skipping orchestration.");
|
|
10335
10598
|
return specs;
|
|
10336
10599
|
}
|
|
10337
10600
|
const runSmartSelectionEnabled = isValidEnabledValue(config?.testOrchestrationOptions?.runSmartSelection?.enabled);
|
|
10338
10601
|
if (!runSmartSelectionEnabled) {
|
|
10339
|
-
|
|
10602
|
+
BStackLogger.info("runSmartSelection is not enabled in config. Skipping orchestration.");
|
|
10340
10603
|
return specs;
|
|
10341
10604
|
}
|
|
10342
10605
|
orchestrationHandler.addToOrderingInstrumentationData("enabled", orchestrationHandler.testOrderingEnabled());
|
|
10343
10606
|
const startTime = performance3.now();
|
|
10344
|
-
|
|
10607
|
+
BStackLogger.info("Test orchestration is enabled. Attempting to reorder test files.");
|
|
10345
10608
|
const testFiles = specs;
|
|
10346
|
-
|
|
10609
|
+
BStackLogger.info(`Test files to be reordered: ${testFiles.join(", ")}`);
|
|
10347
10610
|
const orderedFiles = await orchestrationHandler.reorderTestFiles(testFiles);
|
|
10348
10611
|
if (orderedFiles && orderedFiles.length > 0) {
|
|
10349
|
-
|
|
10612
|
+
BStackLogger.info(`Tests reordered using orchestration: ${orderedFiles.join(", ")}`);
|
|
10350
10613
|
orchestrationHandler.addToOrderingInstrumentationData(
|
|
10351
10614
|
"timeTakenToApply",
|
|
10352
10615
|
Math.floor(performance3.now() - startTime)
|
|
@@ -10354,7 +10617,7 @@ async function applyOrchestrationIfEnabled(specs, config) {
|
|
|
10354
10617
|
);
|
|
10355
10618
|
return orderedFiles;
|
|
10356
10619
|
}
|
|
10357
|
-
|
|
10620
|
+
BStackLogger.info("No test files were reordered by orchestration.");
|
|
10358
10621
|
orchestrationHandler.addToOrderingInstrumentationData(
|
|
10359
10622
|
"timeTakenToApply",
|
|
10360
10623
|
Math.floor(performance3.now() - startTime)
|
|
@@ -10376,12 +10639,12 @@ var init_apply_orchestration = __esm({
|
|
|
10376
10639
|
// src/launcher.ts
|
|
10377
10640
|
init_utils();
|
|
10378
10641
|
init_testOpsConfig();
|
|
10379
|
-
import
|
|
10642
|
+
import fs15 from "node:fs";
|
|
10380
10643
|
import { readFile } from "node:fs/promises";
|
|
10381
|
-
import
|
|
10644
|
+
import path21 from "node:path";
|
|
10382
10645
|
import { promisify as promisify4, format as format4 } from "node:util";
|
|
10383
10646
|
import { performance as performance4, PerformanceObserver as PerformanceObserver2 } from "node:perf_hooks";
|
|
10384
|
-
import
|
|
10647
|
+
import os7 from "node:os";
|
|
10385
10648
|
import { SevereServiceError } from "webdriverio";
|
|
10386
10649
|
import * as BrowserstackLocalLauncher from "browserstack-local";
|
|
10387
10650
|
|
|
@@ -10391,9 +10654,9 @@ init_PercyLogger();
|
|
|
10391
10654
|
// src/Percy/Percy.ts
|
|
10392
10655
|
init_util();
|
|
10393
10656
|
init_PercyLogger();
|
|
10394
|
-
import
|
|
10395
|
-
import
|
|
10396
|
-
import
|
|
10657
|
+
import fs11 from "node:fs";
|
|
10658
|
+
import path10 from "node:path";
|
|
10659
|
+
import os4 from "node:os";
|
|
10397
10660
|
import { spawn as spawn2 } from "node:child_process";
|
|
10398
10661
|
|
|
10399
10662
|
// src/Percy/PercyBinary.ts
|
|
@@ -10403,20 +10666,20 @@ init_constants2();
|
|
|
10403
10666
|
init_bstackLogger();
|
|
10404
10667
|
init_fetchWrapper();
|
|
10405
10668
|
import yauzl2 from "yauzl";
|
|
10406
|
-
import
|
|
10669
|
+
import fs10 from "node:fs";
|
|
10407
10670
|
import fsp2 from "node:fs/promises";
|
|
10408
10671
|
import { pipeline } from "node:stream/promises";
|
|
10409
|
-
import
|
|
10410
|
-
import
|
|
10672
|
+
import path9 from "node:path";
|
|
10673
|
+
import os3 from "node:os";
|
|
10411
10674
|
import { spawn } from "node:child_process";
|
|
10412
10675
|
var PercyBinary = class {
|
|
10413
10676
|
#hostOS = process.platform;
|
|
10414
10677
|
#httpPath = null;
|
|
10415
10678
|
#binaryName = "percy";
|
|
10416
10679
|
#orderedPaths = [
|
|
10417
|
-
|
|
10680
|
+
path9.join(os3.homedir(), ".browserstack"),
|
|
10418
10681
|
process.cwd(),
|
|
10419
|
-
|
|
10682
|
+
os3.tmpdir()
|
|
10420
10683
|
];
|
|
10421
10684
|
constructor() {
|
|
10422
10685
|
const base = "https://github.com/percy/cli/releases/latest/download";
|
|
@@ -10429,15 +10692,15 @@ var PercyBinary = class {
|
|
|
10429
10692
|
this.#httpPath = base + "/percy-linux.zip";
|
|
10430
10693
|
}
|
|
10431
10694
|
}
|
|
10432
|
-
async #makePath(
|
|
10433
|
-
if (await this.#checkPath(
|
|
10695
|
+
async #makePath(path22) {
|
|
10696
|
+
if (await this.#checkPath(path22)) {
|
|
10434
10697
|
return true;
|
|
10435
10698
|
}
|
|
10436
|
-
return fsp2.mkdir(
|
|
10699
|
+
return fsp2.mkdir(path22).then(() => true).catch(() => false);
|
|
10437
10700
|
}
|
|
10438
|
-
async #checkPath(
|
|
10701
|
+
async #checkPath(path22) {
|
|
10439
10702
|
try {
|
|
10440
|
-
const hasDir = await fsp2.access(
|
|
10703
|
+
const hasDir = await fsp2.access(path22).then(() => true, () => false);
|
|
10441
10704
|
if (hasDir) {
|
|
10442
10705
|
return true;
|
|
10443
10706
|
}
|
|
@@ -10447,7 +10710,7 @@ var PercyBinary = class {
|
|
|
10447
10710
|
}
|
|
10448
10711
|
// Get the path for storing the ETag
|
|
10449
10712
|
#getETagPath(destParentDir) {
|
|
10450
|
-
return
|
|
10713
|
+
return path9.join(destParentDir, `${this.#binaryName}.etag`);
|
|
10451
10714
|
}
|
|
10452
10715
|
// Load the stored ETag if it exists
|
|
10453
10716
|
async #loadETag(destParentDir) {
|
|
@@ -10457,7 +10720,7 @@ var PercyBinary = class {
|
|
|
10457
10720
|
const data = await fsp2.readFile(etagPath, "utf8");
|
|
10458
10721
|
return data.trim();
|
|
10459
10722
|
} catch (err) {
|
|
10460
|
-
|
|
10723
|
+
BStackLogger.warn(`Failed to read ETag file ${err}`);
|
|
10461
10724
|
}
|
|
10462
10725
|
}
|
|
10463
10726
|
return null;
|
|
@@ -10470,23 +10733,23 @@ var PercyBinary = class {
|
|
|
10470
10733
|
try {
|
|
10471
10734
|
const etagPath = this.#getETagPath(destParentDir);
|
|
10472
10735
|
await fsp2.writeFile(etagPath, etag);
|
|
10473
|
-
|
|
10736
|
+
BStackLogger.debug("Saved new ETag for percy binary");
|
|
10474
10737
|
} catch (err) {
|
|
10475
|
-
|
|
10738
|
+
BStackLogger.error(`Failed to save ETag file ${err}`);
|
|
10476
10739
|
}
|
|
10477
10740
|
}
|
|
10478
10741
|
async #getAvailableDirs() {
|
|
10479
10742
|
for (let i = 0; i < this.#orderedPaths.length; i++) {
|
|
10480
|
-
const
|
|
10481
|
-
if (await this.#makePath(
|
|
10482
|
-
return
|
|
10743
|
+
const path22 = this.#orderedPaths[i];
|
|
10744
|
+
if (await this.#makePath(path22)) {
|
|
10745
|
+
return path22;
|
|
10483
10746
|
}
|
|
10484
10747
|
}
|
|
10485
10748
|
throw new Error("Error trying to download percy binary");
|
|
10486
10749
|
}
|
|
10487
10750
|
async getBinaryPath() {
|
|
10488
10751
|
const destParentDir = await this.#getAvailableDirs();
|
|
10489
|
-
const binaryPath =
|
|
10752
|
+
const binaryPath = path9.join(destParentDir, this.#binaryName);
|
|
10490
10753
|
let response;
|
|
10491
10754
|
if (await this.#checkPath(binaryPath)) {
|
|
10492
10755
|
const currentETag = await this.#loadETag(destParentDir);
|
|
@@ -10494,13 +10757,13 @@ var PercyBinary = class {
|
|
|
10494
10757
|
try {
|
|
10495
10758
|
const result = await this.#checkForUpdate(currentETag);
|
|
10496
10759
|
if (!result.needsUpdate) {
|
|
10497
|
-
|
|
10760
|
+
BStackLogger.debug("Percy binary is up to date (ETag unchanged)");
|
|
10498
10761
|
return binaryPath;
|
|
10499
10762
|
}
|
|
10500
10763
|
response = result.response;
|
|
10501
|
-
|
|
10764
|
+
BStackLogger.debug("New Percy binary version available, downloading update");
|
|
10502
10765
|
} catch (err) {
|
|
10503
|
-
|
|
10766
|
+
BStackLogger.warn(`Failed to check for binary updates, using existing binary ${err}`);
|
|
10504
10767
|
return binaryPath;
|
|
10505
10768
|
}
|
|
10506
10769
|
}
|
|
@@ -10528,11 +10791,11 @@ var PercyBinary = class {
|
|
|
10528
10791
|
}
|
|
10529
10792
|
const newETag = response.headers.get("eTag");
|
|
10530
10793
|
if (newETag) {
|
|
10531
|
-
await this.#saveETag(
|
|
10794
|
+
await this.#saveETag(path9.dirname(this.#getETagPath(await this.#getAvailableDirs())), newETag);
|
|
10532
10795
|
}
|
|
10533
10796
|
return { needsUpdate: true, response };
|
|
10534
10797
|
} catch (error) {
|
|
10535
|
-
|
|
10798
|
+
BStackLogger.warn(`Error checking for Percy binary updates: ${error}`);
|
|
10536
10799
|
throw error;
|
|
10537
10800
|
}
|
|
10538
10801
|
}
|
|
@@ -10555,9 +10818,9 @@ var PercyBinary = class {
|
|
|
10555
10818
|
await fsp2.mkdir(destParentDir);
|
|
10556
10819
|
}
|
|
10557
10820
|
const binaryName = this.#binaryName;
|
|
10558
|
-
const zipFilePath =
|
|
10559
|
-
const binaryPath =
|
|
10560
|
-
const downloadedFileStream =
|
|
10821
|
+
const zipFilePath = path9.join(destParentDir, binaryName + ".zip");
|
|
10822
|
+
const binaryPath = path9.join(destParentDir, binaryName);
|
|
10823
|
+
const downloadedFileStream = fs10.createWriteStream(zipFilePath);
|
|
10561
10824
|
if (!response) {
|
|
10562
10825
|
response = await _fetch(this.#httpPath);
|
|
10563
10826
|
}
|
|
@@ -10576,8 +10839,8 @@ var PercyBinary = class {
|
|
|
10576
10839
|
if (/\/$/.test(entry.fileName)) {
|
|
10577
10840
|
zipfile.readEntry();
|
|
10578
10841
|
} else {
|
|
10579
|
-
const writeStream =
|
|
10580
|
-
|
|
10842
|
+
const writeStream = fs10.createWriteStream(
|
|
10843
|
+
path9.join(destParentDir, entry.fileName)
|
|
10581
10844
|
);
|
|
10582
10845
|
zipfile.openReadStream(entry, function(zipErr, readStream) {
|
|
10583
10846
|
if (zipErr) {
|
|
@@ -10598,7 +10861,7 @@ var PercyBinary = class {
|
|
|
10598
10861
|
reject(zipErr);
|
|
10599
10862
|
});
|
|
10600
10863
|
zipfile.once("end", () => {
|
|
10601
|
-
|
|
10864
|
+
fs10.chmod(binaryPath, "0755", function(zipErr) {
|
|
10602
10865
|
if (zipErr) {
|
|
10603
10866
|
reject(zipErr);
|
|
10604
10867
|
}
|
|
@@ -10622,7 +10885,7 @@ init_constants2();
|
|
|
10622
10885
|
init_apiUtils();
|
|
10623
10886
|
var logDir = "logs";
|
|
10624
10887
|
var Percy = class {
|
|
10625
|
-
#logfile =
|
|
10888
|
+
#logfile = path10.join(logDir, "percy.log");
|
|
10626
10889
|
#address = process.env.PERCY_SERVER_ADDRESS || "http://127.0.0.1:5338";
|
|
10627
10890
|
#binaryPath = null;
|
|
10628
10891
|
#options;
|
|
@@ -10663,7 +10926,7 @@ var Percy = class {
|
|
|
10663
10926
|
}
|
|
10664
10927
|
async start() {
|
|
10665
10928
|
const binaryPath = await this.#getBinaryPath();
|
|
10666
|
-
const logStream =
|
|
10929
|
+
const logStream = fs11.createWriteStream(this.#logfile, { flags: "a" });
|
|
10667
10930
|
const token = await this.fetchPercyToken();
|
|
10668
10931
|
const configPath = await this.createPercyConfig();
|
|
10669
10932
|
if (!token) {
|
|
@@ -10750,13 +11013,13 @@ var Percy = class {
|
|
|
10750
11013
|
if (!this.#options.percyOptions) {
|
|
10751
11014
|
return null;
|
|
10752
11015
|
}
|
|
10753
|
-
const configPath =
|
|
11016
|
+
const configPath = path10.join(os4.tmpdir(), "percy.json");
|
|
10754
11017
|
const percyOptions = this.#options.percyOptions;
|
|
10755
11018
|
if (!percyOptions.version) {
|
|
10756
11019
|
percyOptions.version = "2";
|
|
10757
11020
|
}
|
|
10758
11021
|
return new Promise((resolve) => {
|
|
10759
|
-
|
|
11022
|
+
fs11.writeFile(
|
|
10760
11023
|
configPath,
|
|
10761
11024
|
JSON.stringify(
|
|
10762
11025
|
percyOptions
|
|
@@ -10850,6 +11113,7 @@ init_constants();
|
|
|
10850
11113
|
init_util();
|
|
10851
11114
|
init_crash_reporter();
|
|
10852
11115
|
init_bstackLogger();
|
|
11116
|
+
init_caCert();
|
|
10853
11117
|
init_PercyLogger();
|
|
10854
11118
|
|
|
10855
11119
|
// src/config.ts
|
|
@@ -10857,10 +11121,62 @@ init_testOpsConfig();
|
|
|
10857
11121
|
init_util();
|
|
10858
11122
|
init_bstackLogger();
|
|
10859
11123
|
import { v4 as uuidv4 } from "uuid";
|
|
11124
|
+
var APP_AUTOMATE_CAP_KEYS = ["appium:app", "appium:bundleId", "appium:appPackage", "appium:appActivity"];
|
|
11125
|
+
function hasAppCap(cap) {
|
|
11126
|
+
if (!cap || typeof cap !== "object") {
|
|
11127
|
+
return false;
|
|
11128
|
+
}
|
|
11129
|
+
const record = cap;
|
|
11130
|
+
if (APP_AUTOMATE_CAP_KEYS.some((key) => !isUndefined(record[key]))) {
|
|
11131
|
+
return true;
|
|
11132
|
+
}
|
|
11133
|
+
const appiumOptions = record["appium:options"];
|
|
11134
|
+
return !!(appiumOptions && !isUndefined(appiumOptions.app));
|
|
11135
|
+
}
|
|
11136
|
+
function detectAppAutomate(capabilities) {
|
|
11137
|
+
if (!capabilities) {
|
|
11138
|
+
return false;
|
|
11139
|
+
}
|
|
11140
|
+
const flat = [];
|
|
11141
|
+
if (Array.isArray(capabilities)) {
|
|
11142
|
+
for (const entry of capabilities) {
|
|
11143
|
+
if (!entry || typeof entry !== "object") {
|
|
11144
|
+
continue;
|
|
11145
|
+
}
|
|
11146
|
+
if ("alwaysMatch" in entry) {
|
|
11147
|
+
const w3c = entry;
|
|
11148
|
+
flat.push(w3c.alwaysMatch);
|
|
11149
|
+
if (Array.isArray(w3c.firstMatch)) {
|
|
11150
|
+
flat.push(...w3c.firstMatch);
|
|
11151
|
+
}
|
|
11152
|
+
continue;
|
|
11153
|
+
}
|
|
11154
|
+
const values = Object.values(entry);
|
|
11155
|
+
const isParallelMultiremote = values.length > 0 && values.every(
|
|
11156
|
+
(v) => v !== null && typeof v === "object" && v.capabilities
|
|
11157
|
+
);
|
|
11158
|
+
if (isParallelMultiremote) {
|
|
11159
|
+
for (const v of values) {
|
|
11160
|
+
flat.push(v.capabilities);
|
|
11161
|
+
}
|
|
11162
|
+
} else {
|
|
11163
|
+
flat.push(entry);
|
|
11164
|
+
}
|
|
11165
|
+
}
|
|
11166
|
+
} else {
|
|
11167
|
+
for (const v of Object.values(capabilities)) {
|
|
11168
|
+
const inner = v.capabilities;
|
|
11169
|
+
if (inner) {
|
|
11170
|
+
flat.push(inner);
|
|
11171
|
+
}
|
|
11172
|
+
}
|
|
11173
|
+
}
|
|
11174
|
+
return flat.some(hasAppCap);
|
|
11175
|
+
}
|
|
10860
11176
|
var BrowserStackConfig = class _BrowserStackConfig {
|
|
10861
|
-
static getInstance(options, config) {
|
|
11177
|
+
static getInstance(options, config, capabilities, isBrowserStackInfra) {
|
|
10862
11178
|
if (!this._instance && options && config) {
|
|
10863
|
-
this._instance = new _BrowserStackConfig(options, config);
|
|
11179
|
+
this._instance = new _BrowserStackConfig(options, config, capabilities, isBrowserStackInfra);
|
|
10864
11180
|
}
|
|
10865
11181
|
return this._instance;
|
|
10866
11182
|
}
|
|
@@ -10881,7 +11197,7 @@ var BrowserStackConfig = class _BrowserStackConfig {
|
|
|
10881
11197
|
percyBuildId;
|
|
10882
11198
|
isPercyAutoEnabled = false;
|
|
10883
11199
|
sdkRunID;
|
|
10884
|
-
constructor(options, config) {
|
|
11200
|
+
constructor(options, config, capabilities, isBrowserStackInfra = true) {
|
|
10885
11201
|
this.framework = config.framework;
|
|
10886
11202
|
this.userName = config.user;
|
|
10887
11203
|
this.accessKey = config.key;
|
|
@@ -10889,11 +11205,11 @@ var BrowserStackConfig = class _BrowserStackConfig {
|
|
|
10889
11205
|
this.percy = options.percy || false;
|
|
10890
11206
|
this.accessibility = options.accessibility;
|
|
10891
11207
|
this.app = options.app;
|
|
10892
|
-
this.appAutomate = !isUndefined(options.app);
|
|
10893
|
-
this.automate = !this.appAutomate;
|
|
11208
|
+
this.appAutomate = isBrowserStackInfra && (!isUndefined(options.app) || detectAppAutomate(capabilities));
|
|
11209
|
+
this.automate = isBrowserStackInfra && !this.appAutomate;
|
|
10894
11210
|
this.buildIdentifier = options.buildIdentifier;
|
|
10895
11211
|
this.sdkRunID = uuidv4();
|
|
10896
|
-
|
|
11212
|
+
BStackLogger.info(`BrowserStack service started with id: ${this.sdkRunID}`);
|
|
10897
11213
|
}
|
|
10898
11214
|
sentFunnelData() {
|
|
10899
11215
|
this.funnelDataSent = true;
|
|
@@ -10903,32 +11219,32 @@ var config_default = BrowserStackConfig;
|
|
|
10903
11219
|
|
|
10904
11220
|
// src/exitHandler.ts
|
|
10905
11221
|
import { spawn as spawn4 } from "node:child_process";
|
|
10906
|
-
import
|
|
11222
|
+
import path17 from "node:path";
|
|
10907
11223
|
|
|
10908
11224
|
// src/instrumentation/funnelInstrumentation.ts
|
|
10909
11225
|
init_usageStats();
|
|
10910
11226
|
init_bstackLogger();
|
|
10911
11227
|
init_constants();
|
|
10912
|
-
import
|
|
11228
|
+
import os5 from "node:os";
|
|
10913
11229
|
import util4, { format as format2 } from "node:util";
|
|
10914
|
-
import
|
|
10915
|
-
import
|
|
11230
|
+
import path12 from "node:path";
|
|
11231
|
+
import fs13 from "node:fs";
|
|
10916
11232
|
|
|
10917
11233
|
// src/data-store.ts
|
|
10918
11234
|
init_bstackLogger();
|
|
10919
|
-
import
|
|
10920
|
-
import
|
|
10921
|
-
var workersDataDirPath =
|
|
11235
|
+
import path11 from "node:path";
|
|
11236
|
+
import fs12 from "node:fs";
|
|
11237
|
+
var workersDataDirPath = path11.join(process.cwd(), "logs", "worker_data");
|
|
10922
11238
|
function getDataFromWorkers() {
|
|
10923
11239
|
const workersData = [];
|
|
10924
|
-
if (!
|
|
11240
|
+
if (!fs12.existsSync(workersDataDirPath)) {
|
|
10925
11241
|
return workersData;
|
|
10926
11242
|
}
|
|
10927
|
-
const files =
|
|
11243
|
+
const files = fs12.readdirSync(workersDataDirPath);
|
|
10928
11244
|
files.forEach((file) => {
|
|
10929
|
-
|
|
10930
|
-
const filePath =
|
|
10931
|
-
const fileContent =
|
|
11245
|
+
BStackLogger.debug("Reading worker file " + file);
|
|
11246
|
+
const filePath = path11.join(workersDataDirPath, file);
|
|
11247
|
+
const fileContent = fs12.readFileSync(filePath, "utf8");
|
|
10932
11248
|
const workerData = JSON.parse(fileContent);
|
|
10933
11249
|
workersData.push(workerData);
|
|
10934
11250
|
});
|
|
@@ -10936,21 +11252,21 @@ function getDataFromWorkers() {
|
|
|
10936
11252
|
return workersData;
|
|
10937
11253
|
}
|
|
10938
11254
|
function saveWorkerData(data) {
|
|
10939
|
-
const filePath =
|
|
11255
|
+
const filePath = path11.join(workersDataDirPath, "worker-data-" + process.pid + ".json");
|
|
10940
11256
|
try {
|
|
10941
11257
|
createWorkersDataDir();
|
|
10942
|
-
|
|
11258
|
+
fs12.writeFileSync(filePath, JSON.stringify(data));
|
|
10943
11259
|
} catch (e) {
|
|
10944
|
-
|
|
11260
|
+
BStackLogger.debug("Exception in saving worker data: " + e);
|
|
10945
11261
|
}
|
|
10946
11262
|
}
|
|
10947
11263
|
function removeWorkersDataDir() {
|
|
10948
|
-
|
|
11264
|
+
fs12.rmSync(workersDataDirPath, { recursive: true, force: true });
|
|
10949
11265
|
return true;
|
|
10950
11266
|
}
|
|
10951
11267
|
function createWorkersDataDir() {
|
|
10952
|
-
if (!
|
|
10953
|
-
|
|
11268
|
+
if (!fs12.existsSync(workersDataDirPath)) {
|
|
11269
|
+
fs12.mkdirSync(workersDataDirPath, { recursive: true });
|
|
10954
11270
|
}
|
|
10955
11271
|
return true;
|
|
10956
11272
|
}
|
|
@@ -10964,16 +11280,16 @@ init_performance_tester();
|
|
|
10964
11280
|
init_constants2();
|
|
10965
11281
|
async function fireFunnelTestEvent(eventType, config, isCLIEnabled = false) {
|
|
10966
11282
|
if (!config.userName || !config.accessKey) {
|
|
10967
|
-
|
|
11283
|
+
BStackLogger.debug("username/accesskey not passed");
|
|
10968
11284
|
return;
|
|
10969
11285
|
}
|
|
10970
11286
|
try {
|
|
10971
11287
|
const data = buildEventData(eventType, config, isCLIEnabled);
|
|
10972
11288
|
await fireFunnelRequest(data);
|
|
10973
|
-
|
|
11289
|
+
BStackLogger.debug("Funnel event success");
|
|
10974
11290
|
config.sentFunnelData();
|
|
10975
11291
|
} catch (error) {
|
|
10976
|
-
|
|
11292
|
+
BStackLogger.debug(`Exception in sending funnel data: ${format2(error)}`);
|
|
10977
11293
|
}
|
|
10978
11294
|
}
|
|
10979
11295
|
async function sendStart(config) {
|
|
@@ -10998,9 +11314,9 @@ async function sendFinish(config, isCLIEnabled = false) {
|
|
|
10998
11314
|
}
|
|
10999
11315
|
function saveFunnelData(eventType, config, isCLIEnabled = false) {
|
|
11000
11316
|
const data = buildEventData(eventType, config, isCLIEnabled);
|
|
11001
|
-
|
|
11002
|
-
const filePath =
|
|
11003
|
-
|
|
11317
|
+
BStackLogger.ensureLogsFolder();
|
|
11318
|
+
const filePath = path12.join(BStackLogger.logFolderPath, "funnelData.json");
|
|
11319
|
+
fs13.writeFileSync(filePath, JSON.stringify(data));
|
|
11004
11320
|
return filePath;
|
|
11005
11321
|
}
|
|
11006
11322
|
function redactCredentialsFromFunnelData(data) {
|
|
@@ -11017,7 +11333,7 @@ function redactCredentialsFromFunnelData(data) {
|
|
|
11017
11333
|
async function fireFunnelRequest(data) {
|
|
11018
11334
|
const { userName, accessKey } = data;
|
|
11019
11335
|
redactCredentialsFromFunnelData(data);
|
|
11020
|
-
|
|
11336
|
+
BStackLogger.debug("Sending SDK event with data " + util4.inspect(data, { depth: 6 }));
|
|
11021
11337
|
const encodedAuth = Buffer.from(`${userName}:${accessKey}`, "utf8").toString("base64");
|
|
11022
11338
|
const response = await fetchWrap(APIUtils.FUNNEL_INSTRUMENTATION_URL, {
|
|
11023
11339
|
method: "POST",
|
|
@@ -11027,7 +11343,7 @@ async function fireFunnelRequest(data) {
|
|
|
11027
11343
|
},
|
|
11028
11344
|
body: JSON.stringify(data)
|
|
11029
11345
|
});
|
|
11030
|
-
|
|
11346
|
+
BStackLogger.debug("Funnel Event Response: " + JSON.stringify(await response.text()));
|
|
11031
11347
|
}
|
|
11032
11348
|
function getProductList(config) {
|
|
11033
11349
|
const products = [];
|
|
@@ -11061,8 +11377,8 @@ function buildEventData(eventType, config, isCLIEnabled = false) {
|
|
|
11061
11377
|
buildName: config.buildName || "undefined",
|
|
11062
11378
|
buildIdentifier: String(config.buildIdentifier),
|
|
11063
11379
|
// Host details
|
|
11064
|
-
os:
|
|
11065
|
-
hostname:
|
|
11380
|
+
os: os5.type() || "unknown",
|
|
11381
|
+
hostname: os5.hostname() || "unknown",
|
|
11066
11382
|
// Product Details
|
|
11067
11383
|
productMap: getProductMap(config),
|
|
11068
11384
|
product: getProductList(config),
|
|
@@ -11112,30 +11428,30 @@ function isProxyError(authResult) {
|
|
|
11112
11428
|
function handleProxyError(config, isSelfHealEnabled) {
|
|
11113
11429
|
sendEvent.tcgProxyFailure(config);
|
|
11114
11430
|
if (isSelfHealEnabled) {
|
|
11115
|
-
|
|
11431
|
+
BStackLogger.warn("Proxy Error. Disabling Healing for this session.");
|
|
11116
11432
|
}
|
|
11117
11433
|
}
|
|
11118
11434
|
function handleUpgradeRequired(isSelfHealEnabled) {
|
|
11119
11435
|
if (isSelfHealEnabled) {
|
|
11120
|
-
|
|
11436
|
+
BStackLogger.warn("Please upgrade Browserstack Service to the latest version to use the self-healing feature.");
|
|
11121
11437
|
}
|
|
11122
11438
|
}
|
|
11123
11439
|
function handleAuthenticationFailure(status, config, isSelfHealEnabled) {
|
|
11124
11440
|
if (status >= 500) {
|
|
11125
11441
|
if (isSelfHealEnabled) {
|
|
11126
|
-
|
|
11442
|
+
BStackLogger.warn("Something went wrong. Disabling healing for this session. Please try again later.");
|
|
11127
11443
|
}
|
|
11128
11444
|
sendEvent.tcgDown(config);
|
|
11129
11445
|
} else {
|
|
11130
11446
|
if (isSelfHealEnabled) {
|
|
11131
|
-
|
|
11447
|
+
BStackLogger.warn("Authentication Failed. Disabling Healing for this session.");
|
|
11132
11448
|
}
|
|
11133
11449
|
sendEvent.tcgAuthFailure(config);
|
|
11134
11450
|
}
|
|
11135
11451
|
}
|
|
11136
11452
|
function handleAuthenticationSuccess(isHealingEnabledForUser, userId, config, isSelfHealEnabled) {
|
|
11137
11453
|
if (!isHealingEnabledForUser && isSelfHealEnabled) {
|
|
11138
|
-
|
|
11454
|
+
BStackLogger.warn("Healing is not enabled for your group, please contact the admin");
|
|
11139
11455
|
} else if (userId && isHealingEnabledForUser) {
|
|
11140
11456
|
sendEvent.tcgtInitSuccessful(config);
|
|
11141
11457
|
}
|
|
@@ -11147,7 +11463,7 @@ function handleInitializationFailure(status, config, isSelfHealEnabled) {
|
|
|
11147
11463
|
sendEvent.invalidTcgAuth(config);
|
|
11148
11464
|
}
|
|
11149
11465
|
if (isSelfHealEnabled) {
|
|
11150
|
-
|
|
11466
|
+
BStackLogger.warn("Authentication Failed. Healing will be disabled for this session.");
|
|
11151
11467
|
}
|
|
11152
11468
|
}
|
|
11153
11469
|
function handleHealingInstrumentation(authResult, config, isSelfHealEnabled) {
|
|
@@ -11174,7 +11490,7 @@ function handleHealingInstrumentation(authResult, config, isSelfHealEnabled) {
|
|
|
11174
11490
|
return;
|
|
11175
11491
|
}
|
|
11176
11492
|
} catch (err) {
|
|
11177
|
-
|
|
11493
|
+
BStackLogger.debug("Error in handling healing instrumentation: " + err);
|
|
11178
11494
|
}
|
|
11179
11495
|
}
|
|
11180
11496
|
|
|
@@ -11186,36 +11502,36 @@ init_bstackLogger();
|
|
|
11186
11502
|
init_cli();
|
|
11187
11503
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
11188
11504
|
var __filename = fileURLToPath2(import.meta.url);
|
|
11189
|
-
var __dirname =
|
|
11505
|
+
var __dirname = path17.dirname(__filename);
|
|
11190
11506
|
function setupExitHandlers() {
|
|
11191
11507
|
const handleCLICleanup = () => {
|
|
11192
|
-
|
|
11508
|
+
BStackLogger.debug("Handling CLI cleanup in exit handler");
|
|
11193
11509
|
try {
|
|
11194
11510
|
const cliProcess = BrowserstackCLI.getInstance()?.process;
|
|
11195
11511
|
if (cliProcess && cliProcess.pid && cliProcess.exitCode === null) {
|
|
11196
|
-
|
|
11512
|
+
BStackLogger.debug(`Found CLI process with PID ${cliProcess.pid}, terminating`);
|
|
11197
11513
|
try {
|
|
11198
11514
|
if (process.platform === "win32") {
|
|
11199
11515
|
cliProcess.kill("SIGTERM");
|
|
11200
|
-
|
|
11516
|
+
BStackLogger.debug("CLI process terminated successfully with SIGTERM (Windows)");
|
|
11201
11517
|
} else {
|
|
11202
11518
|
cliProcess.kill("SIGINT");
|
|
11203
|
-
|
|
11519
|
+
BStackLogger.debug("CLI process terminated successfully with SIGINT (Unix)");
|
|
11204
11520
|
}
|
|
11205
11521
|
} catch (processError2) {
|
|
11206
|
-
|
|
11522
|
+
BStackLogger.debug(`CLI process termination error: ${processError2}`);
|
|
11207
11523
|
try {
|
|
11208
11524
|
cliProcess.kill();
|
|
11209
|
-
|
|
11525
|
+
BStackLogger.debug("CLI process terminated with default signal (fallback)");
|
|
11210
11526
|
} catch (fallbackError) {
|
|
11211
|
-
|
|
11527
|
+
BStackLogger.debug(`CLI process fallback termination error: ${fallbackError}`);
|
|
11212
11528
|
}
|
|
11213
11529
|
}
|
|
11214
11530
|
} else {
|
|
11215
|
-
|
|
11531
|
+
BStackLogger.debug("No CLI process found to terminate");
|
|
11216
11532
|
}
|
|
11217
11533
|
} catch (error) {
|
|
11218
|
-
|
|
11534
|
+
BStackLogger.debug(`Error in CLI cleanup: ${error}`);
|
|
11219
11535
|
}
|
|
11220
11536
|
};
|
|
11221
11537
|
process.on("exit", () => {
|
|
@@ -11223,8 +11539,8 @@ function setupExitHandlers() {
|
|
|
11223
11539
|
handleCLICleanup();
|
|
11224
11540
|
const args = shouldCallCleanup(config_default.getInstance(), isCLIEnabled);
|
|
11225
11541
|
if (Array.isArray(args) && args.length) {
|
|
11226
|
-
|
|
11227
|
-
const childProcess = spawn4("node", [`${
|
|
11542
|
+
BStackLogger.debug(`Spawning cleanup.js with args: ${args.join(", ")}`);
|
|
11543
|
+
const childProcess = spawn4("node", [`${path17.join(__dirname, "cleanup.js")}`, ...args], { detached: true, stdio: "inherit", env: { ...process.env } });
|
|
11228
11544
|
childProcess.unref();
|
|
11229
11545
|
}
|
|
11230
11546
|
});
|
|
@@ -11250,8 +11566,8 @@ function shouldCallCleanup(config, isCLIEnabled = false) {
|
|
|
11250
11566
|
// src/ai-handler.ts
|
|
11251
11567
|
init_bstackLogger();
|
|
11252
11568
|
init_constants();
|
|
11253
|
-
import
|
|
11254
|
-
import
|
|
11569
|
+
import path18 from "node:path";
|
|
11570
|
+
import fs14 from "node:fs";
|
|
11255
11571
|
import url2 from "node:url";
|
|
11256
11572
|
import aiSDK from "@browserstack/ai-sdk-node";
|
|
11257
11573
|
init_util();
|
|
@@ -11278,7 +11594,7 @@ var AiHandler = class {
|
|
|
11278
11594
|
}
|
|
11279
11595
|
} else if (options.selfHeal === true) {
|
|
11280
11596
|
const healingWarnMessage = authResult.message;
|
|
11281
|
-
|
|
11597
|
+
BStackLogger.warn(`Healing Auth failed. Disabling healing for this session. Reason: ${healingWarnMessage}`);
|
|
11282
11598
|
}
|
|
11283
11599
|
return caps;
|
|
11284
11600
|
}
|
|
@@ -11287,8 +11603,8 @@ var AiHandler = class {
|
|
|
11287
11603
|
}
|
|
11288
11604
|
async installFirefoxExtension(browser) {
|
|
11289
11605
|
const __dirname2 = url2.fileURLToPath(new URL(".", import.meta.url));
|
|
11290
|
-
const extensionPath =
|
|
11291
|
-
const extFile =
|
|
11606
|
+
const extensionPath = path18.resolve(__dirname2, aiSDK.BrowserstackHealing.getFirefoxAddonPath());
|
|
11607
|
+
const extFile = fs14.readFileSync(extensionPath);
|
|
11292
11608
|
await browser.installAddOn(extFile.toString("base64"), true);
|
|
11293
11609
|
}
|
|
11294
11610
|
async handleHealing(orginalFunc, using, value, browser, options) {
|
|
@@ -11315,7 +11631,7 @@ var AiHandler = class {
|
|
|
11315
11631
|
return result;
|
|
11316
11632
|
}
|
|
11317
11633
|
if (options.selfHeal === true && this.authResult.isHealingEnabled) {
|
|
11318
|
-
|
|
11634
|
+
BStackLogger.info("findElement failed, trying to heal");
|
|
11319
11635
|
PerformanceTester.start(AI_EVENTS.SELF_HEAL_STEP);
|
|
11320
11636
|
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
11637
|
if (script) {
|
|
@@ -11325,7 +11641,7 @@ var AiHandler = class {
|
|
|
11325
11641
|
PerformanceTester.end(AI_EVENTS.SELF_HEAL_GET_RESULT);
|
|
11326
11642
|
if (tcgData && tcgData.selector && tcgData.value) {
|
|
11327
11643
|
const healedResult = await orginalFunc(tcgData.selector, tcgData.value);
|
|
11328
|
-
|
|
11644
|
+
BStackLogger.info("Healing worked, element found: " + tcgData.selector + ": " + tcgData.value);
|
|
11329
11645
|
PerformanceTester.end(AI_EVENTS.SELF_HEAL_STEP);
|
|
11330
11646
|
return healedResult.error ? result : healedResult;
|
|
11331
11647
|
}
|
|
@@ -11337,9 +11653,9 @@ var AiHandler = class {
|
|
|
11337
11653
|
} catch (err) {
|
|
11338
11654
|
PerformanceTester.end(AI_EVENTS.SELF_HEAL_STEP, false, String(err));
|
|
11339
11655
|
if (options.selfHeal === true) {
|
|
11340
|
-
|
|
11656
|
+
BStackLogger.warn("Something went wrong while healing. Disabling healing for this command");
|
|
11341
11657
|
} else {
|
|
11342
|
-
|
|
11658
|
+
BStackLogger.warn("Error in findElement: " + err + "using: " + using + "value: " + value);
|
|
11343
11659
|
}
|
|
11344
11660
|
}
|
|
11345
11661
|
return await orginalFunc(using, value);
|
|
@@ -11375,7 +11691,7 @@ var AiHandler = class {
|
|
|
11375
11691
|
}
|
|
11376
11692
|
} catch (err) {
|
|
11377
11693
|
if (options.selfHeal === true) {
|
|
11378
|
-
|
|
11694
|
+
BStackLogger.warn(`Error while initiliazing Browserstack healing Extension ${err}`);
|
|
11379
11695
|
}
|
|
11380
11696
|
}
|
|
11381
11697
|
return caps;
|
|
@@ -11384,7 +11700,7 @@ var AiHandler = class {
|
|
|
11384
11700
|
if (SUPPORTED_BROWSERS_FOR_AI.includes(browser.capabilities?.browserName?.toLowerCase())) {
|
|
11385
11701
|
const authInfo = this.authResult;
|
|
11386
11702
|
if (Object.keys(authInfo).length === 0 && options.selfHeal === true) {
|
|
11387
|
-
|
|
11703
|
+
BStackLogger.debug("TCG Auth result is empty");
|
|
11388
11704
|
return;
|
|
11389
11705
|
}
|
|
11390
11706
|
const { isAuthenticated, sessionToken, defaultLogDataEnabled } = authInfo;
|
|
@@ -11412,7 +11728,7 @@ var AiHandler = class {
|
|
|
11412
11728
|
}
|
|
11413
11729
|
} catch (err) {
|
|
11414
11730
|
if (options.selfHeal === true) {
|
|
11415
|
-
|
|
11731
|
+
BStackLogger.warn(`Error while setting up self-healing: ${err}. Disabling healing for this session.`);
|
|
11416
11732
|
}
|
|
11417
11733
|
}
|
|
11418
11734
|
}
|
|
@@ -11430,9 +11746,10 @@ var BrowserstackLauncherService = class {
|
|
|
11430
11746
|
constructor(_options, capabilities, _config) {
|
|
11431
11747
|
this._options = _options;
|
|
11432
11748
|
this._config = _config;
|
|
11433
|
-
|
|
11749
|
+
BStackLogger.clearLogFile();
|
|
11434
11750
|
PercyLogger.clearLogFile();
|
|
11435
11751
|
setupExitHandlers();
|
|
11752
|
+
configureCaCertificate(this._options);
|
|
11436
11753
|
if (!this._config) {
|
|
11437
11754
|
this._config = _options;
|
|
11438
11755
|
}
|
|
@@ -11454,12 +11771,13 @@ var BrowserstackLauncherService = class {
|
|
|
11454
11771
|
if (!isUndefined(process.env.TEST_REPORTING_BUILD_TAG)) {
|
|
11455
11772
|
process.env.TEST_OBSERVABILITY_BUILD_TAG = process.env.TEST_REPORTING_BUILD_TAG;
|
|
11456
11773
|
}
|
|
11457
|
-
|
|
11458
|
-
|
|
11459
|
-
|
|
11774
|
+
const isBrowserStackInfra = isBrowserstackInfra(_config, capabilities);
|
|
11775
|
+
this.browserStackConfig = config_default.getInstance(_options, _config, capabilities, isBrowserStackInfra);
|
|
11776
|
+
BStackLogger.debug(`_options data: ${JSON.stringify(_options)}`);
|
|
11777
|
+
BStackLogger.debug(`webdriver capabilities data: ${JSON.stringify(capabilities)}`);
|
|
11460
11778
|
const configCopy = JSON.parse(JSON.stringify(_config));
|
|
11461
11779
|
CrashReporter.recursivelyRedactKeysFromObject(configCopy, ["user", "username", "key", "accesskey", "password"]);
|
|
11462
|
-
|
|
11780
|
+
BStackLogger.debug(`_config data: ${JSON.stringify(configCopy)}`);
|
|
11463
11781
|
if (Array.isArray(capabilities)) {
|
|
11464
11782
|
capabilities.flatMap((c) => {
|
|
11465
11783
|
if ("alwaysMatch" in c) {
|
|
@@ -11546,7 +11864,7 @@ var BrowserstackLauncherService = class {
|
|
|
11546
11864
|
try {
|
|
11547
11865
|
CrashReporter.setConfigDetails(this._config, capabilities, this._options);
|
|
11548
11866
|
} catch (error) {
|
|
11549
|
-
|
|
11867
|
+
BStackLogger.error(`[Crash_Report_Upload] Config processing failed due to ${error}`);
|
|
11550
11868
|
}
|
|
11551
11869
|
}
|
|
11552
11870
|
browserstackLocal;
|
|
@@ -11576,7 +11894,7 @@ var BrowserstackLauncherService = class {
|
|
|
11576
11894
|
if (config.specs && Array.isArray(config.specs) && isValidEnabledValue(this._options.testOrchestrationOptions?.runSmartSelection?.enabled)) {
|
|
11577
11895
|
try {
|
|
11578
11896
|
const glob = (await import("glob")).sync;
|
|
11579
|
-
const
|
|
11897
|
+
const path22 = await import("node:path");
|
|
11580
11898
|
const expandedSpecs = [];
|
|
11581
11899
|
for (const specPattern of config.specs) {
|
|
11582
11900
|
if (typeof specPattern === "string") {
|
|
@@ -11593,21 +11911,21 @@ var BrowserstackLauncherService = class {
|
|
|
11593
11911
|
}) || [];
|
|
11594
11912
|
filenames.forEach((filename) => {
|
|
11595
11913
|
let absolutePath = filename;
|
|
11596
|
-
if (!
|
|
11597
|
-
absolutePath =
|
|
11914
|
+
if (!path22.isAbsolute(filename)) {
|
|
11915
|
+
absolutePath = path22.resolve(rootDir, filename);
|
|
11598
11916
|
}
|
|
11599
|
-
let relativePath =
|
|
11917
|
+
let relativePath = path22.relative(cwd, absolutePath);
|
|
11600
11918
|
relativePath = relativePath.replace(/\\/g, "/");
|
|
11601
11919
|
expandedSpecs.push(relativePath);
|
|
11602
11920
|
});
|
|
11603
11921
|
}
|
|
11604
11922
|
}
|
|
11605
11923
|
if (expandedSpecs.length > 0) {
|
|
11606
|
-
|
|
11924
|
+
BStackLogger.info(`Expanded specs from glob patterns to ${expandedSpecs.length} files`);
|
|
11607
11925
|
config.specs = expandedSpecs;
|
|
11608
11926
|
}
|
|
11609
11927
|
} catch (error) {
|
|
11610
|
-
|
|
11928
|
+
BStackLogger.error(`Failed to expand spec patterns: ${error}`);
|
|
11611
11929
|
}
|
|
11612
11930
|
}
|
|
11613
11931
|
try {
|
|
@@ -11618,11 +11936,11 @@ var BrowserstackLauncherService = class {
|
|
|
11618
11936
|
CLIUtils.setFrameworkDetail(WDIO_NAMING_PREFIX + config.framework, "WebdriverIO");
|
|
11619
11937
|
const binconfig = CLIUtils.getBinConfig(config, capabilities, this._options, this._buildTag);
|
|
11620
11938
|
await BrowserstackCLI.getInstance().bootstrap(this._options, config, binconfig);
|
|
11621
|
-
|
|
11939
|
+
BStackLogger.debug(`Is CLI running ${BrowserstackCLI.getInstance().isRunning()}`);
|
|
11622
11940
|
PerformanceTester.end(FRAMEWORK_EVENTS.START);
|
|
11623
11941
|
}
|
|
11624
11942
|
} catch (err) {
|
|
11625
|
-
|
|
11943
|
+
BStackLogger.error(`Error while starting CLI ${err}`);
|
|
11626
11944
|
PerformanceTester.end(FRAMEWORK_EVENTS.START, false, format4(err));
|
|
11627
11945
|
}
|
|
11628
11946
|
PerformanceTester.end(FRAMEWORK_EVENTS.INIT);
|
|
@@ -11641,13 +11959,13 @@ var BrowserstackLauncherService = class {
|
|
|
11641
11959
|
}
|
|
11642
11960
|
} catch (err) {
|
|
11643
11961
|
if (this._options.selfHeal === true) {
|
|
11644
|
-
|
|
11962
|
+
BStackLogger.warn(`Error while setting up Browserstack healing Extension ${err}. Disabling healing for this session.`);
|
|
11645
11963
|
}
|
|
11646
11964
|
}
|
|
11647
11965
|
}
|
|
11648
11966
|
if (!BrowserstackCLI.getInstance().isRunning()) {
|
|
11649
11967
|
if (!this._options.app) {
|
|
11650
|
-
|
|
11968
|
+
BStackLogger.debug("app is not defined in browserstack-service config, skipping ...");
|
|
11651
11969
|
} else {
|
|
11652
11970
|
let app = {};
|
|
11653
11971
|
const appConfig = this._options.app;
|
|
@@ -11656,10 +11974,10 @@ var BrowserstackLauncherService = class {
|
|
|
11656
11974
|
} catch (error) {
|
|
11657
11975
|
throw new SevereServiceError(error.message);
|
|
11658
11976
|
}
|
|
11659
|
-
if (VALID_APP_EXTENSION.includes(
|
|
11660
|
-
if (
|
|
11977
|
+
if (VALID_APP_EXTENSION.includes(path21.extname(app.app))) {
|
|
11978
|
+
if (fs15.existsSync(app.app)) {
|
|
11661
11979
|
const data = await this._uploadApp(app);
|
|
11662
|
-
|
|
11980
|
+
BStackLogger.info(`app upload completed: ${JSON.stringify(data)}`);
|
|
11663
11981
|
app.app = data.app_url;
|
|
11664
11982
|
} else if (app.customId) {
|
|
11665
11983
|
app.app = app.customId;
|
|
@@ -11667,7 +11985,7 @@ var BrowserstackLauncherService = class {
|
|
|
11667
11985
|
throw new SevereServiceError(`[Invalid app path] app path ${app.app} is not correct, Provide correct path to app under test`);
|
|
11668
11986
|
}
|
|
11669
11987
|
}
|
|
11670
|
-
|
|
11988
|
+
BStackLogger.info(`Using app: ${app.app}`);
|
|
11671
11989
|
this._updateCaps(capabilities, "app", app.app);
|
|
11672
11990
|
}
|
|
11673
11991
|
}
|
|
@@ -11680,7 +11998,7 @@ var BrowserstackLauncherService = class {
|
|
|
11680
11998
|
const shouldSetupPercy = this._options.percy || isUndefined(this._options.percy) && this._options.app;
|
|
11681
11999
|
let buildStartResponse = null;
|
|
11682
12000
|
if (!BrowserstackCLI.getInstance().isRunning() && (this._options.testObservability || this._accessibilityAutomation || shouldSetupPercy)) {
|
|
11683
|
-
|
|
12001
|
+
BStackLogger.debug("Sending launch start event");
|
|
11684
12002
|
buildStartResponse = await launchTestSession(this._options, this._config, {
|
|
11685
12003
|
projectName: this._projectName,
|
|
11686
12004
|
buildName: this._buildName,
|
|
@@ -11739,15 +12057,15 @@ var BrowserstackLauncherService = class {
|
|
|
11739
12057
|
if (typeof spec !== "string") {
|
|
11740
12058
|
return spec;
|
|
11741
12059
|
}
|
|
11742
|
-
const absolutePath =
|
|
11743
|
-
const relativePath =
|
|
12060
|
+
const absolutePath = path21.isAbsolute(spec) ? spec : path21.resolve(cwd, spec);
|
|
12061
|
+
const relativePath = path21.relative(rootDir, absolutePath);
|
|
11744
12062
|
return relativePath.replace(/\\/g, "/");
|
|
11745
12063
|
});
|
|
11746
12064
|
};
|
|
11747
12065
|
try {
|
|
11748
12066
|
const { applyOrchestrationIfEnabled: applyOrchestrationIfEnabled2 } = await Promise.resolve().then(() => (init_apply_orchestration(), apply_orchestration_exports));
|
|
11749
12067
|
if (config.specs && config.specs.length > 0 && this._options.testObservability && isValidEnabledValue(this._options.testOrchestrationOptions?.runSmartSelection?.enabled)) {
|
|
11750
|
-
|
|
12068
|
+
BStackLogger.info("Applying test orchestration");
|
|
11751
12069
|
const specs = config.specs.filter((spec) => typeof spec === "string");
|
|
11752
12070
|
console.log(`Specs before orchestration: ${specs}`);
|
|
11753
12071
|
const orderedSpecs = await applyOrchestrationIfEnabled2(specs, this._options);
|
|
@@ -11755,14 +12073,14 @@ var BrowserstackLauncherService = class {
|
|
|
11755
12073
|
const specsToConvert = orderedSpecs && orderedSpecs.length > 0 ? orderedSpecs : specs;
|
|
11756
12074
|
config.specs = convertToRootDirRelative(specsToConvert);
|
|
11757
12075
|
console.log(`Specs after orchestration: ${config.specs}`);
|
|
11758
|
-
|
|
12076
|
+
BStackLogger.info("Test specs updated with orchestrated order");
|
|
11759
12077
|
}
|
|
11760
12078
|
} catch (error) {
|
|
11761
|
-
|
|
12079
|
+
BStackLogger.error(`Error applying test orchestration: ${error}`);
|
|
11762
12080
|
if (config.specs && config.specs.length > 0) {
|
|
11763
12081
|
const specs = config.specs.filter((spec) => typeof spec === "string");
|
|
11764
12082
|
config.specs = convertToRootDirRelative(specs);
|
|
11765
|
-
|
|
12083
|
+
BStackLogger.debug(`Specs converted back to rootDir-relative after error: ${config.specs}`);
|
|
11766
12084
|
}
|
|
11767
12085
|
}
|
|
11768
12086
|
}
|
|
@@ -11770,7 +12088,7 @@ var BrowserstackLauncherService = class {
|
|
|
11770
12088
|
return;
|
|
11771
12089
|
}
|
|
11772
12090
|
if (!this._options.browserstackLocal) {
|
|
11773
|
-
return
|
|
12091
|
+
return BStackLogger.info("browserstackLocal is not enabled - skipping...");
|
|
11774
12092
|
}
|
|
11775
12093
|
const opts = {
|
|
11776
12094
|
key: this._config.key,
|
|
@@ -11783,7 +12101,7 @@ var BrowserstackLauncherService = class {
|
|
|
11783
12101
|
}
|
|
11784
12102
|
const obs = new PerformanceObserver2((list) => {
|
|
11785
12103
|
const entry = list.getEntries()[0];
|
|
11786
|
-
|
|
12104
|
+
BStackLogger.info(`Browserstack Local successfully started after ${entry.duration}ms`);
|
|
11787
12105
|
});
|
|
11788
12106
|
obs.observe({ entryTypes: ["measure"] });
|
|
11789
12107
|
let timer;
|
|
@@ -11816,13 +12134,13 @@ var BrowserstackLauncherService = class {
|
|
|
11816
12134
|
PerformanceTester.start(FRAMEWORK_EVENTS.STOP);
|
|
11817
12135
|
try {
|
|
11818
12136
|
const isCLIEnabled = BrowserstackCLI.getInstance().isRunning();
|
|
11819
|
-
|
|
11820
|
-
|
|
12137
|
+
BStackLogger.debug("Inside OnComplete hook..");
|
|
12138
|
+
BStackLogger.debug("Sending stop launch event");
|
|
11821
12139
|
try {
|
|
11822
12140
|
await (isCLIEnabled ? BrowserstackCLI.getInstance().stop() : stopBuildUpstream());
|
|
11823
12141
|
PerformanceTester.end(FRAMEWORK_EVENTS.STOP);
|
|
11824
12142
|
} catch (err) {
|
|
11825
|
-
|
|
12143
|
+
BStackLogger.error(`Error while stopping CLI ${err}`);
|
|
11826
12144
|
PerformanceTester.end(FRAMEWORK_EVENTS.STOP, false, format4(err));
|
|
11827
12145
|
}
|
|
11828
12146
|
if (process.env[BROWSERSTACK_OBSERVABILITY] && process.env[BROWSERSTACK_TESTHUB_UUID]) {
|
|
@@ -11838,16 +12156,16 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
11838
12156
|
return;
|
|
11839
12157
|
}
|
|
11840
12158
|
const duration = (/* @__PURE__ */ new Date()).getTime() - new Date(process.env.START_TIME).getTime();
|
|
11841
|
-
|
|
12159
|
+
BStackLogger.info(`Total duration is ${duration / 1e3} s`);
|
|
11842
12160
|
}
|
|
11843
|
-
|
|
12161
|
+
BStackLogger.info(`BrowserStack service run ended for id: ${this.browserStackConfig?.sdkRunID} testhub id: ${testOpsConfig_default.getInstance()?.buildHashedId}`);
|
|
11844
12162
|
await sendFinish(this.browserStackConfig, isCLIEnabled);
|
|
11845
12163
|
try {
|
|
11846
12164
|
PerformanceTester.start(EVENTS.SDK_SEND_LOGS);
|
|
11847
12165
|
await this._uploadServiceLogs();
|
|
11848
12166
|
PerformanceTester.end(EVENTS.SDK_SEND_LOGS);
|
|
11849
12167
|
} catch (error) {
|
|
11850
|
-
|
|
12168
|
+
BStackLogger.debug(`Failed to upload BrowserStack WDIO Service logs ${error}`);
|
|
11851
12169
|
PerformanceTester.end(EVENTS.SDK_SEND_LOGS, false, format4(error));
|
|
11852
12170
|
}
|
|
11853
12171
|
PerformanceTester.end(EVENTS.SDK_ON_STOP);
|
|
@@ -11857,9 +12175,9 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
11857
12175
|
PerformanceTester.end(EVENTS.SDK_ON_STOP, false, format4(error));
|
|
11858
12176
|
PerformanceTester.end(EVENTS.SDK_CLEANUP, false, format4(error));
|
|
11859
12177
|
await PerformanceTester.stopAndGenerate("performance-launcher.html");
|
|
11860
|
-
|
|
12178
|
+
BStackLogger.error(`Error in onComplete hook: ${error}`);
|
|
11861
12179
|
}
|
|
11862
|
-
|
|
12180
|
+
BStackLogger.clearLogger();
|
|
11863
12181
|
if (this._options.percy) {
|
|
11864
12182
|
await this.stopPercy();
|
|
11865
12183
|
PercyLogger.clearLogger();
|
|
@@ -11943,10 +12261,10 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
11943
12261
|
}
|
|
11944
12262
|
}
|
|
11945
12263
|
async _uploadApp(app) {
|
|
11946
|
-
|
|
12264
|
+
BStackLogger.info(`uploading app ${app.app} ${app.customId ? `and custom_id: ${app.customId}` : ""} to browserstack`);
|
|
11947
12265
|
const form = new FormData();
|
|
11948
12266
|
if (app.app) {
|
|
11949
|
-
const fileName =
|
|
12267
|
+
const fileName = path21.basename(app.app);
|
|
11950
12268
|
const fileBuffer = await readFile(app.app);
|
|
11951
12269
|
const fileBlob = new Blob([new Uint8Array(fileBuffer)]);
|
|
11952
12270
|
form.append("file", fileBlob, fileName);
|
|
@@ -11995,8 +12313,8 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
11995
12313
|
const clientBuildUuid = this._getClientBuildUuid();
|
|
11996
12314
|
const response = await uploadLogs(getBrowserStackUser(this._config), getBrowserStackKey(this._config), clientBuildUuid);
|
|
11997
12315
|
if (response) {
|
|
11998
|
-
|
|
11999
|
-
|
|
12316
|
+
BStackLogger.info(`Upload response: ${JSON.stringify(response, null, 2)}`);
|
|
12317
|
+
BStackLogger.logToFile(`Response - ${format4(response)}`, "debug");
|
|
12000
12318
|
}
|
|
12001
12319
|
}
|
|
12002
12320
|
_removeCliOnlyCapabilityOptions(capabilities) {
|
|
@@ -12129,7 +12447,7 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
12129
12447
|
});
|
|
12130
12448
|
}
|
|
12131
12449
|
} catch (error) {
|
|
12132
|
-
|
|
12450
|
+
BStackLogger.debug(`Exception while retrieving capability value. Error - ${error}`);
|
|
12133
12451
|
}
|
|
12134
12452
|
}
|
|
12135
12453
|
_updateCaps(capabilities, capType, value) {
|
|
@@ -12265,7 +12583,7 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
12265
12583
|
}
|
|
12266
12584
|
if ((!this._buildName || process.env.BROWSERSTACK_BUILD_NAME) && this._buildIdentifier) {
|
|
12267
12585
|
this._updateCaps(capabilities, "buildIdentifier");
|
|
12268
|
-
|
|
12586
|
+
BStackLogger.warn("Skipping buildIdentifier as buildName is not passed.");
|
|
12269
12587
|
return;
|
|
12270
12588
|
}
|
|
12271
12589
|
if (this._buildIdentifier && this._buildIdentifier.includes("${DATE_TIME}")) {
|
|
@@ -12308,16 +12626,16 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
12308
12626
|
* else returns corresponding value in json file (e.g. { "wdio-build": { "identifier" : 2 } } => 2 in this case)
|
|
12309
12627
|
*/
|
|
12310
12628
|
_getLocalBuildNumber() {
|
|
12311
|
-
const browserstackFolderPath =
|
|
12629
|
+
const browserstackFolderPath = path21.join(os7.homedir(), ".browserstack");
|
|
12312
12630
|
try {
|
|
12313
|
-
if (!
|
|
12314
|
-
|
|
12631
|
+
if (!fs15.existsSync(browserstackFolderPath)) {
|
|
12632
|
+
fs15.mkdirSync(browserstackFolderPath);
|
|
12315
12633
|
}
|
|
12316
|
-
const filePath =
|
|
12317
|
-
if (!
|
|
12318
|
-
|
|
12634
|
+
const filePath = path21.join(browserstackFolderPath, ".build-name-cache.json");
|
|
12635
|
+
if (!fs15.existsSync(filePath)) {
|
|
12636
|
+
fs15.appendFileSync(filePath, JSON.stringify({}));
|
|
12319
12637
|
}
|
|
12320
|
-
const buildCacheFileData =
|
|
12638
|
+
const buildCacheFileData = fs15.readFileSync(filePath);
|
|
12321
12639
|
const parsedBuildCacheFileData = JSON.parse(buildCacheFileData.toString());
|
|
12322
12640
|
if (this._buildName && this._buildName in parsedBuildCacheFileData) {
|
|
12323
12641
|
const prevIdentifier = parseInt(parsedBuildCacheFileData[this._buildName].identifier);
|
|
@@ -12336,16 +12654,16 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
|
|
|
12336
12654
|
if (!buildName || !filePath) {
|
|
12337
12655
|
return;
|
|
12338
12656
|
}
|
|
12339
|
-
const jsonContent = JSON.parse(
|
|
12657
|
+
const jsonContent = JSON.parse(fs15.readFileSync(filePath).toString());
|
|
12340
12658
|
jsonContent[buildName] = { "identifier": buildIdentifier };
|
|
12341
|
-
|
|
12659
|
+
fs15.writeFileSync(filePath, JSON.stringify(jsonContent));
|
|
12342
12660
|
}
|
|
12343
12661
|
_getClientBuildUuid() {
|
|
12344
12662
|
if (process.env[BROWSERSTACK_TESTHUB_UUID]) {
|
|
12345
12663
|
return process.env[BROWSERSTACK_TESTHUB_UUID];
|
|
12346
12664
|
}
|
|
12347
12665
|
const uuid = this.browserStackConfig?.sdkRunID;
|
|
12348
|
-
|
|
12666
|
+
BStackLogger.logToFile(`If facing any issues, please contact BrowserStack support with the Build Run Id - ${uuid}`, "info");
|
|
12349
12667
|
return uuid;
|
|
12350
12668
|
}
|
|
12351
12669
|
};
|
|
@@ -12367,6 +12685,7 @@ init_util();
|
|
|
12367
12685
|
init_insights_handler();
|
|
12368
12686
|
init_reporter();
|
|
12369
12687
|
init_constants();
|
|
12688
|
+
init_caCert();
|
|
12370
12689
|
init_crash_reporter();
|
|
12371
12690
|
|
|
12372
12691
|
// src/accessibility-handler.ts
|
|
@@ -12490,7 +12809,7 @@ var _AccessibilityHandler = class {
|
|
|
12490
12809
|
};
|
|
12491
12810
|
browserWithA11y.startA11yScanning = async () => {
|
|
12492
12811
|
if (this._testIdentifier === null) {
|
|
12493
|
-
|
|
12812
|
+
BStackLogger.warn("Accessibility scanning cannot be started from outside the test");
|
|
12494
12813
|
return;
|
|
12495
12814
|
}
|
|
12496
12815
|
AccessibilityHandler._a11yScanSessionMap[sessionId] = true;
|
|
@@ -12502,7 +12821,7 @@ var _AccessibilityHandler = class {
|
|
|
12502
12821
|
};
|
|
12503
12822
|
browserWithA11y.stopA11yScanning = async () => {
|
|
12504
12823
|
if (this._testIdentifier === null) {
|
|
12505
|
-
|
|
12824
|
+
BStackLogger.warn("Accessibility scanning cannot be stopped from outside the test");
|
|
12506
12825
|
return;
|
|
12507
12826
|
}
|
|
12508
12827
|
AccessibilityHandler._a11yScanSessionMap[sessionId] = false;
|
|
@@ -12521,7 +12840,7 @@ var _AccessibilityHandler = class {
|
|
|
12521
12840
|
const prevImpl = orig ? orig.bind(browser) : void 0;
|
|
12522
12841
|
browser.overwriteCommand(command.name, this.commandWrapper.bind(this, command, prevImpl), command.class === "Element");
|
|
12523
12842
|
} catch (error) {
|
|
12524
|
-
|
|
12843
|
+
BStackLogger.debug(`Exception in overwrite command ${command.name} - ${error}`);
|
|
12525
12844
|
}
|
|
12526
12845
|
});
|
|
12527
12846
|
PerformanceTester.end(CONFIG_EVENTS.ACCESSIBILITY);
|
|
@@ -12545,14 +12864,14 @@ var _AccessibilityHandler = class {
|
|
|
12545
12864
|
};
|
|
12546
12865
|
this._testMetadata[testIdentifier].accessibilityScanStarted = shouldScanTest;
|
|
12547
12866
|
if (shouldScanTest) {
|
|
12548
|
-
|
|
12867
|
+
BStackLogger.info("Automate test case execution has started.");
|
|
12549
12868
|
}
|
|
12550
12869
|
} catch (error) {
|
|
12551
|
-
|
|
12870
|
+
BStackLogger.error(`Exception in starting accessibility automation scan for this test case ${error}`);
|
|
12552
12871
|
}
|
|
12553
12872
|
}
|
|
12554
12873
|
async afterTest(suiteTitle, test) {
|
|
12555
|
-
|
|
12874
|
+
BStackLogger.debug("Accessibility after test hook. Before sending test stop event");
|
|
12556
12875
|
if (this._framework !== "mocha" || !this.shouldRunTestHooks(this._browser, this._accessibility)) {
|
|
12557
12876
|
return;
|
|
12558
12877
|
}
|
|
@@ -12564,17 +12883,17 @@ var _AccessibilityHandler = class {
|
|
|
12564
12883
|
return;
|
|
12565
12884
|
}
|
|
12566
12885
|
if (shouldScanTestForAccessibility2) {
|
|
12567
|
-
|
|
12886
|
+
BStackLogger.info("Automate test case execution has ended. Processing for accessibility testing is underway. ");
|
|
12568
12887
|
const dataForExtension = {
|
|
12569
12888
|
"thTestRunUuid": process.env.TEST_ANALYTICS_ID,
|
|
12570
12889
|
"thBuildUuid": process.env.BROWSERSTACK_TESTHUB_UUID,
|
|
12571
12890
|
"thJwtToken": process.env.BROWSERSTACK_TESTHUB_JWT
|
|
12572
12891
|
};
|
|
12573
12892
|
await this.sendTestStopEvent(this._browser, dataForExtension);
|
|
12574
|
-
|
|
12893
|
+
BStackLogger.info("Accessibility testing for this test case has ended.");
|
|
12575
12894
|
}
|
|
12576
12895
|
} catch (error) {
|
|
12577
|
-
|
|
12896
|
+
BStackLogger.error(`Accessibility results could not be processed for the test case ${test.title}. Error : ${error}`);
|
|
12578
12897
|
}
|
|
12579
12898
|
}
|
|
12580
12899
|
/**
|
|
@@ -12602,14 +12921,14 @@ var _AccessibilityHandler = class {
|
|
|
12602
12921
|
}
|
|
12603
12922
|
listener_default.setTestRunAccessibilityVar(this._accessibility && shouldScanScenario);
|
|
12604
12923
|
if (shouldScanScenario) {
|
|
12605
|
-
|
|
12924
|
+
BStackLogger.info("Automate test case execution has started.");
|
|
12606
12925
|
}
|
|
12607
12926
|
} catch (error) {
|
|
12608
|
-
|
|
12927
|
+
BStackLogger.error(`Exception in starting accessibility automation scan for this test case ${error}`);
|
|
12609
12928
|
}
|
|
12610
12929
|
}
|
|
12611
12930
|
async afterScenario(world) {
|
|
12612
|
-
|
|
12931
|
+
BStackLogger.debug("Accessibility after scenario hook. Before sending test stop event");
|
|
12613
12932
|
if (!this.shouldRunTestHooks(this._browser, this._accessibility)) {
|
|
12614
12933
|
return;
|
|
12615
12934
|
}
|
|
@@ -12622,17 +12941,17 @@ var _AccessibilityHandler = class {
|
|
|
12622
12941
|
return;
|
|
12623
12942
|
}
|
|
12624
12943
|
if (shouldScanTestForAccessibility2) {
|
|
12625
|
-
|
|
12944
|
+
BStackLogger.info("Automate test case execution has ended. Processing for accessibility testing is underway. ");
|
|
12626
12945
|
const dataForExtension = {
|
|
12627
12946
|
"thTestRunUuid": process.env.TEST_ANALYTICS_ID,
|
|
12628
12947
|
"thBuildUuid": process.env.BROWSERSTACK_TESTHUB_UUID,
|
|
12629
12948
|
"thJwtToken": process.env.BROWSERSTACK_TESTHUB_JWT
|
|
12630
12949
|
};
|
|
12631
12950
|
await this.sendTestStopEvent(this._browser, dataForExtension);
|
|
12632
|
-
|
|
12951
|
+
BStackLogger.info("Accessibility testing for this test case has ended.");
|
|
12633
12952
|
}
|
|
12634
12953
|
} catch (error) {
|
|
12635
|
-
|
|
12954
|
+
BStackLogger.error(`Accessibility results could not be processed for the test case ${pickleData.name}. Error : ${error}`);
|
|
12636
12955
|
}
|
|
12637
12956
|
}
|
|
12638
12957
|
/*
|
|
@@ -12640,14 +12959,14 @@ var _AccessibilityHandler = class {
|
|
|
12640
12959
|
*/
|
|
12641
12960
|
async commandWrapper(command, prevImpl, origFunction, ...args) {
|
|
12642
12961
|
if (this._sessionId && AccessibilityHandler._a11yScanSessionMap[this._sessionId] && (!command.name.includes("execute") || !AccessibilityHandler.shouldPatchExecuteScript(args.length ? args[0] : null))) {
|
|
12643
|
-
|
|
12962
|
+
BStackLogger.debug(`Performing scan for ${command.class} ${command.name}`);
|
|
12644
12963
|
await performA11yScan(this.isAppAutomate, this._browser, true, true, command.name);
|
|
12645
12964
|
}
|
|
12646
12965
|
const impl = prevImpl || origFunction;
|
|
12647
12966
|
return impl(...args);
|
|
12648
12967
|
}
|
|
12649
12968
|
async sendTestStopEvent(browser, dataForExtension) {
|
|
12650
|
-
|
|
12969
|
+
BStackLogger.debug("Performing scan before saving results");
|
|
12651
12970
|
if (AccessibilityHandler._a11yScanSessionMap[this._sessionId]) {
|
|
12652
12971
|
await PerformanceTester.measureWrapper(A11Y_EVENTS.PERFORM_SCAN, async () => {
|
|
12653
12972
|
await performA11yScan(this.isAppAutomate, browser, true, true);
|
|
@@ -12659,9 +12978,9 @@ var _AccessibilityHandler = class {
|
|
|
12659
12978
|
await PerformanceTester.measureWrapper(A11Y_EVENTS.SAVE_RESULTS, async () => {
|
|
12660
12979
|
if (accessibility_scripts_default.saveTestResults) {
|
|
12661
12980
|
const results = await executeAccessibilityScript(browser, accessibility_scripts_default.saveTestResults, dataForExtension);
|
|
12662
|
-
|
|
12981
|
+
BStackLogger.debug(util11.format(results));
|
|
12663
12982
|
} else {
|
|
12664
|
-
|
|
12983
|
+
BStackLogger.error("saveTestResults script is null or undefined");
|
|
12665
12984
|
}
|
|
12666
12985
|
})();
|
|
12667
12986
|
}
|
|
@@ -12738,6 +13057,7 @@ var BrowserstackService = class {
|
|
|
12738
13057
|
this._caps = _caps;
|
|
12739
13058
|
this._config = _config;
|
|
12740
13059
|
this._options = { ...DEFAULT_OPTIONS, ...options };
|
|
13060
|
+
configureCaCertificate(this._options);
|
|
12741
13061
|
if (!this._config) {
|
|
12742
13062
|
this._config = this._options;
|
|
12743
13063
|
}
|
|
@@ -12830,20 +13150,20 @@ var BrowserstackService = class {
|
|
|
12830
13150
|
NOT_ALLOWED_KEYS_IN_CAPS.forEach((key) => delete capabilities[`browserstack.${key}`]);
|
|
12831
13151
|
}
|
|
12832
13152
|
} catch (err) {
|
|
12833
|
-
|
|
13153
|
+
BStackLogger.error(`Error while tracking automation framework event: ${err}`);
|
|
12834
13154
|
}
|
|
12835
13155
|
} catch (err) {
|
|
12836
|
-
|
|
13156
|
+
BStackLogger.error(`Error while connecting to Browserstack CLI: ${err}`);
|
|
12837
13157
|
PerformanceTester.end(DRIVER_EVENT.INIT, false, util12.format(err));
|
|
12838
13158
|
throw err;
|
|
12839
13159
|
}
|
|
12840
13160
|
PerformanceTester.end(DRIVER_EVENT.INIT);
|
|
12841
13161
|
PerformanceTester.start(EVENTS.SDK_DEVICE_ALLOCATION);
|
|
12842
|
-
|
|
13162
|
+
BStackLogger.debug("Device allocation tracking started - waiting for WebDriverIO to create remote session");
|
|
12843
13163
|
}
|
|
12844
13164
|
async before(caps, specs, browser) {
|
|
12845
13165
|
PerformanceTester.end(EVENTS.SDK_DEVICE_ALLOCATION, true, "Device allocated and session created");
|
|
12846
|
-
|
|
13166
|
+
BStackLogger.debug("Device allocation tracking ended - remote session created successfully");
|
|
12847
13167
|
PerformanceTester.start(DRIVER_EVENT.PRE_INITIALIZE);
|
|
12848
13168
|
this._browser = browser ? browser : globalThis.browser;
|
|
12849
13169
|
PerformanceTester.browser = this._browser;
|
|
@@ -12852,7 +13172,7 @@ var BrowserstackService = class {
|
|
|
12852
13172
|
await ai_handler_default.selfHeal(this._options, caps, this._browser);
|
|
12853
13173
|
} catch (err) {
|
|
12854
13174
|
if (this._options.selfHeal === true) {
|
|
12855
|
-
|
|
13175
|
+
BStackLogger.warn(`Error while setting up self-healing: ${err}. Disabling healing for this session.`);
|
|
12856
13176
|
}
|
|
12857
13177
|
}
|
|
12858
13178
|
}
|
|
@@ -12882,13 +13202,13 @@ var BrowserstackService = class {
|
|
|
12882
13202
|
this._options.accessibilityOptions
|
|
12883
13203
|
);
|
|
12884
13204
|
if (isBrowserstackSession(this._browser) && BrowserstackCLI.getInstance().isRunning()) {
|
|
12885
|
-
|
|
13205
|
+
BStackLogger.info(`CLI is running, tracking accessibility event for before: ${sessionId}`);
|
|
12886
13206
|
} else {
|
|
12887
13207
|
await this._accessibilityHandler.before(sessionId);
|
|
12888
13208
|
}
|
|
12889
13209
|
listener_default.setAccessibilityOptions(this._options.accessibilityOptions);
|
|
12890
13210
|
} catch (err) {
|
|
12891
|
-
|
|
13211
|
+
BStackLogger.error(`[Accessibility Test Run] Error in service class before function: ${err}`);
|
|
12892
13212
|
}
|
|
12893
13213
|
if (shouldProcessEventForTesthub("")) {
|
|
12894
13214
|
patchConsoleLogs();
|
|
@@ -12899,7 +13219,7 @@ var BrowserstackService = class {
|
|
|
12899
13219
|
this._options
|
|
12900
13220
|
);
|
|
12901
13221
|
if (BrowserstackCLI.getInstance().isRunning()) {
|
|
12902
|
-
|
|
13222
|
+
BStackLogger.info(`CLI is running, tracking insights event for before: ${sessionId}`);
|
|
12903
13223
|
await BrowserstackCLI.getInstance().getAutomationFramework().trackEvent(AutomationFrameworkState.CREATE, HookState.POST, { browser: this._browser, hubUrl: this._config.hostname });
|
|
12904
13224
|
this._insightsHandler.setGitConfigPath();
|
|
12905
13225
|
PerformanceTester.end(DRIVER_EVENT.PRE_INITIALIZE);
|
|
@@ -12934,7 +13254,7 @@ var BrowserstackService = class {
|
|
|
12934
13254
|
});
|
|
12935
13255
|
}
|
|
12936
13256
|
} catch (err) {
|
|
12937
|
-
|
|
13257
|
+
BStackLogger.error(`Error in service class before function: ${err}`);
|
|
12938
13258
|
if (shouldProcessEventForTesthub("")) {
|
|
12939
13259
|
CrashReporter.uploadCrashReport(`Error in service class before function: ${err}`, err ? err.stack : "unknown error");
|
|
12940
13260
|
}
|
|
@@ -13118,7 +13438,7 @@ var BrowserstackService = class {
|
|
|
13118
13438
|
return;
|
|
13119
13439
|
}
|
|
13120
13440
|
} catch (error) {
|
|
13121
|
-
|
|
13441
|
+
BStackLogger.error(`Error in after hook: ${error}`);
|
|
13122
13442
|
PerformanceTester.end(DRIVER_EVENT.QUIT, false, util12.format(error));
|
|
13123
13443
|
PerformanceTester.end(HOOK_EVENTS.AFTER, false, util12.format(error));
|
|
13124
13444
|
await PerformanceTester.stopAndGenerate("performance-service.html");
|
|
@@ -13189,14 +13509,14 @@ var BrowserstackService = class {
|
|
|
13189
13509
|
failureReason = hasReasons ? this._failReasons.join("\n") : void 0;
|
|
13190
13510
|
}
|
|
13191
13511
|
if (!this._browser.isMultiremote) {
|
|
13192
|
-
|
|
13512
|
+
BStackLogger.info(`Update (reloaded) job with sessionId ${oldSessionId}, ${sessionStatus}`);
|
|
13193
13513
|
} else {
|
|
13194
13514
|
const browserName = this._browser.instances.filter(
|
|
13195
13515
|
(browserName2) => this._browser && this._browser.getInstance(browserName2).sessionId === newSessionId
|
|
13196
13516
|
)[0];
|
|
13197
|
-
|
|
13517
|
+
BStackLogger.info(`Update (reloaded) multiremote job for browser "${browserName}" and sessionId ${oldSessionId}, ${sessionStatus}`);
|
|
13198
13518
|
}
|
|
13199
|
-
|
|
13519
|
+
BStackLogger.warn(`Session Reloaded: Old Session Id: ${oldSessionId}, New Session Id: ${newSessionId}`);
|
|
13200
13520
|
await this._insightsHandler?.sendCBTInfo();
|
|
13201
13521
|
if (setSessionStatus) {
|
|
13202
13522
|
await this._update(oldSessionId, {
|
|
@@ -13222,7 +13542,7 @@ var BrowserstackService = class {
|
|
|
13222
13542
|
}
|
|
13223
13543
|
_updateJob(requestBody) {
|
|
13224
13544
|
return this._multiRemoteAction((sessionId, browserName) => {
|
|
13225
|
-
|
|
13545
|
+
BStackLogger.info(
|
|
13226
13546
|
browserName ? `Update multiremote job for browser "${browserName}" and sessionId ${sessionId}` : `Update job with sessionId ${sessionId}`
|
|
13227
13547
|
);
|
|
13228
13548
|
return this._update(sessionId, requestBody);
|
|
@@ -13248,7 +13568,7 @@ var BrowserstackService = class {
|
|
|
13248
13568
|
return Promise.resolve();
|
|
13249
13569
|
}
|
|
13250
13570
|
const sessionUrl = `${this._sessionBaseUrl}/${sessionId}.json`;
|
|
13251
|
-
|
|
13571
|
+
BStackLogger.debug(`Updating Browserstack session at ${sessionUrl} with request body: `, requestBody);
|
|
13252
13572
|
const encodedAuth = Buffer.from(`${this._config.user}:${this._config.key}`, "utf8").toString("base64");
|
|
13253
13573
|
const headers = {
|
|
13254
13574
|
"Content-Type": "application/json; charset=utf-8",
|
|
@@ -13273,7 +13593,7 @@ var BrowserstackService = class {
|
|
|
13273
13593
|
}
|
|
13274
13594
|
await this._multiRemoteAction(async (sessionId, browserName) => {
|
|
13275
13595
|
const sessionUrl = `${this._sessionBaseUrl}/${sessionId}.json`;
|
|
13276
|
-
|
|
13596
|
+
BStackLogger.debug(`Requesting Browserstack session URL at ${sessionUrl}`);
|
|
13277
13597
|
let browserUrl;
|
|
13278
13598
|
const encodedAuth = Buffer.from(`${this._config.user}:${this._config.key}`, "utf8").toString("base64");
|
|
13279
13599
|
const headers = {
|
|
@@ -13300,7 +13620,7 @@ var BrowserstackService = class {
|
|
|
13300
13620
|
}
|
|
13301
13621
|
const capabilities = getBrowserCapabilities(this._browser, this._caps, browserName);
|
|
13302
13622
|
const browserString = getBrowserDescription(capabilities);
|
|
13303
|
-
|
|
13623
|
+
BStackLogger.info(`${browserString} session: ${browserUrl}`);
|
|
13304
13624
|
});
|
|
13305
13625
|
}
|
|
13306
13626
|
async _setSessionName(suiteTitle, test) {
|