From c403299a792ba118470764ef21e89627e9fbf54f Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Mon, 4 Aug 2025 16:36:18 +0530 Subject: [PATCH 1/4] O11y Artifact changes --- packages/wdio-browserstack-service/README.md | 81 ++++++++++++-- .../src/accessibility-handler.ts | 6 +- .../wdio-browserstack-service/src/cleanup.ts | 11 +- .../src/constants.ts | 23 +++- .../src/insights-handler.ts | 2 +- .../wdio-browserstack-service/src/launcher.ts | 22 ++-- .../src/request-handler.ts | 2 +- .../wdio-browserstack-service/src/service.ts | 19 +++- .../src/testHub/utils.ts | 7 +- .../wdio-browserstack-service/src/types.ts | 29 ++++- .../wdio-browserstack-service/src/util.ts | 102 +++++++++++++++--- .../tests/service.test.ts | 6 +- 12 files changed, 261 insertions(+), 49 deletions(-) diff --git a/packages/wdio-browserstack-service/README.md b/packages/wdio-browserstack-service/README.md index 98129752a70..1afe4b6ee3b 100644 --- a/packages/wdio-browserstack-service/README.md +++ b/packages/wdio-browserstack-service/README.md @@ -28,8 +28,8 @@ export const config = { key: process.env.BROWSERSTACK_ACCESS_KEY, services: [ ['browserstack', { - testObservability: true, - testObservabilityOptions: { + testReporting: true, + testReportingOptions: { projectName: "Your project name goes here", buildName: "The static build job name goes here e.g. Nightly regression" }, @@ -44,13 +44,80 @@ export const config = { In order to authorize to the BrowserStack service your config needs to contain a [`user`](https://webdriver.io/docs/options#user) and [`key`](https://webdriver.io/docs/options#key) option. -### testObservability +### testReporting (formerly testObservability) + +Test Reporting and Analytics is an advanced test reporting tool that gives insights to improve your automation tests and helps you debug faster. It's enabled by default by setting the testReporting flag as true for all users of browserstack-service. You can disable this by setting the testReporting flag to false. + +Once your tests finish running, you can visit [Test Reporting and Analytics](https://automation.browserstack.com/?utm_source=webdriverio&utm_medium=partnered&utm_campaign=documentation) to debug your builds with additional insights like Unique Error Analysis, Automatic Flaky Test Detection, and more. + +You can use Test Reporting and Analytics even if you don't run your tests on the BrowserStack infrastructure. Even if you run your tests on a CI, a local machine, or even on other cloud service providers, Test Reporting and Analytics can still generate intelligent test reports and advanced analytics on your tests. + +If you want to use Test Reporting and Analytics without running your tests on BrowserStack infrastructure, you can set your config as follows: + +```js +// wdio.conf.js +export const config = { + // ... + services: [ + ['browserstack', { + testReporting: true, + testReportingOptions: { + user: process.env.BROWSERSTACK_USERNAME, + key: process.env.BROWSERSTACK_ACCESS_KEY, + projectName: "Your project name goes here", + buildName: "The static build job name goes here e.g. Nightly regression" + } + }] + ], + // ... +}; +``` + +For backward compatibility, the legacy `testObservability` and `testObservabilityOptions` flags are still supported: + +```js +// wdio.conf.js (legacy configuration) +export const config = { + // ... + services: [ + ['browserstack', { + testObservability: true, // deprecated, use testReporting instead + testObservabilityOptions: { // deprecated, use testReportingOptions instead + user: process.env.BROWSERSTACK_USERNAME, + key: process.env.BROWSERSTACK_ACCESS_KEY, + projectName: "Your project name goes here", + buildName: "The static build job name goes here e.g. Nightly regression" + } + }] + ], + // ... +}; +``` + +#### Environment Variables + +The following environment variables are supported: + +**New (recommended):** +- `BROWSERSTACK_TEST_REPORTING` - Enable/disable test reporting +- `BROWSERSTACK_TEST_REPORTING_DEBUG` - Enable debug mode for test reporting +- `TEST_REPORTING_BUILD_TAG` - Comma-separated build tags + +**Legacy (still supported):** +- `BROWSERSTACK_OBSERVABILITY` - Enable/disable test observability (deprecated) +- `TEST_OBSERVABILITY_BUILD_TAG` - Comma-separated build tags (deprecated) + +You can explore all the features of Test Reporting and Analytics in [this sandbox](https://automation-demo.browserstack.com/?utm_source=webdriverio&utm_medium=partnered&utm_campaign=documentation) or read more about it [here](https://www.browserstack.com/docs/test-reporting/overview/what-is-test-reporting?utm_source=webdriverio&utm_medium=partnered&utm_campaign=documentation). + +### testObservability (deprecated) + +**⚠️ DEPRECATED:** Use `testReporting` instead. This option is maintained for backward compatibility. -Test Observability is an advanced test reporting tool that gives insights to improve your automation tests and helps you debug faster. It’s enabled by default by setting the testObservability​ flag as true for all users of browserstack-service. You can disable this by setting the testObservability​ flag to false. +Test Observability is an advanced test reporting tool that gives insights to improve your automation tests and helps you debug faster. It's enabled by default by setting the testObservability​ flag as true for all users of browserstack-service. You can disable this by setting the testObservability​ flag to false. -Once your tests finish running, you can visit [Test Observability](https://observability.browserstack.com/?utm_source=webdriverio&utm_medium=partnered&utm_campaign=documentation) to debug your builds with additional insights like Unique Error Analysis, Automatic Flaky Test Detection, and more. +Once your tests finish running, you can visit [Test Reporting and Analytics](https://automation.browserstack.com/?utm_source=webdriverio&utm_medium=partnered&utm_campaign=documentation) to debug your builds with additional insights like Unique Error Analysis, Automatic Flaky Test Detection, and more. -You can use Test Observability even if you don’t run your tests on the BrowserStack infrastructure. Even if you run your tests on a CI, a local machine, or even on other cloud service providers, Test Observability can still generate intelligent test reports and advanced analytics on your tests. +You can use Test Observability even if you don't run your tests on the BrowserStack infrastructure. Even if you run your tests on a CI, a local machine, or even on other cloud service providers, Test Observability can still generate intelligent test reports and advanced analytics on your tests. If you want to use Test Observability without running your tests on BrowserStack infrastructure, you can set your config as follows: @@ -74,7 +141,7 @@ export const config = { }; ``` -You can explore all the features of Test Observability in [this sandbox](https://observability-demo.browserstack.com/?utm_source=webdriverio&utm_medium=partnered&utm_campaign=documentation) or read more about it [here](https://www.browserstack.com/docs/test-observability/overview/what-is-test-observability?utm_source=webdriverio&utm_medium=partnered&utm_campaign=documentation). +You can explore all the features of Test Reporting and Analytics in [this sandbox](https://automation-demo.browserstack.com/?utm_source=webdriverio&utm_medium=partnered&utm_campaign=documentation) or read more about it [here](https://www.browserstack.com/docs/test-reporting/overview/what-is-test-reporting?utm_source=webdriverio&utm_medium=partnered&utm_campaign=documentation). ### browserstackLocal Set this to true to enable routing connections from BrowserStack cloud through your computer. diff --git a/packages/wdio-browserstack-service/src/accessibility-handler.ts b/packages/wdio-browserstack-service/src/accessibility-handler.ts index 01c7f981ce5..62e5f4dd159 100644 --- a/packages/wdio-browserstack-service/src/accessibility-handler.ts +++ b/packages/wdio-browserstack-service/src/accessibility-handler.ts @@ -25,7 +25,8 @@ import { validateCapsWithNonBstackA11y, isTrue, validateCapsWithAppA11y, - getAppA11yResults + getAppA11yResults, + getTestReportingConfig } from './util.js' import accessibilityScripts from './scripts/accessibility-scripts.js' import PerformanceTester from './instrumentation/performance/performance-tester.js' @@ -115,7 +116,8 @@ class _AccessibilityHandler { this._accessibility = isTrue(this._getCapabilityValue(this._caps, 'accessibility', 'browserstack.accessibility')) //checks for running ALLY on non-bstack infra - if (isAccessibilityAutomationSession(this._accessibility) && (this._turboscale || !shouldAddServiceVersion(this._config, this._options.testObservability))){ + const reportingConfig = getTestReportingConfig(this._options) + if (isAccessibilityAutomationSession(this._accessibility) && (this._turboscale || !shouldAddServiceVersion(this._config, reportingConfig.enabled))){ if (validateCapsWithNonBstackA11y(this._platformA11yMeta.browser_name as string, this._platformA11yMeta?.browser_version as string)){ this._accessibility = true } diff --git a/packages/wdio-browserstack-service/src/cleanup.ts b/packages/wdio-browserstack-service/src/cleanup.ts index d4590f71327..5f43e920035 100644 --- a/packages/wdio-browserstack-service/src/cleanup.ts +++ b/packages/wdio-browserstack-service/src/cleanup.ts @@ -3,7 +3,7 @@ import { BStackLogger } from './bstackLogger.js' import fs from 'node:fs' import util from 'node:util' import { fireFunnelRequest } from './instrumentation/funnelInstrumentation.js' -import { BROWSERSTACK_TESTHUB_UUID, BROWSERSTACK_TESTHUB_JWT, BROWSERSTACK_OBSERVABILITY } from './constants.js' +import { BROWSERSTACK_TESTHUB_UUID, BROWSERSTACK_TESTHUB_JWT, BROWSERSTACK_OBSERVABILITY, BROWSERSTACK_TEST_REPORTING } from './constants.js' import PerformanceTester from './instrumentation/performance/performance-tester.js' export default class BStackCleanup { @@ -42,18 +42,19 @@ export default class BStackCleanup { if (!process.env[BROWSERSTACK_TESTHUB_JWT]) { return } - BStackLogger.debug('Executing observability cleanup') + BStackLogger.debug('Executing Test Reporting and Analytics cleanup') try { const killSignal = funnelData?.event_properties?.finishedMetadata?.signal const result = await stopBuildUpstream(killSignal) - if (process.env[BROWSERSTACK_OBSERVABILITY] && process.env[BROWSERSTACK_TESTHUB_UUID]) { - BStackLogger.info(`\nVisit https://observability.browserstack.com/builds/${process.env[BROWSERSTACK_TESTHUB_UUID]} to view build report, insights, and many more debugging information all at one place!\n`) + // Update to use new URL and support both environment variables + if ((process.env[BROWSERSTACK_OBSERVABILITY] || process.env[BROWSERSTACK_TEST_REPORTING]) && process.env[BROWSERSTACK_TESTHUB_UUID]) { + BStackLogger.info(`\nVisit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TESTHUB_UUID]} to view build report, insights, and many more debugging information all at one place!\n`) } const status = (result && result.status) || 'failed' const message = (result && result.message) this.updateO11yStopData(funnelData, status, status === 'failed' ? message : undefined) } catch (e: unknown) { - BStackLogger.error('Error in stopping Observability build: ' + e) + BStackLogger.error('Error in stopping Test Reporting and Analytics build: ' + e) this.updateO11yStopData(funnelData, 'failed', e) } } diff --git a/packages/wdio-browserstack-service/src/constants.ts b/packages/wdio-browserstack-service/src/constants.ts index 30941e9ca7a..7e7e7879c66 100644 --- a/packages/wdio-browserstack-service/src/constants.ts +++ b/packages/wdio-browserstack-service/src/constants.ts @@ -24,6 +24,7 @@ export const DEFAULT_OPTIONS: Partial = { setSessionName: true, setSessionStatus: true, testObservability: true, + testReporting: true, accessibility: false } @@ -120,9 +121,29 @@ export const BSTACK_A11Y_POLLING_TIMEOUT = 'BSTACK_A11Y_POLLING_TIMEOUT' // Whether session is a accessibility session export const BROWSERSTACK_ACCESSIBILITY = 'BROWSERSTACK_ACCESSIBILITY' -// Whether session is a observability session +// Whether session is a test reporting session (new name) +export const BROWSERSTACK_TEST_REPORTING = 'BROWSERSTACK_TEST_REPORTING' + +// Debug flag for test reporting +export const BROWSERSTACK_TEST_REPORTING_DEBUG = 'BROWSERSTACK_TEST_REPORTING_DEBUG' + +// Build tag environment variable for test reporting +export const TEST_REPORTING_BUILD_TAG = 'TEST_REPORTING_BUILD_TAG' + +// Build name environment variable for test reporting +export const TEST_REPORTING_BUILD_NAME = 'TEST_REPORTING_BUILD_NAME' + +// Project name environment variable for test reporting +export const TEST_REPORTING_PROJECT_NAME = 'TEST_REPORTING_PROJECT_NAME' + +// Whether session is a observability session (legacy name) export const BROWSERSTACK_OBSERVABILITY = 'BROWSERSTACK_OBSERVABILITY' +// Legacy environment variables for backward compatibility +export const TEST_OBSERVABILITY_BUILD_TAG = 'TEST_OBSERVABILITY_BUILD_TAG' +export const TEST_OBSERVABILITY_BUILD_NAME = 'TEST_OBSERVABILITY_BUILD_NAME' +export const TEST_OBSERVABILITY_PROJECT_NAME = 'TEST_OBSERVABILITY_PROJECT_NAME' + // Maximum size of VCS info which is allowed export const MAX_GIT_META_DATA_SIZE_IN_BYTES = 64 * 1024 diff --git a/packages/wdio-browserstack-service/src/insights-handler.ts b/packages/wdio-browserstack-service/src/insights-handler.ts index 1c8559d9617..a7d604fcc52 100644 --- a/packages/wdio-browserstack-service/src/insights-handler.ts +++ b/packages/wdio-browserstack-service/src/insights-handler.ts @@ -510,7 +510,7 @@ class _InsightsHandler { this.listener.logCreated([stdLog]) } } catch (error) { - BStackLogger.debug(`Exception in uploading log data to Observability with error : ${error}`) + BStackLogger.debug(`Exception in uploading log data to Test Reporting and Analytics with error : ${error}`) } } diff --git a/packages/wdio-browserstack-service/src/launcher.ts b/packages/wdio-browserstack-service/src/launcher.ts index 1f9939b9ac7..cbe58c5e52e 100644 --- a/packages/wdio-browserstack-service/src/launcher.ts +++ b/packages/wdio-browserstack-service/src/launcher.ts @@ -22,7 +22,8 @@ import { BROWSERSTACK_TESTHUB_UUID, VALID_APP_EXTENSION, BROWSERSTACK_PERCY, - BROWSERSTACK_OBSERVABILITY + BROWSERSTACK_OBSERVABILITY, + BROWSERSTACK_TEST_REPORTING } from './constants.js' import { launchTestSession, @@ -40,7 +41,8 @@ import { isValidCapsForHealing, getBooleanValueFromString, validateCapsWithNonBstackA11y, - mergeChromeOptions + mergeChromeOptions, + getTestReportingConfig } from './util.js' import { getProductMap } from './testHub/utils.js' import CrashReporter from './crash-reporter.js' @@ -173,7 +175,10 @@ export default class BrowserstackLauncherService implements Services.ServiceInst // by default observability will be true unless specified as false this._options.testObservability = this._options.testObservability !== false - if (this._options.testObservability + // Get resolved reporting config + const reportingConfig = getTestReportingConfig(this._options) + + if (reportingConfig.enabled && // update files to run if it's a rerun process.env[RERUN_ENV] && process.env[RERUN_TESTS_ENV] @@ -283,7 +288,10 @@ export default class BrowserstackLauncherService implements Services.ServiceInst const shouldSetupPercy = this._options.percy || (isUndefined(this._options.percy) && this._options.app) let buildStartResponse = null - if (this._options.testObservability || this._accessibilityAutomation || shouldSetupPercy) { + const reportingConfig = getTestReportingConfig(this._options) + const shouldLaunchTestSession = this._accessibilityAutomation || reportingConfig.enabled || shouldSetupPercy + + if (shouldLaunchTestSession) { BStackLogger.debug('Sending launch start event') buildStartResponse = await launchTestSession(this._options, this._config, { @@ -403,8 +411,10 @@ export default class BrowserstackLauncherService implements Services.ServiceInst BStackLogger.debug('Sending stop launch event') await stopBuildUpstream() - if (process.env[BROWSERSTACK_OBSERVABILITY] && process.env[BROWSERSTACK_TESTHUB_UUID]) { - console.log(`\nVisit https://observability.browserstack.com/builds/${process.env[BROWSERSTACK_TESTHUB_UUID]} to view build report, insights, and many more debugging information all at one place!\n`) + + // Update to use new URL and terminology - check both old and new env vars + if ((process.env[BROWSERSTACK_OBSERVABILITY] || process.env[BROWSERSTACK_TEST_REPORTING]) && process.env[BROWSERSTACK_TESTHUB_UUID]) { + console.log(`\nVisit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TESTHUB_UUID]} to view build report, insights, and many more debugging information all at one place!\n`) } this.browserStackConfig.testObservability.buildStopped = true diff --git a/packages/wdio-browserstack-service/src/request-handler.ts b/packages/wdio-browserstack-service/src/request-handler.ts index d25e9a7100b..12f581a9ffe 100644 --- a/packages/wdio-browserstack-service/src/request-handler.ts +++ b/packages/wdio-browserstack-service/src/request-handler.ts @@ -25,7 +25,7 @@ export default class RequestQueueHandler { add (event: UploadType) { if (!process.env[TESTOPS_BUILD_COMPLETED_ENV]) { - throw new Error('Observability build start not completed yet.') + throw new Error('Test Reporting and Analytics build start not completed yet.') } this.queue.push(event) diff --git a/packages/wdio-browserstack-service/src/service.ts b/packages/wdio-browserstack-service/src/service.ts index 3d061e71484..cee83a22064 100644 --- a/packages/wdio-browserstack-service/src/service.ts +++ b/packages/wdio-browserstack-service/src/service.ts @@ -10,7 +10,9 @@ import { isBrowserstackSession, patchConsoleLogs, shouldAddServiceVersion, - isTrue + isTrue, + getTestReportingConfig, + setupEnvironmentVariables } from './util.js' import type { BrowserstackConfig, BrowserstackOptions, MultiRemoteAction, SessionResponse, TurboScaleSessionResponse } from './types.js' import type { Pickle, Feature, ITestCaseHookParameter, CucumberHook } from './cucumber-types.js' @@ -58,7 +60,14 @@ export default class BrowserstackService implements Services.ServiceInstance { this._options = { ...DEFAULT_OPTIONS, ...options } // added to maintain backward compatibility with webdriverIO v5 this._config || (this._config = this._options) - this._observability = this._options.testObservability + + // Use helper function to resolve reporting config + const reportingConfig = getTestReportingConfig(this._options) + this._observability = reportingConfig.enabled + + // Set environment variables for both naming conventions + setupEnvironmentVariables(this._options) + this._accessibility = this._options.accessibility this._percy = isTrue(process.env.BROWSERSTACK_PERCY) this._percyCaptureMode = process.env.BROWSERSTACK_PERCY_CAPTURE_MODE @@ -101,7 +110,11 @@ export default class BrowserstackService implements Services.ServiceInstance { // if no user and key is specified even though a browserstack service was // provided set user and key with values so that the session request // will fail - const testObservabilityOptions = this._options.testObservabilityOptions + + // Support both testObservabilityOptions and testReportingOptions + const reportingConfig = getTestReportingConfig(this._options) + const testObservabilityOptions = reportingConfig.options + if (!config.user && !(testObservabilityOptions && testObservabilityOptions.user)) { config.user = 'NotSetUser' } diff --git a/packages/wdio-browserstack-service/src/testHub/utils.ts b/packages/wdio-browserstack-service/src/testHub/utils.ts index 215ddbe11af..5eaafb02c06 100644 --- a/packages/wdio-browserstack-service/src/testHub/utils.ts +++ b/packages/wdio-browserstack-service/src/testHub/utils.ts @@ -1,5 +1,5 @@ -import { BROWSERSTACK_PERCY, BROWSERSTACK_OBSERVABILITY, BROWSERSTACK_ACCESSIBILITY } from '../constants.js' +import { BROWSERSTACK_PERCY, BROWSERSTACK_OBSERVABILITY, BROWSERSTACK_ACCESSIBILITY, BROWSERSTACK_TEST_REPORTING } from '../constants.js' import type BrowserStackConfig from '../config.js' import { BStackLogger } from '../bstackLogger.js' import { isTrue } from '../util.js' @@ -15,7 +15,7 @@ export const getProductMap = (config: BrowserStackConfig): any => { } export const shouldProcessEventForTesthub = (eventType: string): boolean => { - if (isTrue(process.env[BROWSERSTACK_OBSERVABILITY])) { + if (isTrue(process.env[BROWSERSTACK_OBSERVABILITY]) || isTrue(process.env[BROWSERSTACK_TEST_REPORTING])) { return true } if (isTrue(process.env[BROWSERSTACK_ACCESSIBILITY])) { @@ -24,11 +24,12 @@ export const shouldProcessEventForTesthub = (eventType: string): boolean => { if (isTrue(process.env[BROWSERSTACK_PERCY]) && eventType) { return false } - return Boolean(process.env[BROWSERSTACK_ACCESSIBILITY] || process.env[BROWSERSTACK_OBSERVABILITY] || process.env[BROWSERSTACK_PERCY])! + return Boolean(process.env[BROWSERSTACK_ACCESSIBILITY] || process.env[BROWSERSTACK_OBSERVABILITY] || process.env[BROWSERSTACK_TEST_REPORTING] || process.env[BROWSERSTACK_PERCY])! } export const handleErrorForObservability = (error: any): void => { process.env[BROWSERSTACK_OBSERVABILITY] = 'false' + process.env[BROWSERSTACK_TEST_REPORTING] = 'false' logBuildError(error, 'observability') } diff --git a/packages/wdio-browserstack-service/src/types.ts b/packages/wdio-browserstack-service/src/types.ts index 2e44298713e..b27e8080c6c 100644 --- a/packages/wdio-browserstack-service/src/types.ts +++ b/packages/wdio-browserstack-service/src/types.ts @@ -41,6 +41,15 @@ export interface TestObservabilityOptions { key?: string } +// Add new interface that's identical but with new name +export interface TestReportingOptions { + buildName?: string, + projectName?: string, + buildTag?: string[], + user?: string, + key?: string +} + export interface BrowserstackOptions extends Options.Testrunner { selfHeal?: boolean; } @@ -54,17 +63,31 @@ export interface BrowserstackConfig { */ buildIdentifier?: string; /** - * Set this to true to enable BrowserStack Test Observability which will collect test related data + * Set this to true to enable BrowserStack Test Reporting and Analytics which will collect test related data * (name, hierarchy, status, error stack trace, file name and hierarchy), test commands, etc. - * and show all the data in a meaningful manner in BrowserStack Test Observability dashboards for faster test debugging and better insights. + * and show all the data in a meaningful manner in BrowserStack Test Reporting and Analytics dashboards for faster test debugging and better insights. * @default true + * @deprecated Use testReporting instead */ testObservability?: boolean; /** - * Set the Test Observability related config options under this key. + * Set this to true to enable BrowserStack Test Reporting and Analytics which will collect test related data + * (name, hierarchy, status, error stack trace, file name and hierarchy), test commands, etc. + * and show all the data in a meaningful manner in BrowserStack Test Reporting and Analytics dashboards for faster test debugging and better insights. + * @default true + */ + testReporting?: boolean; + /** + * Set the Test Reporting and Analytics related config options under this key. * For e.g. buildName, projectName, BrowserStack access credentials, etc. + * @deprecated Use testReportingOptions instead */ testObservabilityOptions?: TestObservabilityOptions; + /** + * Set the Test Reporting and Analytics related config options under this key. + * For e.g. buildName, projectName, BrowserStack access credentials, etc. + */ + testReportingOptions?: TestReportingOptions; /** * Set this to true to enable BrowserStack Percy which will take screenshots * and snapshots for your tests run on Browserstack diff --git a/packages/wdio-browserstack-service/src/util.ts b/packages/wdio-browserstack-service/src/util.ts index 9bd7ebde3bc..fc71b43c851 100644 --- a/packages/wdio-browserstack-service/src/util.ts +++ b/packages/wdio-browserstack-service/src/util.ts @@ -40,6 +40,13 @@ import { TESTOPS_BUILD_COMPLETED_ENV, BROWSERSTACK_TESTHUB_JWT, BROWSERSTACK_OBSERVABILITY, + BROWSERSTACK_TEST_REPORTING, + TEST_REPORTING_BUILD_TAG, + TEST_REPORTING_BUILD_NAME, + TEST_REPORTING_PROJECT_NAME, + TEST_OBSERVABILITY_BUILD_TAG, + TEST_OBSERVABILITY_BUILD_NAME, + TEST_OBSERVABILITY_PROJECT_NAME, BROWSERSTACK_ACCESSIBILITY, MAX_GIT_META_DATA_SIZE_IN_BYTES, GIT_META_DATA_TRUNCATED, @@ -347,7 +354,8 @@ export const processAccessibilityResponse = (response: LaunchResponse, options: } export const processLaunchBuildResponse = (response: LaunchResponse, options: BrowserstackConfig & Options.Testrunner) => { - if (options.testObservability) { + const reportingConfig = getTestReportingConfig(options) + if (reportingConfig.enabled) { processTestObservabilityResponse(response) } processAccessibilityResponse(response, options) @@ -378,7 +386,7 @@ export const launchTestSession = PerformanceTester.measureWrapper(PERFORMANCE_SD accessibility: { settings: options.accessibilityOptions }, - browserstackAutomation: shouldAddServiceVersion(config, options.testObservability), + browserstackAutomation: shouldAddServiceVersion(config, getTestReportingConfig(options).enabled), framework_details: { frameworkName: 'WebdriverIO-' + config.framework, frameworkVersion: bsConfig.bstackServiceVersion, @@ -1172,7 +1180,11 @@ export function getBrowserStackUserAndKey(config: Options.Testrunner, options: O } export function shouldAddServiceVersion(config: Options.Testrunner, testObservability?: boolean, caps?: Capabilities.BrowserStackCapabilities): boolean { - if ((config.services && config.services.toString().includes('chromedriver') && testObservability !== false) || !isBrowserstackInfra(config, caps)) { + const options = config as BrowserstackConfig & Options.Testrunner + const reportingConfig = getTestReportingConfig(options) + const isTestReportingEnabled = testObservability ?? reportingConfig.enabled + + if ((config.services && config.services.toString().includes('chromedriver') && isTestReportingEnabled !== false) || !isBrowserstackInfra(config, caps)) { return false } return true @@ -1204,18 +1216,53 @@ export async function batchAndPostEvents (eventUrl: string, kind: string, data: }).json() BStackLogger.debug(`[${kind}] Success response: ${JSON.stringify(response)}`) } catch (error) { - BStackLogger.debug(`[${kind}] EXCEPTION IN ${kind} REQUEST TO TEST OBSERVABILITY : ${error}`) + BStackLogger.debug(`[${kind}] EXCEPTION IN ${kind} REQUEST TO TEST Reporting and Analytics : ${error}`) throw new Error('Exception in request ' + error) } } +// Update environment variable handling to support both sets +// Update environment variable handling to support both sets +export function setupEnvironmentVariables(options: BrowserstackConfig & Options.Testrunner) { + const reportingConfig = getTestReportingConfig(options) + + // Set both legacy and new environment variables for compatibility + if (reportingConfig.enabled) { + process.env[BROWSERSTACK_OBSERVABILITY] = 'true' + process.env[BROWSERSTACK_TEST_REPORTING] = 'true' + } else { + process.env[BROWSERSTACK_OBSERVABILITY] = 'false' + process.env[BROWSERSTACK_TEST_REPORTING] = 'false' + } +} + +// Add helper function to resolve test reporting config +export function getTestReportingConfig(options: BrowserstackConfig & Options.Testrunner) { + // New flags take precedence + if (options.testReporting !== undefined) { + return { + enabled: options.testReporting, + options: options.testReportingOptions || options.testObservabilityOptions || {} + } + } + + // Fallback to legacy flags + return { + enabled: options.testObservability ?? true, + options: options.testObservabilityOptions || {} + } +} + export function getObservabilityUser(options: BrowserstackConfig & Options.Testrunner, config: Options.Testrunner) { if (process.env.BROWSERSTACK_USERNAME) { return process.env.BROWSERSTACK_USERNAME } - if (options.testObservabilityOptions && options.testObservabilityOptions.user) { - return options.testObservabilityOptions.user + + const reportingConfig = getTestReportingConfig(options) + if (reportingConfig.options && reportingConfig.options.user) { + return reportingConfig.options.user } + return config.user } @@ -1223,39 +1270,66 @@ export function getObservabilityKey(options: BrowserstackConfig & Options.Testru if (process.env.BROWSERSTACK_ACCESS_KEY) { return process.env.BROWSERSTACK_ACCESS_KEY } - if (options.testObservabilityOptions && options.testObservabilityOptions.key) { - return options.testObservabilityOptions.key + + const reportingConfig = getTestReportingConfig(options) + if (reportingConfig.options && reportingConfig.options.key) { + return reportingConfig.options.key } + return config.key } export function getObservabilityProject(options: BrowserstackConfig & Options.Testrunner, bstackProjectName?: string) { + // Check new env var first + if (process.env.TEST_REPORTING_PROJECT_NAME) { + return process.env.TEST_REPORTING_PROJECT_NAME + } + // Fallback to legacy env var if (process.env.TEST_OBSERVABILITY_PROJECT_NAME) { return process.env.TEST_OBSERVABILITY_PROJECT_NAME } - if (options.testObservabilityOptions && options.testObservabilityOptions.projectName) { - return options.testObservabilityOptions.projectName + + const reportingConfig = getTestReportingConfig(options) + if (reportingConfig.options && reportingConfig.options.projectName) { + return reportingConfig.options.projectName } + return bstackProjectName } export function getObservabilityBuild(options: BrowserstackConfig & Options.Testrunner, bstackBuildName?: string) { + // Check new env var first + if (process.env.TEST_REPORTING_BUILD_NAME) { + return process.env.TEST_REPORTING_BUILD_NAME + } + // Fallback to legacy env var if (process.env.TEST_OBSERVABILITY_BUILD_NAME) { return process.env.TEST_OBSERVABILITY_BUILD_NAME } - if (options.testObservabilityOptions && options.testObservabilityOptions.buildName) { - return options.testObservabilityOptions.buildName + + const reportingConfig = getTestReportingConfig(options) + if (reportingConfig.options && reportingConfig.options.buildName) { + return reportingConfig.options.buildName } + return bstackBuildName || path.basename(path.resolve(process.cwd())) } export function getObservabilityBuildTags(options: BrowserstackConfig & Options.Testrunner, bstackBuildTag?: string): string[] { + // Check new env var first + if (process.env.TEST_REPORTING_BUILD_TAG) { + return process.env.TEST_REPORTING_BUILD_TAG.split(',') + } + // Fallback to legacy env var if (process.env.TEST_OBSERVABILITY_BUILD_TAG) { return process.env.TEST_OBSERVABILITY_BUILD_TAG.split(',') } - if (options.testObservabilityOptions && options.testObservabilityOptions.buildTag) { - return options.testObservabilityOptions.buildTag + + const reportingConfig = getTestReportingConfig(options) + if (reportingConfig.options && reportingConfig.options.buildTag) { + return reportingConfig.options.buildTag } + if (bstackBuildTag) { return [bstackBuildTag] } diff --git a/packages/wdio-browserstack-service/tests/service.test.ts b/packages/wdio-browserstack-service/tests/service.test.ts index afc23c77177..7b3624d4ea1 100644 --- a/packages/wdio-browserstack-service/tests/service.test.ts +++ b/packages/wdio-browserstack-service/tests/service.test.ts @@ -1306,7 +1306,7 @@ describe('setAnnotation', () => { keyword: 'Given ', } await service.beforeStep(step) - expect(browser.execute).toBeCalledTimes(3) + expect(browser.execute).toBeCalledTimes(4) expect(browser.execute).toBeCalledWith('browserstack_executor: {"action":"annotate","arguments":{"data":"Feature: Feature1","level":"info"}}') expect(browser.execute).toBeCalledWith('browserstack_executor: {"action":"annotate","arguments":{"data":"Scenario: foobar","level":"info"}}') expect(browser.execute).toBeCalledWith('browserstack_executor: {"action":"annotate","arguments":{"data":"Step: Given I am a step","level":"info"}}') @@ -1318,7 +1318,7 @@ describe('setAnnotation', () => { await service.before(service['_config'] as any, [], browser) await service.beforeSuite({ title: jasmineSuiteTitle } as any) await service.beforeTest({ fullName: 'foo bar baz', description: 'baz' } as any) - expect(browser.execute).toBeCalledTimes(1) + expect(browser.execute).toBeCalledTimes(2) expect(browser.execute).toBeCalledWith('browserstack_executor: {"action":"annotate","arguments":{"data":"Test: foo bar baz","level":"info"}}') }) }) @@ -1328,7 +1328,7 @@ describe('setAnnotation', () => { await service.before(service['_config'] as any, [], browser) await service.beforeSuite({ title: 'My Feature' } as any) await service.beforeTest({ title: 'Test Title', parent: 'Suite Title' } as any) - expect(browser.execute).toBeCalledTimes(1) + expect(browser.execute).toBeCalledTimes(2) expect(browser.execute).toBeCalledWith('browserstack_executor: {"action":"annotate","arguments":{"data":"Test: Test Title","level":"info"}}') }) }) From 792d4aa119b3f1499e22b6e140a67414bf1c45db Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Mon, 4 Aug 2025 16:39:39 +0530 Subject: [PATCH 2/4] minor fixes --- packages/wdio-browserstack-service/src/util.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/wdio-browserstack-service/src/util.ts b/packages/wdio-browserstack-service/src/util.ts index fc71b43c851..14f3508fbbc 100644 --- a/packages/wdio-browserstack-service/src/util.ts +++ b/packages/wdio-browserstack-service/src/util.ts @@ -41,12 +41,6 @@ import { BROWSERSTACK_TESTHUB_JWT, BROWSERSTACK_OBSERVABILITY, BROWSERSTACK_TEST_REPORTING, - TEST_REPORTING_BUILD_TAG, - TEST_REPORTING_BUILD_NAME, - TEST_REPORTING_PROJECT_NAME, - TEST_OBSERVABILITY_BUILD_TAG, - TEST_OBSERVABILITY_BUILD_NAME, - TEST_OBSERVABILITY_PROJECT_NAME, BROWSERSTACK_ACCESSIBILITY, MAX_GIT_META_DATA_SIZE_IN_BYTES, GIT_META_DATA_TRUNCATED, From b27f08baa4d2b70c5dbfb82cfc8211b35f58fd74 Mon Sep 17 00:00:00 2001 From: Tanmay Lokhande Date: Tue, 12 Aug 2025 07:44:19 +0530 Subject: [PATCH 3/4] updates for the comments --- .../src/accessibility-handler.ts | 6 +- .../wdio-browserstack-service/src/cleanup.ts | 5 +- .../wdio-browserstack-service/src/launcher.ts | 23 ++--- .../wdio-browserstack-service/src/service.ts | 16 ++-- .../src/testHub/utils.ts | 7 +- .../wdio-browserstack-service/src/util.ts | 96 +++++++------------ .../tests/request-handler.test.ts | 2 +- .../tests/service.test.ts | 6 +- 8 files changed, 60 insertions(+), 101 deletions(-) diff --git a/packages/wdio-browserstack-service/src/accessibility-handler.ts b/packages/wdio-browserstack-service/src/accessibility-handler.ts index 62e5f4dd159..01c7f981ce5 100644 --- a/packages/wdio-browserstack-service/src/accessibility-handler.ts +++ b/packages/wdio-browserstack-service/src/accessibility-handler.ts @@ -25,8 +25,7 @@ import { validateCapsWithNonBstackA11y, isTrue, validateCapsWithAppA11y, - getAppA11yResults, - getTestReportingConfig + getAppA11yResults } from './util.js' import accessibilityScripts from './scripts/accessibility-scripts.js' import PerformanceTester from './instrumentation/performance/performance-tester.js' @@ -116,8 +115,7 @@ class _AccessibilityHandler { this._accessibility = isTrue(this._getCapabilityValue(this._caps, 'accessibility', 'browserstack.accessibility')) //checks for running ALLY on non-bstack infra - const reportingConfig = getTestReportingConfig(this._options) - if (isAccessibilityAutomationSession(this._accessibility) && (this._turboscale || !shouldAddServiceVersion(this._config, reportingConfig.enabled))){ + if (isAccessibilityAutomationSession(this._accessibility) && (this._turboscale || !shouldAddServiceVersion(this._config, this._options.testObservability))){ if (validateCapsWithNonBstackA11y(this._platformA11yMeta.browser_name as string, this._platformA11yMeta?.browser_version as string)){ this._accessibility = true } diff --git a/packages/wdio-browserstack-service/src/cleanup.ts b/packages/wdio-browserstack-service/src/cleanup.ts index 5f43e920035..ba289f8ec44 100644 --- a/packages/wdio-browserstack-service/src/cleanup.ts +++ b/packages/wdio-browserstack-service/src/cleanup.ts @@ -3,7 +3,7 @@ import { BStackLogger } from './bstackLogger.js' import fs from 'node:fs' import util from 'node:util' import { fireFunnelRequest } from './instrumentation/funnelInstrumentation.js' -import { BROWSERSTACK_TESTHUB_UUID, BROWSERSTACK_TESTHUB_JWT, BROWSERSTACK_OBSERVABILITY, BROWSERSTACK_TEST_REPORTING } from './constants.js' +import { BROWSERSTACK_TESTHUB_UUID, BROWSERSTACK_TESTHUB_JWT, BROWSERSTACK_OBSERVABILITY } from './constants.js' import PerformanceTester from './instrumentation/performance/performance-tester.js' export default class BStackCleanup { @@ -46,8 +46,7 @@ export default class BStackCleanup { try { const killSignal = funnelData?.event_properties?.finishedMetadata?.signal const result = await stopBuildUpstream(killSignal) - // Update to use new URL and support both environment variables - if ((process.env[BROWSERSTACK_OBSERVABILITY] || process.env[BROWSERSTACK_TEST_REPORTING]) && process.env[BROWSERSTACK_TESTHUB_UUID]) { + if (process.env[BROWSERSTACK_OBSERVABILITY] && process.env[BROWSERSTACK_TESTHUB_UUID]) { BStackLogger.info(`\nVisit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TESTHUB_UUID]} to view build report, insights, and many more debugging information all at one place!\n`) } const status = (result && result.status) || 'failed' diff --git a/packages/wdio-browserstack-service/src/launcher.ts b/packages/wdio-browserstack-service/src/launcher.ts index cbe58c5e52e..7f6e85fe036 100644 --- a/packages/wdio-browserstack-service/src/launcher.ts +++ b/packages/wdio-browserstack-service/src/launcher.ts @@ -22,8 +22,7 @@ import { BROWSERSTACK_TESTHUB_UUID, VALID_APP_EXTENSION, BROWSERSTACK_PERCY, - BROWSERSTACK_OBSERVABILITY, - BROWSERSTACK_TEST_REPORTING + BROWSERSTACK_OBSERVABILITY } from './constants.js' import { launchTestSession, @@ -42,7 +41,8 @@ import { getBooleanValueFromString, validateCapsWithNonBstackA11y, mergeChromeOptions, - getTestReportingConfig + normalizeTestReportingConfig, + normalizeTestReportingEnvVariables } from './util.js' import { getProductMap } from './testHub/utils.js' import CrashReporter from './crash-reporter.js' @@ -86,6 +86,10 @@ export default class BrowserstackLauncherService implements Services.ServiceInst // added to maintain backward compatibility with webdriverIO v5 this._config || (this._config = _options) + //normalizing testReporting config and env variables + normalizeTestReportingConfig(this._options) + + normalizeTestReportingEnvVariables() this.browserStackConfig = BrowserStackConfig.getInstance(_options, _config) if (Array.isArray(capabilities)) { capabilities @@ -175,10 +179,7 @@ export default class BrowserstackLauncherService implements Services.ServiceInst // by default observability will be true unless specified as false this._options.testObservability = this._options.testObservability !== false - // Get resolved reporting config - const reportingConfig = getTestReportingConfig(this._options) - - if (reportingConfig.enabled + if (this._options.testObservability && // update files to run if it's a rerun process.env[RERUN_ENV] && process.env[RERUN_TESTS_ENV] @@ -288,10 +289,7 @@ export default class BrowserstackLauncherService implements Services.ServiceInst const shouldSetupPercy = this._options.percy || (isUndefined(this._options.percy) && this._options.app) let buildStartResponse = null - const reportingConfig = getTestReportingConfig(this._options) - const shouldLaunchTestSession = this._accessibilityAutomation || reportingConfig.enabled || shouldSetupPercy - - if (shouldLaunchTestSession) { + if (this._options.testObservability || this._accessibilityAutomation || shouldSetupPercy) { BStackLogger.debug('Sending launch start event') buildStartResponse = await launchTestSession(this._options, this._config, { @@ -412,8 +410,7 @@ export default class BrowserstackLauncherService implements Services.ServiceInst BStackLogger.debug('Sending stop launch event') await stopBuildUpstream() - // Update to use new URL and terminology - check both old and new env vars - if ((process.env[BROWSERSTACK_OBSERVABILITY] || process.env[BROWSERSTACK_TEST_REPORTING]) && process.env[BROWSERSTACK_TESTHUB_UUID]) { + if (process.env[BROWSERSTACK_OBSERVABILITY] && process.env[BROWSERSTACK_TESTHUB_UUID]) { console.log(`\nVisit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TESTHUB_UUID]} to view build report, insights, and many more debugging information all at one place!\n`) } this.browserStackConfig.testObservability.buildStopped = true diff --git a/packages/wdio-browserstack-service/src/service.ts b/packages/wdio-browserstack-service/src/service.ts index cee83a22064..1fe247ad19e 100644 --- a/packages/wdio-browserstack-service/src/service.ts +++ b/packages/wdio-browserstack-service/src/service.ts @@ -11,8 +11,8 @@ import { patchConsoleLogs, shouldAddServiceVersion, isTrue, - getTestReportingConfig, - setupEnvironmentVariables + normalizeTestReportingConfig, + normalizeTestReportingEnvVariables } from './util.js' import type { BrowserstackConfig, BrowserstackOptions, MultiRemoteAction, SessionResponse, TurboScaleSessionResponse } from './types.js' import type { Pickle, Feature, ITestCaseHookParameter, CucumberHook } from './cucumber-types.js' @@ -61,12 +61,10 @@ export default class BrowserstackService implements Services.ServiceInstance { // added to maintain backward compatibility with webdriverIO v5 this._config || (this._config = this._options) - // Use helper function to resolve reporting config - const reportingConfig = getTestReportingConfig(this._options) - this._observability = reportingConfig.enabled + normalizeTestReportingConfig(this._options) - // Set environment variables for both naming conventions - setupEnvironmentVariables(this._options) + normalizeTestReportingEnvVariables() + this._observability = this._options.testObservability this._accessibility = this._options.accessibility this._percy = isTrue(process.env.BROWSERSTACK_PERCY) @@ -111,9 +109,7 @@ export default class BrowserstackService implements Services.ServiceInstance { // provided set user and key with values so that the session request // will fail - // Support both testObservabilityOptions and testReportingOptions - const reportingConfig = getTestReportingConfig(this._options) - const testObservabilityOptions = reportingConfig.options + const testObservabilityOptions = this._options.testObservabilityOptions if (!config.user && !(testObservabilityOptions && testObservabilityOptions.user)) { config.user = 'NotSetUser' diff --git a/packages/wdio-browserstack-service/src/testHub/utils.ts b/packages/wdio-browserstack-service/src/testHub/utils.ts index 5eaafb02c06..215ddbe11af 100644 --- a/packages/wdio-browserstack-service/src/testHub/utils.ts +++ b/packages/wdio-browserstack-service/src/testHub/utils.ts @@ -1,5 +1,5 @@ -import { BROWSERSTACK_PERCY, BROWSERSTACK_OBSERVABILITY, BROWSERSTACK_ACCESSIBILITY, BROWSERSTACK_TEST_REPORTING } from '../constants.js' +import { BROWSERSTACK_PERCY, BROWSERSTACK_OBSERVABILITY, BROWSERSTACK_ACCESSIBILITY } from '../constants.js' import type BrowserStackConfig from '../config.js' import { BStackLogger } from '../bstackLogger.js' import { isTrue } from '../util.js' @@ -15,7 +15,7 @@ export const getProductMap = (config: BrowserStackConfig): any => { } export const shouldProcessEventForTesthub = (eventType: string): boolean => { - if (isTrue(process.env[BROWSERSTACK_OBSERVABILITY]) || isTrue(process.env[BROWSERSTACK_TEST_REPORTING])) { + if (isTrue(process.env[BROWSERSTACK_OBSERVABILITY])) { return true } if (isTrue(process.env[BROWSERSTACK_ACCESSIBILITY])) { @@ -24,12 +24,11 @@ export const shouldProcessEventForTesthub = (eventType: string): boolean => { if (isTrue(process.env[BROWSERSTACK_PERCY]) && eventType) { return false } - return Boolean(process.env[BROWSERSTACK_ACCESSIBILITY] || process.env[BROWSERSTACK_OBSERVABILITY] || process.env[BROWSERSTACK_TEST_REPORTING] || process.env[BROWSERSTACK_PERCY])! + return Boolean(process.env[BROWSERSTACK_ACCESSIBILITY] || process.env[BROWSERSTACK_OBSERVABILITY] || process.env[BROWSERSTACK_PERCY])! } export const handleErrorForObservability = (error: any): void => { process.env[BROWSERSTACK_OBSERVABILITY] = 'false' - process.env[BROWSERSTACK_TEST_REPORTING] = 'false' logBuildError(error, 'observability') } diff --git a/packages/wdio-browserstack-service/src/util.ts b/packages/wdio-browserstack-service/src/util.ts index 14f3508fbbc..d48f6c07838 100644 --- a/packages/wdio-browserstack-service/src/util.ts +++ b/packages/wdio-browserstack-service/src/util.ts @@ -46,7 +46,8 @@ import { GIT_META_DATA_TRUNCATED, APP_ALLY_ENDPOINT, APP_ALLY_ISSUES_SUMMARY_ENDPOINT, - APP_ALLY_ISSUES_ENDPOINT + APP_ALLY_ISSUES_ENDPOINT, + TEST_REPORTING_PROJECT_NAME } from './constants.js' import CrashReporter from './crash-reporter.js' import { BStackLogger } from './bstackLogger.js' @@ -348,8 +349,7 @@ export const processAccessibilityResponse = (response: LaunchResponse, options: } export const processLaunchBuildResponse = (response: LaunchResponse, options: BrowserstackConfig & Options.Testrunner) => { - const reportingConfig = getTestReportingConfig(options) - if (reportingConfig.enabled) { + if (options.testObservability) { processTestObservabilityResponse(response) } processAccessibilityResponse(response, options) @@ -380,7 +380,7 @@ export const launchTestSession = PerformanceTester.measureWrapper(PERFORMANCE_SD accessibility: { settings: options.accessibilityOptions }, - browserstackAutomation: shouldAddServiceVersion(config, getTestReportingConfig(options).enabled), + browserstackAutomation: shouldAddServiceVersion(config, options.testObservability), framework_details: { frameworkName: 'WebdriverIO-' + config.framework, frameworkVersion: bsConfig.bstackServiceVersion, @@ -1174,11 +1174,7 @@ export function getBrowserStackUserAndKey(config: Options.Testrunner, options: O } export function shouldAddServiceVersion(config: Options.Testrunner, testObservability?: boolean, caps?: Capabilities.BrowserStackCapabilities): boolean { - const options = config as BrowserstackConfig & Options.Testrunner - const reportingConfig = getTestReportingConfig(options) - const isTestReportingEnabled = testObservability ?? reportingConfig.enabled - - if ((config.services && config.services.toString().includes('chromedriver') && isTestReportingEnabled !== false) || !isBrowserstackInfra(config, caps)) { + if ((config.services && config.services.toString().includes('chromedriver') && testObservability !== false) || !isBrowserstackInfra(config, caps)) { return false } return true @@ -1215,36 +1211,30 @@ export async function batchAndPostEvents (eventUrl: string, kind: string, data: } } -// Update environment variable handling to support both sets -// Update environment variable handling to support both sets -export function setupEnvironmentVariables(options: BrowserstackConfig & Options.Testrunner) { - const reportingConfig = getTestReportingConfig(options) +export function normalizeTestReportingConfig(_options: BrowserstackConfig & Options.Testrunner){ + if (!isUndefined(_options.testReporting)){ + _options.testObservability = _options.testReporting + } - // Set both legacy and new environment variables for compatibility - if (reportingConfig.enabled) { - process.env[BROWSERSTACK_OBSERVABILITY] = 'true' - process.env[BROWSERSTACK_TEST_REPORTING] = 'true' - } else { - process.env[BROWSERSTACK_OBSERVABILITY] = 'false' - process.env[BROWSERSTACK_TEST_REPORTING] = 'false' + if (!isUndefined(_options.testReportingOptions)){ + _options.testObservabilityOptions = _options.testReportingOptions } } -// Add helper function to resolve test reporting config -export function getTestReportingConfig(options: BrowserstackConfig & Options.Testrunner) { - // New flags take precedence - if (options.testReporting !== undefined) { - return { - enabled: options.testReporting, - options: options.testReportingOptions || options.testObservabilityOptions || {} - } +export function normalizeTestReportingEnvVariables(){ + if (!isUndefined(process.env[BROWSERSTACK_TEST_REPORTING])){ + process.env[BROWSERSTACK_OBSERVABILITY] = process.env[BROWSERSTACK_TEST_REPORTING] } - - // Fallback to legacy flags - return { - enabled: options.testObservability ?? true, - options: options.testObservabilityOptions || {} + if (!isUndefined(process.env[TEST_REPORTING_PROJECT_NAME])){ + process.env.TEST_OBSERVABILITY_PROJECT_NAME = process.env[TEST_REPORTING_PROJECT_NAME] } + if (!isUndefined(process.env.TEST_REPORTING_BUILD_NAME)) { + process.env.TEST_OBSERVABILITY_BUILD_NAME = process.env.TEST_REPORTING_BUILD_NAME + } + if (!isUndefined(process.env.TEST_REPORTING_BUILD_TAG)) { + process.env.TEST_OBSERVABILITY_BUILD_TAG = process.env.TEST_REPORTING_BUILD_TAG + } + } export function getObservabilityUser(options: BrowserstackConfig & Options.Testrunner, config: Options.Testrunner) { @@ -1252,9 +1242,8 @@ export function getObservabilityUser(options: BrowserstackConfig & Options.Testr return process.env.BROWSERSTACK_USERNAME } - const reportingConfig = getTestReportingConfig(options) - if (reportingConfig.options && reportingConfig.options.user) { - return reportingConfig.options.user + if (options.testObservabilityOptions && options.testObservabilityOptions.user) { + return options.testObservabilityOptions.user } return config.user @@ -1265,63 +1254,44 @@ export function getObservabilityKey(options: BrowserstackConfig & Options.Testru return process.env.BROWSERSTACK_ACCESS_KEY } - const reportingConfig = getTestReportingConfig(options) - if (reportingConfig.options && reportingConfig.options.key) { - return reportingConfig.options.key + if (options.testObservabilityOptions && options.testObservabilityOptions.key) { + return options.testObservabilityOptions.key } return config.key } export function getObservabilityProject(options: BrowserstackConfig & Options.Testrunner, bstackProjectName?: string) { - // Check new env var first - if (process.env.TEST_REPORTING_PROJECT_NAME) { - return process.env.TEST_REPORTING_PROJECT_NAME - } - // Fallback to legacy env var if (process.env.TEST_OBSERVABILITY_PROJECT_NAME) { return process.env.TEST_OBSERVABILITY_PROJECT_NAME } - const reportingConfig = getTestReportingConfig(options) - if (reportingConfig.options && reportingConfig.options.projectName) { - return reportingConfig.options.projectName + if (options.testObservabilityOptions && options.testObservabilityOptions.projectName) { + return options.testObservabilityOptions.projectName } return bstackProjectName } export function getObservabilityBuild(options: BrowserstackConfig & Options.Testrunner, bstackBuildName?: string) { - // Check new env var first - if (process.env.TEST_REPORTING_BUILD_NAME) { - return process.env.TEST_REPORTING_BUILD_NAME - } - // Fallback to legacy env var if (process.env.TEST_OBSERVABILITY_BUILD_NAME) { return process.env.TEST_OBSERVABILITY_BUILD_NAME } - const reportingConfig = getTestReportingConfig(options) - if (reportingConfig.options && reportingConfig.options.buildName) { - return reportingConfig.options.buildName + if (options.testObservabilityOptions && options.testObservabilityOptions.buildName) { + return options.testObservabilityOptions.buildName } return bstackBuildName || path.basename(path.resolve(process.cwd())) } export function getObservabilityBuildTags(options: BrowserstackConfig & Options.Testrunner, bstackBuildTag?: string): string[] { - // Check new env var first - if (process.env.TEST_REPORTING_BUILD_TAG) { - return process.env.TEST_REPORTING_BUILD_TAG.split(',') - } - // Fallback to legacy env var if (process.env.TEST_OBSERVABILITY_BUILD_TAG) { return process.env.TEST_OBSERVABILITY_BUILD_TAG.split(',') } - const reportingConfig = getTestReportingConfig(options) - if (reportingConfig.options && reportingConfig.options.buildTag) { - return reportingConfig.options.buildTag + if (options.testObservabilityOptions && options.testObservabilityOptions.buildTag) { + return options.testObservabilityOptions.buildTag } if (bstackBuildTag) { diff --git a/packages/wdio-browserstack-service/tests/request-handler.test.ts b/packages/wdio-browserstack-service/tests/request-handler.test.ts index a1f66d39925..0d95cce0398 100644 --- a/packages/wdio-browserstack-service/tests/request-handler.test.ts +++ b/packages/wdio-browserstack-service/tests/request-handler.test.ts @@ -28,7 +28,7 @@ describe('RequestQueueHandler', () => { describe('add', () => { it('throw error if BS_TESTOPS_BUILD_COMPLETED not present', () => { delete process.env[TESTOPS_BUILD_COMPLETED_ENV] - expect(() => requestQueueHandler.add({ event_type: 'there' })).toThrowError(/Observability build start not completed yet/) + expect(() => requestQueueHandler.add({ event_type: 'there' })).toThrowError(/Test Reporting and Analytics build start not completed yet/) }) it('if event_type in BATCH_EVENT_TYPES', () => { diff --git a/packages/wdio-browserstack-service/tests/service.test.ts b/packages/wdio-browserstack-service/tests/service.test.ts index 7b3624d4ea1..afc23c77177 100644 --- a/packages/wdio-browserstack-service/tests/service.test.ts +++ b/packages/wdio-browserstack-service/tests/service.test.ts @@ -1306,7 +1306,7 @@ describe('setAnnotation', () => { keyword: 'Given ', } await service.beforeStep(step) - expect(browser.execute).toBeCalledTimes(4) + expect(browser.execute).toBeCalledTimes(3) expect(browser.execute).toBeCalledWith('browserstack_executor: {"action":"annotate","arguments":{"data":"Feature: Feature1","level":"info"}}') expect(browser.execute).toBeCalledWith('browserstack_executor: {"action":"annotate","arguments":{"data":"Scenario: foobar","level":"info"}}') expect(browser.execute).toBeCalledWith('browserstack_executor: {"action":"annotate","arguments":{"data":"Step: Given I am a step","level":"info"}}') @@ -1318,7 +1318,7 @@ describe('setAnnotation', () => { await service.before(service['_config'] as any, [], browser) await service.beforeSuite({ title: jasmineSuiteTitle } as any) await service.beforeTest({ fullName: 'foo bar baz', description: 'baz' } as any) - expect(browser.execute).toBeCalledTimes(2) + expect(browser.execute).toBeCalledTimes(1) expect(browser.execute).toBeCalledWith('browserstack_executor: {"action":"annotate","arguments":{"data":"Test: foo bar baz","level":"info"}}') }) }) @@ -1328,7 +1328,7 @@ describe('setAnnotation', () => { await service.before(service['_config'] as any, [], browser) await service.beforeSuite({ title: 'My Feature' } as any) await service.beforeTest({ title: 'Test Title', parent: 'Suite Title' } as any) - expect(browser.execute).toBeCalledTimes(2) + expect(browser.execute).toBeCalledTimes(1) expect(browser.execute).toBeCalledWith('browserstack_executor: {"action":"annotate","arguments":{"data":"Test: Test Title","level":"info"}}') }) }) From 02a92c628aa5240e96edf7b0373b6cc1ed12932e Mon Sep 17 00:00:00 2001 From: Tanmay Lokhande Date: Tue, 12 Aug 2025 07:53:12 +0530 Subject: [PATCH 4/4] updated readme --- packages/wdio-browserstack-service/README.md | 34 ------------------- .../wdio-browserstack-service/src/launcher.ts | 1 - .../wdio-browserstack-service/src/service.ts | 3 -- .../wdio-browserstack-service/src/util.ts | 10 ------ 4 files changed, 48 deletions(-) diff --git a/packages/wdio-browserstack-service/README.md b/packages/wdio-browserstack-service/README.md index 1afe4b6ee3b..0ef7d661279 100644 --- a/packages/wdio-browserstack-service/README.md +++ b/packages/wdio-browserstack-service/README.md @@ -109,40 +109,6 @@ The following environment variables are supported: You can explore all the features of Test Reporting and Analytics in [this sandbox](https://automation-demo.browserstack.com/?utm_source=webdriverio&utm_medium=partnered&utm_campaign=documentation) or read more about it [here](https://www.browserstack.com/docs/test-reporting/overview/what-is-test-reporting?utm_source=webdriverio&utm_medium=partnered&utm_campaign=documentation). -### testObservability (deprecated) - -**⚠️ DEPRECATED:** Use `testReporting` instead. This option is maintained for backward compatibility. - -Test Observability is an advanced test reporting tool that gives insights to improve your automation tests and helps you debug faster. It's enabled by default by setting the testObservability​ flag as true for all users of browserstack-service. You can disable this by setting the testObservability​ flag to false. - -Once your tests finish running, you can visit [Test Reporting and Analytics](https://automation.browserstack.com/?utm_source=webdriverio&utm_medium=partnered&utm_campaign=documentation) to debug your builds with additional insights like Unique Error Analysis, Automatic Flaky Test Detection, and more. - -You can use Test Observability even if you don't run your tests on the BrowserStack infrastructure. Even if you run your tests on a CI, a local machine, or even on other cloud service providers, Test Observability can still generate intelligent test reports and advanced analytics on your tests. - -If you want to use Test Observability without running your tests on BrowserStack infrastructure, you can set your config as follows: - - -```js -// wdio.conf.js -export const config = { - // ... - services: [ - ['browserstack', { - testObservability: true, - testObservabilityOptions: { - user: process.env.BROWSERSTACK_USERNAME, - key: process.env.BROWSERSTACK_ACCESS_KEY, - projectName: "Your project name goes here", - buildName: "The static build job name goes here e.g. Nightly regression" - } - }] - ], - // ... -}; -``` - -You can explore all the features of Test Reporting and Analytics in [this sandbox](https://automation-demo.browserstack.com/?utm_source=webdriverio&utm_medium=partnered&utm_campaign=documentation) or read more about it [here](https://www.browserstack.com/docs/test-reporting/overview/what-is-test-reporting?utm_source=webdriverio&utm_medium=partnered&utm_campaign=documentation). - ### browserstackLocal Set this to true to enable routing connections from BrowserStack cloud through your computer. diff --git a/packages/wdio-browserstack-service/src/launcher.ts b/packages/wdio-browserstack-service/src/launcher.ts index 7f6e85fe036..3af346bae57 100644 --- a/packages/wdio-browserstack-service/src/launcher.ts +++ b/packages/wdio-browserstack-service/src/launcher.ts @@ -409,7 +409,6 @@ export default class BrowserstackLauncherService implements Services.ServiceInst BStackLogger.debug('Sending stop launch event') await stopBuildUpstream() - if (process.env[BROWSERSTACK_OBSERVABILITY] && process.env[BROWSERSTACK_TESTHUB_UUID]) { console.log(`\nVisit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TESTHUB_UUID]} to view build report, insights, and many more debugging information all at one place!\n`) } diff --git a/packages/wdio-browserstack-service/src/service.ts b/packages/wdio-browserstack-service/src/service.ts index 1fe247ad19e..a2d471a1d3e 100644 --- a/packages/wdio-browserstack-service/src/service.ts +++ b/packages/wdio-browserstack-service/src/service.ts @@ -65,7 +65,6 @@ export default class BrowserstackService implements Services.ServiceInstance { normalizeTestReportingEnvVariables() this._observability = this._options.testObservability - this._accessibility = this._options.accessibility this._percy = isTrue(process.env.BROWSERSTACK_PERCY) this._percyCaptureMode = process.env.BROWSERSTACK_PERCY_CAPTURE_MODE @@ -108,9 +107,7 @@ export default class BrowserstackService implements Services.ServiceInstance { // if no user and key is specified even though a browserstack service was // provided set user and key with values so that the session request // will fail - const testObservabilityOptions = this._options.testObservabilityOptions - if (!config.user && !(testObservabilityOptions && testObservabilityOptions.user)) { config.user = 'NotSetUser' } diff --git a/packages/wdio-browserstack-service/src/util.ts b/packages/wdio-browserstack-service/src/util.ts index d48f6c07838..e03a7abe900 100644 --- a/packages/wdio-browserstack-service/src/util.ts +++ b/packages/wdio-browserstack-service/src/util.ts @@ -1241,11 +1241,9 @@ export function getObservabilityUser(options: BrowserstackConfig & Options.Testr if (process.env.BROWSERSTACK_USERNAME) { return process.env.BROWSERSTACK_USERNAME } - if (options.testObservabilityOptions && options.testObservabilityOptions.user) { return options.testObservabilityOptions.user } - return config.user } @@ -1253,11 +1251,9 @@ export function getObservabilityKey(options: BrowserstackConfig & Options.Testru if (process.env.BROWSERSTACK_ACCESS_KEY) { return process.env.BROWSERSTACK_ACCESS_KEY } - if (options.testObservabilityOptions && options.testObservabilityOptions.key) { return options.testObservabilityOptions.key } - return config.key } @@ -1265,11 +1261,9 @@ export function getObservabilityProject(options: BrowserstackConfig & Options.Te if (process.env.TEST_OBSERVABILITY_PROJECT_NAME) { return process.env.TEST_OBSERVABILITY_PROJECT_NAME } - if (options.testObservabilityOptions && options.testObservabilityOptions.projectName) { return options.testObservabilityOptions.projectName } - return bstackProjectName } @@ -1277,11 +1271,9 @@ export function getObservabilityBuild(options: BrowserstackConfig & Options.Test if (process.env.TEST_OBSERVABILITY_BUILD_NAME) { return process.env.TEST_OBSERVABILITY_BUILD_NAME } - if (options.testObservabilityOptions && options.testObservabilityOptions.buildName) { return options.testObservabilityOptions.buildName } - return bstackBuildName || path.basename(path.resolve(process.cwd())) } @@ -1289,11 +1281,9 @@ export function getObservabilityBuildTags(options: BrowserstackConfig & Options. if (process.env.TEST_OBSERVABILITY_BUILD_TAG) { return process.env.TEST_OBSERVABILITY_BUILD_TAG.split(',') } - if (options.testObservabilityOptions && options.testObservabilityOptions.buildTag) { return options.testObservabilityOptions.buildTag } - if (bstackBuildTag) { return [bstackBuildTag] }