From aea24d8fa368fce14d71598c30699230b27185ff Mon Sep 17 00:00:00 2001 From: Bhargavi-BS Date: Thu, 15 May 2025 20:15:06 +0530 Subject: [PATCH 1/8] support for non-bstack ALLY --- .../src/accessibility-handler.ts | 23 ++++++- .../wdio-browserstack-service/src/launcher.ts | 33 ++++++++- .../src/scripts/accessibility-scripts.ts | 10 ++- .../wdio-browserstack-service/src/service.ts | 31 +++++---- .../wdio-browserstack-service/src/util.ts | 69 +++++++++++++++++-- 5 files changed, 139 insertions(+), 27 deletions(-) diff --git a/packages/wdio-browserstack-service/src/accessibility-handler.ts b/packages/wdio-browserstack-service/src/accessibility-handler.ts index 25a3ba37aed..8fe851e7956 100644 --- a/packages/wdio-browserstack-service/src/accessibility-handler.ts +++ b/packages/wdio-browserstack-service/src/accessibility-handler.ts @@ -1,6 +1,8 @@ import util from 'node:util' -import type { Capabilities, Frameworks } from '@wdio/types' +import type { Capabilities, Frameworks, Options } from '@wdio/types' + +import type { BrowserstackConfig, BrowserstackOptions } from './types.js' import type { ITestCaseHookParameter } from './cucumber-types.js' @@ -19,6 +21,8 @@ import { o11yClassErrorHandler, shouldScanTestForAccessibility, validateCapsWithA11y, + shouldAddServiceVersion, + validateCapsWithNonBstackA11y, isTrue, validateCapsWithAppA11y, getAppA11yResults, @@ -35,6 +39,9 @@ class _AccessibilityHandler { private _caps: Capabilities.ResolvedTestrunnerCapabilities private _suiteFile?: string private _accessibility?: boolean + private _turboscale?: boolean + private _options: BrowserstackConfig & BrowserstackOptions + private _config: Options.Testrunner private _accessibilityOptions?: { [key: string]: unknown; } private _testMetadata: { [key: string]: unknown; } = {} private static _a11yScanSessionMap: { [key: string]: unknown; } = {} @@ -44,9 +51,12 @@ class _AccessibilityHandler { constructor ( private _browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser, _capabilities: Capabilities.ResolvedTestrunnerCapabilities, + _options : BrowserstackConfig & BrowserstackOptions, private isAppAutomate: boolean, + _config : Options.Testrunner, private _framework?: string, _accessibilityAutomation?: boolean | string, + _turboscale?: boolean | string, _accessibilityOpts?: { [key: string]: unknown; } ) { const caps = (this._browser as WebdriverIO.Browser).capabilities as WebdriverIO.Capabilities @@ -64,6 +74,9 @@ class _AccessibilityHandler { this._caps = _capabilities this._accessibility = isTrue(_accessibilityAutomation) this._accessibilityOptions = _accessibilityOpts + this._options = _options + this._config= _config + this._turboscale = isTrue(_turboscale) } setSuiteFile(filename: string) { @@ -103,7 +116,11 @@ class _AccessibilityHandler { this._sessionId = sessionId this._accessibility = isTrue(this._getCapabilityValue(this._caps, 'accessibility', 'browserstack.accessibility')) - if (isBrowserstackSession(this._browser)) { + 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 + } + } else { if (isAccessibilityAutomationSession(this._accessibility) && !this.isAppAutomate) { const deviceName = this._getCapabilityValue(this._caps, 'deviceName', 'device') const chromeOptions = this._getCapabilityValue(this._caps, 'goog:chromeOptions', '') as Capabilities.ChromeOptions @@ -356,7 +373,7 @@ class _AccessibilityHandler { if (!browser) { return false } - return isBrowserstackSession(browser) && isAccessibilityAutomationSession(isAccessibility) + return isAccessibilityAutomationSession(isAccessibility) } private async checkIfPageOpened(browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser, testIdentifier: string, shouldScanTest?: boolean) { diff --git a/packages/wdio-browserstack-service/src/launcher.ts b/packages/wdio-browserstack-service/src/launcher.ts index 9c9701ca950..a138c3d1fa8 100644 --- a/packages/wdio-browserstack-service/src/launcher.ts +++ b/packages/wdio-browserstack-service/src/launcher.ts @@ -39,6 +39,8 @@ import { ObjectsAreEqual, getBasicAuthHeader, isValidCapsForHealing, getBooleanValueFromString, + validateCapsWithNonBstackA11y, + mergeChromeOptions } from './util.js' import CrashReporter from './crash-reporter.js' import { BStackLogger } from './bstackLogger.js' @@ -50,7 +52,7 @@ import { sendFinish, sendStart } from './instrumentation/funnelInstrumentation.j import AiHandler from './ai-handler.js' import PerformanceTester from './instrumentation/performance/performance-tester.js' import * as PERFORMANCE_SDK_EVENTS from './instrumentation/performance/constants.js' - +import accessibilityScripts from './scripts/accessibility-scripts.js' import { _fetch as fetch } from './fetchWrapper.js' type BrowserstackLocal = BrowserstackLocalLauncher.Local & { @@ -295,6 +297,35 @@ export default class BrowserstackLauncherService implements Services.ServiceInst buildIdentifier: this._buildIdentifier }, this.browserStackConfig, this._accessibilityAutomation) } + + if (isAccessibilityAutomationSession(this._accessibilityAutomation) && (process.env.BROWSERSTACK_TURBOSCALE || !shouldAddServiceVersion(this._config, this._options.testObservability))){ + if (Array.isArray(capabilities)) { + capabilities + .flatMap((c) => { + + if (Object.values(c).length > 0 && Object.values(c).every(c => typeof c === 'object' && c.capabilities)) { + return Object.values(c).map((o) => o.capabilities) as WebdriverIO.Capabilities[] + } + return c as WebdriverIO.Capabilities + }) + .forEach((capability: WebdriverIO.Capabilities) => { + if (validateCapsWithNonBstackA11y(capability['browserName'], capability['browserVersion'] )){ + const chromeOptions = capability['goog:chromeOptions'] as unknown as Capabilities.ChromeOptions + const overrideOptions: Partial = accessibilityScripts.ChromeExtension + if (chromeOptions){ + + const finalChromeOptions = mergeChromeOptions(chromeOptions, overrideOptions) + capability['goog:chromeOptions'] = finalChromeOptions + } else { + capability['goog:chromeOptions'] = overrideOptions + + } + + } + }) + } + } + if (buildStartResponse?.accessibility) { if (this._accessibilityAutomation === null) { this.browserStackConfig.accessibility = buildStartResponse.accessibility.success as boolean diff --git a/packages/wdio-browserstack-service/src/scripts/accessibility-scripts.ts b/packages/wdio-browserstack-service/src/scripts/accessibility-scripts.ts index 6290b1f9fbf..152ab12e346 100644 --- a/packages/wdio-browserstack-service/src/scripts/accessibility-scripts.ts +++ b/packages/wdio-browserstack-service/src/scripts/accessibility-scripts.ts @@ -22,6 +22,7 @@ class AccessibilityScripts { public getResultsSummary: string | null = null public saveTestResults: string | null = null public commandsToWrap: Array | null = null + public ChromeExtension: { [key: string]: unknown } = {} public browserstackFolderPath = '' public commandsPath = '' @@ -77,7 +78,7 @@ class AccessibilityScripts { } } - public update(data: { commands: [], scripts: Scripts }) { + public update(data: { commands: [], scripts: Scripts, nonBStackInfraA11yChromeOptions: {} }) { if (data.scripts) { this.performScan = data.scripts.scan this.getResults = data.scripts.getResults @@ -87,6 +88,10 @@ class AccessibilityScripts { if (data.commands && data.commands.length) { this.commandsToWrap = data.commands } + if (data.nonBStackInfraA11yChromeOptions){ + this.ChromeExtension = data.nonBStackInfraA11yChromeOptions + } + } public store() { @@ -101,7 +106,8 @@ class AccessibilityScripts { getResults: this.getResults, getResultsSummary: this.getResultsSummary, saveResults: this.saveTestResults, - } + }, + nonBStackInfraA11yChromeOptions: this.ChromeExtension, })) } } diff --git a/packages/wdio-browserstack-service/src/service.ts b/packages/wdio-browserstack-service/src/service.ts index 761de3da7f3..1addee05d51 100644 --- a/packages/wdio-browserstack-service/src/service.ts +++ b/packages/wdio-browserstack-service/src/service.ts @@ -149,22 +149,23 @@ export default class BrowserstackService implements Services.ServiceInstance { try { const sessionId = this._browser.sessionId - if (isBrowserstackSession(this._browser)) { - try { - this._accessibilityHandler = new AccessibilityHandler( - this._browser, - this._caps, - this._isAppAutomate(), - this._config.framework, - this._accessibility, - this._options.accessibilityOptions - ) - await this._accessibilityHandler.before(sessionId) + try { + this._accessibilityHandler = new AccessibilityHandler( + this._browser, + this._caps, + this._options, + this._isAppAutomate(), + this._config, + this._config.framework, + this._accessibility, + this._turboScale, + this._options.accessibilityOptions + ) + await this._accessibilityHandler.before(sessionId) - Listener.setAccessibilityOptions(this._options.accessibilityOptions) - } catch (err) { - BStackLogger.error(`[Accessibility Test Run] Error in service class before function: ${err}`) - } + Listener.setAccessibilityOptions(this._options.accessibilityOptions) + } catch (err) { + BStackLogger.error(`[Accessibility Test Run] Error in service class before function: ${err}`) } if (shouldProcessEventForTesthub('')) { diff --git a/packages/wdio-browserstack-service/src/util.ts b/packages/wdio-browserstack-service/src/util.ts index 8e5f33bea15..e6f1b51d8e7 100644 --- a/packages/wdio-browserstack-service/src/util.ts +++ b/packages/wdio-browserstack-service/src/util.ts @@ -21,7 +21,6 @@ import * as PERFORMANCE_SDK_EVENTS from './instrumentation/performance/constants import { logBuildError, handleErrorForObservability, handleErrorForAccessibility, getProductMapForBuildStartCall } from './testHub/utils.js' import type BrowserStackConfig from './config.js' import type { Errors } from './testHub/utils.js' - import type { UserConfig, UploadType, BrowserstackConfig, BrowserstackOptions, LaunchResponse } from './types.js' import type { ITestCaseHookParameter } from './cucumber-types.js' import { @@ -328,9 +327,11 @@ export const processAccessibilityResponse = (response: LaunchResponse) => { if (response.accessibility.options) { const { accessibilityToken, pollingTimeout, scannerVersion } = jsonifyAccessibilityArray(response.accessibility.options.capabilities, 'name', 'value') + const result = jsonifyAccessibilityArray(response.accessibility.options.capabilities, 'name', 'value') const scriptsJson = { 'scripts': jsonifyAccessibilityArray(response.accessibility.options.scripts, 'name', 'command'), - 'commands': response.accessibility.options.commandsToWrap.commands + 'commands': response.accessibility.options.commandsToWrap.commands, + 'nonBStackInfraA11yChromeOptions': result['goog:chromeOptions'] } if (scannerVersion) { process.env.BSTACK_A11Y_SCANNER_VERSION = scannerVersion as string @@ -398,6 +399,11 @@ export const launchTestSession = PerformanceTester.measureWrapper(PERFORMANCE_SD config: {} } + if (accessibilityAutomation && (isTurboScale(options) || data.browserstackAutomation === false)){ + data.accessibility.settings ??= {} + data.accessibility.settings['includeEncodedExtension'] = true + } + try { if (Object.keys(CrashReporter.userConfigForReporting).length === 0) { CrashReporter.userConfigForReporting = process.env.USER_CONFIG_FOR_REPORTING !== undefined ? JSON.parse(process.env.USER_CONFIG_FOR_REPORTING) : {} @@ -420,6 +426,7 @@ export const launchTestSession = PerformanceTester.measureWrapper(PERFORMANCE_SD body: JSON.stringify(data) }) const jsonResponse: LaunchResponse = await response.json() + delete data?.accessibility?.settings?.includeEncodedExtension BStackLogger.debug(`[Start_Build] Success response: ${JSON.stringify(jsonResponse)}`) process.env[TESTOPS_BUILD_COMPLETED_ENV] = 'true' if (jsonResponse.jwt) { @@ -486,6 +493,20 @@ export const validateCapsWithA11y = (deviceName?: any, platformMeta?: { [key: st return false } +export const validateCapsWithNonBstackA11y = (browserName?: string | undefined, browserVersion?:string | undefined ) => { + + if (browserName?.toLowerCase() !== 'chrome') { + BStackLogger.warn('Accessibility Automation will run only on Chrome browsers.') + return false + } + if ( !isUndefined(browserVersion) && !(browserVersion === 'latest' || parseFloat(browserVersion + '') > 100)) { + BStackLogger.warn('Accessibility Automation will run only on Chrome browser version greater than 100.') + return false + } + return true + +} + export const shouldScanTestForAccessibility = (suiteTitle: string | undefined, testTitle: string, accessibilityOptions?: { [key: string]: string; }, world?: { [key: string]: unknown; }, isCucumber?: boolean ) => { try { const includeTags = Array.isArray(accessibilityOptions?.includeTagsInTestingScope) ? accessibilityOptions?.includeTagsInTestingScope : [] @@ -551,10 +572,6 @@ export const _getParamsForAppAccessibility = ( commandName?: string ): { thTestR /* eslint-disable @typescript-eslint/no-explicit-any */ export const performA11yScan = async (isAppAutomate: boolean, browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser, isBrowserStackSession?: boolean, isAccessibility?: boolean | string, commandName?: string) : Promise<{ [key: string]: any; } | undefined> => { - if (!isBrowserStackSession) { - BStackLogger.warn('Not a BrowserStack Automate session, cannot perform Accessibility scan.') - return // since we are running only on Automate as of now - } if (!isAccessibilityAutomationSession(isAccessibility)) { BStackLogger.warn('Not an Accessibility Automation session, cannot perform Accessibility scan.') @@ -1640,3 +1657,43 @@ export function getBooleanValueFromString(value: string | undefined): boolean { return ['true'].includes(value.trim().toLowerCase()) } +export function mergeDeep(target: Record, ...sources: any[]): Record { + if (!sources.length) {return target} + const source = sources.shift() + + if (isObject(target) && isObject(source)) { + for (const key in source) { + const sourceValue = source[key] + const targetValue = target[key] + + if (isObject(sourceValue)) { + if (!targetValue || !isObject(targetValue)) { + target[key] = {} + } + mergeDeep(target[key], sourceValue) + } else { + target[key] = sourceValue + } + } + } + + return mergeDeep(target, ...sources) +} + +export function mergeChromeOptions(base: Capabilities.ChromeOptions, override: Partial): Capabilities.ChromeOptions { + const merged: Capabilities.ChromeOptions = { ...base } + + if (override.args) { + merged.args = [...(base.args || []), ...override.args] + } + + if (override.extensions) { + merged.extensions = [...(base.extensions || []), ...override.extensions] + } + + if (override.prefs) { + merged.prefs = mergeDeep({ ...(base.prefs || {}) }, override.prefs) + } + return merged +} + From 80689d9b7abed9f270f7dd7753e225bf50ded222 Mon Sep 17 00:00:00 2001 From: Bhargavi-BS Date: Fri, 16 May 2025 18:26:40 +0530 Subject: [PATCH 2/8] added changes --- packages/wdio-browserstack-service/src/util.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/wdio-browserstack-service/src/util.ts b/packages/wdio-browserstack-service/src/util.ts index e6f1b51d8e7..c4e2c54bf5f 100644 --- a/packages/wdio-browserstack-service/src/util.ts +++ b/packages/wdio-browserstack-service/src/util.ts @@ -597,10 +597,6 @@ export const performA11yScan = async (isAppAutomate: boolean, browser: Webdriver } export const getA11yResults = PerformanceTester.measureWrapper(PERFORMANCE_SDK_EVENTS.A11Y_EVENTS.GET_RESULTS, async (isAppAutomate: boolean, browser: WebdriverIO.Browser, isBrowserStackSession?: boolean, isAccessibility?: boolean | string) : Promise> => { - if (!isBrowserStackSession) { - BStackLogger.warn('Not a BrowserStack Automate session, cannot retrieve Accessibility results.') - return [] // since we are running only on Automate as of now - } if (!isAccessibilityAutomationSession(isAccessibility)) { BStackLogger.warn('Not an Accessibility Automation session, cannot retrieve Accessibility results.') @@ -680,9 +676,6 @@ const getAppA11yResultResponse = async (apiUrl: string, isAppAutomate: boolean, } export const getA11yResultsSummary = PerformanceTester.measureWrapper(PERFORMANCE_SDK_EVENTS.A11Y_EVENTS.GET_RESULTS_SUMMARY, async (isAppAutomate: boolean, browser: WebdriverIO.Browser, isBrowserStackSession?: boolean, isAccessibility?: boolean | string) : Promise<{ [key: string]: any; }> => { - if (!isBrowserStackSession) { - return {} // since we are running only on Automate as of now - } if (!isAccessibilityAutomationSession(isAccessibility)) { BStackLogger.warn('Not an Accessibility Automation session, cannot retrieve Accessibility results summary.') From 606b1fcf5919d7a93e1c14ce3b4e695618fa3c7f Mon Sep 17 00:00:00 2001 From: Bhargavi-BS Date: Thu, 29 May 2025 16:19:33 +0530 Subject: [PATCH 3/8] unit test changes --- .../tests/accessibility-handler.test.ts | 32 ++++++++++++------- .../tests/accessibility-scripts.test.ts | 11 +++++-- .../tests/app-accessibility-handler.test.ts | 13 ++++++-- .../tests/util.test.ts | 12 ------- 4 files changed, 40 insertions(+), 28 deletions(-) diff --git a/packages/wdio-browserstack-service/tests/accessibility-handler.test.ts b/packages/wdio-browserstack-service/tests/accessibility-handler.test.ts index 8755707c377..c31156bf466 100644 --- a/packages/wdio-browserstack-service/tests/accessibility-handler.test.ts +++ b/packages/wdio-browserstack-service/tests/accessibility-handler.test.ts @@ -6,6 +6,8 @@ import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest' import logger from '@wdio/logger' import AccessibilityHandler from '../src/accessibility-handler.js' +import type { BrowserstackConfig, BrowserstackOptions } from '../src/types.js' +import type { Options } from '@wdio/types' import * as utils from '../src/util.js' import type { Capabilities } from '@wdio/types' import * as bstackLogger from '../src/bstackLogger.js' @@ -13,6 +15,8 @@ import * as bstackLogger from '../src/bstackLogger.js' const log = logger('test') let accessibilityHandler: AccessibilityHandler let browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser +let options: BrowserstackConfig & BrowserstackOptions +let config : Options.Testrunner let caps: Capabilities.RemoteCapability let accessibilityOpts: { [key: string]: any; } @@ -65,7 +69,11 @@ beforeEach(() => { osVersion: 'Catalina', accessibility: true } } as Capabilities.RemoteCapability - accessibilityHandler = new AccessibilityHandler(browser, caps, false, 'framework', true) + options = { + accessibility: true + } + config = {} + accessibilityHandler = new AccessibilityHandler(browser, caps, options, false, config, 'framework', true) }) it('should initialize correctly', () => { @@ -76,7 +84,7 @@ it('should initialize correctly', () => { needsReview: true } } - accessibilityHandler = new AccessibilityHandler(browser, caps, false, 'framework', true, accessibilityOpts) + accessibilityHandler = new AccessibilityHandler(browser, caps, options, false, config, 'framework', true, false, accessibilityOpts) expect(accessibilityHandler['_platformA11yMeta']).toEqual({ browser_name: 'chrome', browser_version: 'latest', os_name: 'OS X', os_version: 'Catalina' }) expect(accessibilityHandler['_accessibility']).toEqual(true) expect(accessibilityHandler['_caps']).toEqual(caps) @@ -87,11 +95,12 @@ describe('before', () => { // let _getCapabilityValueSpy const isBrowserstackSessionSpy = vi.spyOn(utils, 'isBrowserstackSession') const getA11yResultsSummarySpy = vi.spyOn(utils, 'getA11yResultsSummary') + const shouldAddServiceVersionSpy = vi.spyOn(utils, 'shouldAddServiceVersion') const getA11yResultsSpy = vi.spyOn(utils, 'getA11yResults') const isAccessibilityAutomationSessionSpy = vi.spyOn(utils, 'isAccessibilityAutomationSession') beforeEach(() => { - accessibilityHandler = new AccessibilityHandler(browser, caps, false, 'framework', true, accessibilityOpts) + accessibilityHandler = new AccessibilityHandler(browser, caps, options, false, config, 'framework', true, false, accessibilityOpts) getA11yResultsSpy.mockClear() isBrowserstackSessionSpy.mockClear() getA11yResultsSummarySpy.mockClear() @@ -101,24 +110,25 @@ describe('before', () => { it('calls isBrowserstackSession', async () => { isBrowserstackSessionSpy.mockReturnValue(true) await accessibilityHandler.before('session123') - expect(isBrowserstackSessionSpy).toBeCalledTimes(1) + expect(isBrowserstackSessionSpy).toBeCalledTimes(0) }) it('isBrowserstackSession returns true', async () => { isBrowserstackSessionSpy.mockReturnValue(true) await accessibilityHandler.before('session123') - expect(isBrowserstackSessionSpy).toBeCalledTimes(1) + expect(isBrowserstackSessionSpy).toBeCalledTimes(0) }) it('calls isAccessibilityAutomationSession', async () => { isBrowserstackSessionSpy.mockReturnValue(true) await accessibilityHandler.before('session123') - expect(isAccessibilityAutomationSessionSpy).toBeCalledTimes(1) + expect(isAccessibilityAutomationSessionSpy).toBeCalledTimes(2) }) it('calls validateCapsWithA11y', async () => { const _getCapabilityValueSpy = vi.spyOn(accessibilityHandler, '_getCapabilityValue').mockReturnValue(true) const validateCapsWithA11ySpy = vi.spyOn(utils, 'validateCapsWithA11y') + shouldAddServiceVersionSpy.mockReturnValue(true) isBrowserstackSessionSpy.mockReturnValue(true) isAccessibilityAutomationSessionSpy.mockReturnValue(true) await accessibilityHandler.before('session123') @@ -148,7 +158,7 @@ describe('beforeScenario', () => { let executeSpy: any beforeEach(() => { - accessibilityHandler = new AccessibilityHandler(browser, caps, false, 'framework', true, accessibilityOpts) + accessibilityHandler = new AccessibilityHandler(browser, caps, options, false, config, 'framework', true, false, accessibilityOpts) executeAsyncSpy = vi.spyOn((browser as WebdriverIO.Browser), 'executeAsync') executeSpy = vi.spyOn((browser as WebdriverIO.Browser), 'execute') vi.spyOn(utils, 'isBrowserstackSession').mockReturnValue(true) @@ -384,7 +394,7 @@ describe('beforeTest', () => { describe('mocha', () => { beforeEach(() => { - accessibilityHandler = new AccessibilityHandler(browser, caps, false, 'mocha', true, accessibilityOpts) + accessibilityHandler = new AccessibilityHandler(browser, caps, options, false, config, 'mocha', true, false, accessibilityOpts) vi.spyOn(utils, 'isBrowserstackSession').mockReturnValue(true) vi.spyOn(utils, 'isAccessibilityAutomationSession').mockReturnValue(true) vi.spyOn(utils, 'getUniqueIdentifier').mockReturnValue('test title') @@ -445,7 +455,7 @@ describe('beforeTest', () => { describe('jasmine', () => { let isBrowserstackSession: any beforeEach(() => { - accessibilityHandler = new AccessibilityHandler(browser, caps, false, 'jasmine', true, accessibilityOpts) + accessibilityHandler = new AccessibilityHandler(browser, caps, options, false, config, 'jasmine', true, false, accessibilityOpts) isBrowserstackSession = vi.spyOn(utils, 'isBrowserstackSession').mockReturnValue(true) }) @@ -464,7 +474,7 @@ describe('afterTest', () => { let accessibilityHandler: AccessibilityHandler beforeEach(() => { - accessibilityHandler = new AccessibilityHandler(browser, caps, false, 'mocha', true, accessibilityOpts) + accessibilityHandler = new AccessibilityHandler(browser, caps, options, false, config, 'mocha', true, false, accessibilityOpts) executeAsyncSpy = vi.spyOn((browser as WebdriverIO.Browser), 'executeAsync') vi.spyOn(utils, 'isBrowserstackSession').mockReturnValue(true) vi.spyOn(utils, 'isAccessibilityAutomationSession').mockReturnValue(true) @@ -517,7 +527,7 @@ describe('getIdentifier', () => { let getUniqueIdentifierForCucumberSpy: any beforeEach(() => { - accessibilityHandler = new AccessibilityHandler(browser, caps, false, 'framework', true, accessibilityOpts) + accessibilityHandler = new AccessibilityHandler(browser, caps, options, false, config, 'framework', true, false, accessibilityOpts) getUniqueIdentifierSpy = vi.spyOn(utils, 'getUniqueIdentifier') getUniqueIdentifierForCucumberSpy = vi.spyOn(utils, 'getUniqueIdentifierForCucumber') diff --git a/packages/wdio-browserstack-service/tests/accessibility-scripts.test.ts b/packages/wdio-browserstack-service/tests/accessibility-scripts.test.ts index 8f5951851ca..609d4b07242 100644 --- a/packages/wdio-browserstack-service/tests/accessibility-scripts.test.ts +++ b/packages/wdio-browserstack-service/tests/accessibility-scripts.test.ts @@ -6,7 +6,7 @@ import AccessibilityScripts from '../src/scripts/accessibility-scripts.js' vi.mock('node:fs', () => ({ default: { - readFileSync: vi.fn().mockReturnValue('{"scripts": {"scan": "scan", "getResults": "getResults", "getResultsSummary": "getResultsSummary", "saveResults": "saveResults"}, "commands": [{"command": "command1"}, {"command": "command2"}]}'), + readFileSync: vi.fn().mockReturnValue('{"scripts": {"scan": "scan", "getResults": "getResults", "getResultsSummary": "getResultsSummary", "saveResults": "saveResults"}, "commands": [{"command": "command1"}, {"command": "command2"}], "nonBStackInfraA11yChromeOptions": {"extension": ["extension1"]}}'), writeFileSync: vi.fn(), existsSync: vi.fn().mockReturnValue(true), mkdirSync: vi.fn(), @@ -34,6 +34,7 @@ describe('AccessibilityScripts', () => { expect(accessibilityScripts.getResultsSummary).to.equal('getResultsSummary') expect(accessibilityScripts.saveTestResults).to.equal('saveResults') expect(accessibilityScripts.commandsToWrap).to.deep.equal([{ command: 'command1' }, { command: 'command2' }]) + expect(accessibilityScripts.ChromeExtension).to.deep.equal({ extension: ['extension1'] }) }) it('should update data', () => { @@ -45,15 +46,17 @@ describe('AccessibilityScripts', () => { getResultsSummary: 'getResultsSummary', saveResults: 'saveResults', }, + nonBStackInfraA11yChromeOptions: { extension: ['extension1'] } } as unknown - accessibilityScripts.update(data as { commands: [any]; scripts: { scan: null; getResults: null; getResultsSummary: null; saveResults: null } }) + accessibilityScripts.update(data as { commands: [any]; scripts: { scan: null; getResults: null; getResultsSummary: null; saveResults: null }; nonBStackInfraA11yChromeOptions:{} }) expect(accessibilityScripts.performScan).to.equal('scan') expect(accessibilityScripts.getResults).to.equal('getResults') expect(accessibilityScripts.getResultsSummary).to.equal('getResultsSummary') expect(accessibilityScripts.saveTestResults).to.equal('saveResults') expect(accessibilityScripts.commandsToWrap).to.deep.equal([{ command: 'command1' }, { command: 'command2' }]) + expect(accessibilityScripts.ChromeExtension).to.deep.equal({ extension: ['extension1'] }) }) it('should store data to file', () => { @@ -63,6 +66,7 @@ describe('AccessibilityScripts', () => { accessibilityScripts.getResultsSummary = 'getResultsSummary' accessibilityScripts.saveTestResults = 'saveResults' accessibilityScripts.commandsToWrap = [{ command: 'command1' }, { command: 'command2' }] + accessibilityScripts.ChromeExtension = { extension: ['extension1'] } const writeFileSyncStub = vi.spyOn(fs, 'writeFileSync') accessibilityScripts.store() @@ -76,7 +80,8 @@ describe('AccessibilityScripts', () => { getResults: accessibilityScripts.getResults, getResultsSummary: accessibilityScripts.getResultsSummary, saveResults: accessibilityScripts.saveTestResults, - } + }, + nonBStackInfraA11yChromeOptions: accessibilityScripts.ChromeExtension, }) ) }) diff --git a/packages/wdio-browserstack-service/tests/app-accessibility-handler.test.ts b/packages/wdio-browserstack-service/tests/app-accessibility-handler.test.ts index b4493015da8..bc8f631b314 100644 --- a/packages/wdio-browserstack-service/tests/app-accessibility-handler.test.ts +++ b/packages/wdio-browserstack-service/tests/app-accessibility-handler.test.ts @@ -3,6 +3,8 @@ import { describe, expect, it, vi, beforeEach } from 'vitest' import logger from '@wdio/logger' import AccessibilityHandler from '../src/accessibility-handler.js' +import type { BrowserstackConfig, BrowserstackOptions } from '../src/types.js' +import type { Options } from '@wdio/types' import * as utils from '../src/util.js' import type { Capabilities } from '@wdio/types' import * as bstackLogger from '../src/bstackLogger.js' @@ -11,6 +13,8 @@ const log = logger('test') let accessibilityHandler: AccessibilityHandler let browser: WebdriverIO.Browser let caps: Capabilities.RemoteCapability +let options: BrowserstackConfig & BrowserstackOptions +let config : Options.Testrunner let accessibilityOpts: { [key: string]: any } vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger'))) @@ -54,7 +58,12 @@ describe('App Automate Accessibility Handler', () => { } } - accessibilityHandler = new AccessibilityHandler(browser, caps, true, 'mocha', true, accessibilityOpts) + options = { + accessibility: true + } + config = {} + + accessibilityHandler = new AccessibilityHandler(browser, caps, options, true, config, 'mocha', true, false, accessibilityOpts) }) describe('initialization', () => { @@ -89,7 +98,7 @@ describe('App Automate Accessibility Handler', () => { await accessibilityHandler.before('app123') - expect(isBrowserstackSessionSpy).toBeCalledTimes(1) + expect(isBrowserstackSessionSpy).toBeCalledTimes(0) expect(isAppAccessibilityAutomationSessionSpy).toBeCalledTimes(1) expect(validateCapsWithAppA11ySpy).toBeCalledTimes(1) }) diff --git a/packages/wdio-browserstack-service/tests/util.test.ts b/packages/wdio-browserstack-service/tests/util.test.ts index 4a05c47407c..59cd166e87c 100644 --- a/packages/wdio-browserstack-service/tests/util.test.ts +++ b/packages/wdio-browserstack-service/tests/util.test.ts @@ -1675,18 +1675,6 @@ describe('performA11yScan', () => { logInfoMock = vi.spyOn(log, 'warn') }) - it('should return early if not a BrowserStack session', async () => { - browser = { - execute: async () => ({ success: true }), - executeAsync: async () => ({ success: true }), - } as unknown as WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser - - const result = await performA11yScan(false, browser, false, true) - expect(result).toBeUndefined() - expect(logInfoMock.mock.calls[0][0]) - .toContain('Not a BrowserStack Automate session, cannot perform Accessibility scan.') - }) - it('should return early if not an Accessibility Automation session', async () => { browser = { execute: async () => ({ success: true }), From 9224da9e87f1aa36be9e6d87ed2836648255314e Mon Sep 17 00:00:00 2001 From: Bhargavi-BS Date: Mon, 2 Jun 2025 19:05:23 +0530 Subject: [PATCH 4/8] review changes & unit tests added --- .../src/accessibility-handler.ts | 1 + .../wdio-browserstack-service/src/launcher.ts | 58 ++++++----- .../tests/accessibility-handler.test.ts | 8 ++ .../tests/launcher.test.ts | 26 +++++ .../tests/util.test.ts | 99 +++++++++++++++++-- 5 files changed, 156 insertions(+), 36 deletions(-) diff --git a/packages/wdio-browserstack-service/src/accessibility-handler.ts b/packages/wdio-browserstack-service/src/accessibility-handler.ts index 8fe851e7956..1ce2cdc319b 100644 --- a/packages/wdio-browserstack-service/src/accessibility-handler.ts +++ b/packages/wdio-browserstack-service/src/accessibility-handler.ts @@ -116,6 +116,7 @@ class _AccessibilityHandler { this._sessionId = sessionId 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))){ 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/launcher.ts b/packages/wdio-browserstack-service/src/launcher.ts index a138c3d1fa8..5ca54f72f83 100644 --- a/packages/wdio-browserstack-service/src/launcher.ts +++ b/packages/wdio-browserstack-service/src/launcher.ts @@ -298,32 +298,10 @@ export default class BrowserstackLauncherService implements Services.ServiceInst }, this.browserStackConfig, this._accessibilityAutomation) } + //added checks for Accessibility running on non-bstack infra if (isAccessibilityAutomationSession(this._accessibilityAutomation) && (process.env.BROWSERSTACK_TURBOSCALE || !shouldAddServiceVersion(this._config, this._options.testObservability))){ - if (Array.isArray(capabilities)) { - capabilities - .flatMap((c) => { - - if (Object.values(c).length > 0 && Object.values(c).every(c => typeof c === 'object' && c.capabilities)) { - return Object.values(c).map((o) => o.capabilities) as WebdriverIO.Capabilities[] - } - return c as WebdriverIO.Capabilities - }) - .forEach((capability: WebdriverIO.Capabilities) => { - if (validateCapsWithNonBstackA11y(capability['browserName'], capability['browserVersion'] )){ - const chromeOptions = capability['goog:chromeOptions'] as unknown as Capabilities.ChromeOptions - const overrideOptions: Partial = accessibilityScripts.ChromeExtension - if (chromeOptions){ - - const finalChromeOptions = mergeChromeOptions(chromeOptions, overrideOptions) - capability['goog:chromeOptions'] = finalChromeOptions - } else { - capability['goog:chromeOptions'] = overrideOptions - - } - - } - }) - } + const overrideOptions: Partial = accessibilityScripts.ChromeExtension + this._updateObjectTypeCaps(capabilities, 'goog:chromeOptions', overrideOptions) } if (buildStartResponse?.accessibility) { @@ -604,7 +582,7 @@ export default class BrowserstackLauncherService implements Services.ServiceInst } } - _updateObjectTypeCaps(capabilities?: Capabilities.TestrunnerCapabilities, capType?: string, value?: { [key: string]: unknown }) { + _updateObjectTypeCaps(capabilities?: Capabilities.TestrunnerCapabilities | WebdriverIO.Capabilities, capType?: string, value?: { [key: string]: unknown }) { try { if (Array.isArray(capabilities)) { capabilities @@ -619,6 +597,19 @@ export default class BrowserstackLauncherService implements Services.ServiceInst return c as WebdriverIO.Capabilities }) .forEach((capability: WebdriverIO.Capabilities) => { + if (validateCapsWithNonBstackA11y(capability.browserName, capability.browserVersion )){ + if (capType === 'goog:chromeOptions' && value) { + + const chromeOptions = capability['goog:chromeOptions'] as unknown as Capabilities.ChromeOptions + if (chromeOptions){ + const finalChromeOptions = mergeChromeOptions(chromeOptions, value) + capability['goog:chromeOptions'] = finalChromeOptions + } else { + capability['goog:chromeOptions'] = value + } + return + } + } if (!capability['bstack:options']) { const extensionCaps = Object.keys(capability).filter((cap) => cap.includes(':')) if (extensionCaps.length) { @@ -653,6 +644,21 @@ export default class BrowserstackLauncherService implements Services.ServiceInst }) } else if (typeof capabilities === 'object') { Object.entries(capabilities as Capabilities.RequestedMultiremoteCapabilities).forEach(([, caps]) => { + if (validateCapsWithNonBstackA11y( + (caps.capabilities as WebdriverIO.Capabilities).browserName, + (caps.capabilities as WebdriverIO.Capabilities).browserVersion + )) { + if (capType === 'goog:chromeOptions' && value) { + const chromeOptions = (caps.capabilities as WebdriverIO.Capabilities)['goog:chromeOptions'] as unknown as Capabilities.ChromeOptions + if (chromeOptions) { + const finalChromeOptions = mergeChromeOptions(chromeOptions, value); + (caps.capabilities as WebdriverIO.Capabilities)['goog:chromeOptions'] = finalChromeOptions + } else { + (caps.capabilities as WebdriverIO.Capabilities)['goog:chromeOptions'] = value + } + return + } + } if (!(caps.capabilities as WebdriverIO.Capabilities)['bstack:options']) { const extensionCaps = Object.keys(caps.capabilities).filter((cap) => cap.includes(':')) if (extensionCaps.length) { diff --git a/packages/wdio-browserstack-service/tests/accessibility-handler.test.ts b/packages/wdio-browserstack-service/tests/accessibility-handler.test.ts index c31156bf466..a381b4c621d 100644 --- a/packages/wdio-browserstack-service/tests/accessibility-handler.test.ts +++ b/packages/wdio-browserstack-service/tests/accessibility-handler.test.ts @@ -136,6 +136,14 @@ describe('before', () => { expect(validateCapsWithA11ySpy).toBeCalledTimes(1) }) + it('calls validateCapsWithNonBstackA11y', async () => { + const validateCapsWithNonBstackA11ySpy = vi.spyOn(utils, 'validateCapsWithNonBstackA11y') + shouldAddServiceVersionSpy.mockReturnValue(false) + isAccessibilityAutomationSessionSpy.mockReturnValue(true) + await accessibilityHandler.before('session123') + expect(validateCapsWithNonBstackA11ySpy).toBeCalledTimes(1) + }) + it('calls getA11yResultsSummary', async () => { isBrowserstackSessionSpy.mockReturnValue(true) isAccessibilityAutomationSessionSpy.mockReturnValue(true) diff --git a/packages/wdio-browserstack-service/tests/launcher.test.ts b/packages/wdio-browserstack-service/tests/launcher.test.ts index b65cc9ad090..26b61f535df 100644 --- a/packages/wdio-browserstack-service/tests/launcher.test.ts +++ b/packages/wdio-browserstack-service/tests/launcher.test.ts @@ -944,6 +944,32 @@ describe('_updateObjectTypeCaps', () => { expect(caps.chromeBrowser.capabilities).toEqual({ 'browserstack.wdioService': pkg.version, 'browserstack.accessibilityOptions': { includeIssueType: { bestPractice: true, needsReview: true } } }) }) + it('should set chromeOptions if capType is goog:chromeOptions and no existing options are present', () => { + const value = { args: ['--disable-gpu'] } + vi.spyOn(utils, 'validateCapsWithNonBstackA11y').mockImplementation(() => true) + const service = new BrowserstackLauncher(options as BrowserstackConfig & Options.Testrunner, caps, config) + service._updateObjectTypeCaps(caps, 'goog:chromeOptions', value) + expect(caps[0]['goog:chromeOptions']).toEqual(value) + }) + + it('should merge chromeOptions if capType is goog:chromeOptions and value is provided', () => { + const caps: any = [{ 'goog:chromeOptions': { args: ['--headless'] } }] + const value = { args: ['--disable-gpu'] } + vi.spyOn(utils, 'validateCapsWithNonBstackA11y').mockImplementation(() => true) + const service = new BrowserstackLauncher(options as BrowserstackConfig & Options.Testrunner, caps, config) + service._updateObjectTypeCaps(caps, 'goog:chromeOptions', value) + expect(caps[0]['goog:chromeOptions']).toEqual({ args: ['--headless', '--disable-gpu'] }) + }) + + it('should update goog:chromeOptions in caps object if value is provided', () => { + const caps = { chromeBrowser: { capabilities: { 'goog:chromeOptions': { args: ['--headless'] }, 'bstack:options': {} } } } + const value = { args: ['--disable-gpu'] } + vi.spyOn(utils, 'validateCapsWithNonBstackA11y').mockImplementation(() => true) + const service = new BrowserstackLauncher(options as BrowserstackConfig & Options.Testrunner, caps, config) + service._updateObjectTypeCaps(caps, 'goog:chromeOptions', value) + expect(caps.chromeBrowser.capabilities['goog:chromeOptions']).toEqual({ args: ['--headless', '--disable-gpu'] }) + }) + it('should delete accessibilityOptions in caps array if value not passed in _updateObjectTypeCaps', () => { const caps = [{ 'bstack:options': { accessibilityOptions: { wcagVersion: 'wcag2a' } } }] const service = new BrowserstackLauncher(options as any, caps as any, config) diff --git a/packages/wdio-browserstack-service/tests/util.test.ts b/packages/wdio-browserstack-service/tests/util.test.ts index 59cd166e87c..6607ecb2c47 100644 --- a/packages/wdio-browserstack-service/tests/util.test.ts +++ b/packages/wdio-browserstack-service/tests/util.test.ts @@ -36,6 +36,7 @@ import { getFailureObject, validateCapsWithAppA11y, validateCapsWithA11y, + validateCapsWithNonBstackA11y, shouldScanTestForAccessibility, isAccessibilityAutomationSession, isAppAccessibilityAutomationSession, @@ -52,6 +53,8 @@ import { performA11yScan, getAppA11yResults, getAppA11yResultsSummary, + mergeDeep, + mergeChromeOptions } from '../src/util.js' import * as bstackLogger from '../src/bstackLogger.js' import { BROWSERSTACK_OBSERVABILITY, TESTOPS_BUILD_COMPLETED_ENV, BROWSERSTACK_TESTHUB_JWT, BROWSERSTACK_ACCESSIBILITY } from '../src/constants.js' @@ -1058,6 +1061,41 @@ describe('validateCapsWithA11y', () => { }) }) +describe('validateCapsWithNonBstackA11y', () => { + let logInfoMock: any + beforeEach(() => { + logInfoMock = vi.spyOn(log, 'warn') + }) + + it('returns false if browser is not chrome', async () => { + + const browserName = 'safari' + const browserVersion = 'latest' + + expect(validateCapsWithNonBstackA11y(browserName, browserVersion)).toEqual(false) + expect(logInfoMock.mock.calls[0][0]) + .toContain('Accessibility Automation will run only on Chrome browsers.') + }) + + it('returns false if browser version is lesser than 100', async () => { + + const browserName = 'chrome' + const browserVersion = '98' + + expect(validateCapsWithNonBstackA11y(browserName, browserVersion)).toEqual(false) + expect(logInfoMock.mock.calls[0][0]) + .toContain('Accessibility Automation will run only on Chrome browser version greater than 100.') + }) + + it('returns true if validation done', async () => { + const browserName = 'chrome' + const browserVersion = 'latest' + + expect(validateCapsWithNonBstackA11y(browserName, browserVersion)).toEqual(true) + }) + +}) + describe('shouldScanTestForAccessibility', () => { const cucumberWorldObj = { pickle: { @@ -1137,11 +1175,6 @@ describe('getA11yResults', () => { on: vi.fn(), } as unknown as WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser - it('return false if BrowserStack Session', async () => { - const result: any = await utils.getA11yResults((browser as WebdriverIO.Browser), false, false) - expect(result).toEqual([]) - }) - it('return success object if ally token defined and no error in response data', async () => { vi.spyOn(utils, 'isAccessibilityAutomationSession').mockReturnValue(false) const result: any = await utils.getA11yResults((browser as WebdriverIO.Browser), true, false) @@ -1190,11 +1223,6 @@ describe('getA11yResultsSummary', () => { on: vi.fn(), } as unknown as WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser - it('return false if BrowserStack Session', async () => { - const result: any = await utils.getA11yResultsSummary((browser as WebdriverIO.Browser), false, false) - expect(result).toEqual({}) - }) - it('return success object if ally token defined and no error in response data', async () => { vi.spyOn(utils, 'isAccessibilityAutomationSession').mockReturnValue(false) const result: any = await utils.getA11yResultsSummary((browser as WebdriverIO.Browser), true, false) @@ -1939,4 +1967,55 @@ describe('getAppA11yResultsSummary', () => { delete process.env.BSTACK_A11Y_JWT vi.clearAllMocks() }) + + describe('mergeDeep', () => { + it('should deeply merge two objects', () => { + const target = { a: 1, b: { c: 2 } } + const source = { b: { d: 3 }, e: 4 } + const result = mergeDeep(target, source) + + expect(result).toEqual({ + a: 1, + b: { c: 2, d: 3 }, + e: 4 + }) + }) + + it('should handle empty sources', () => { + const target = { a: 1 } + const result = mergeDeep(target) + + expect(result).toEqual({ a: 1 }) + }) + }) + + describe('mergeChromeOptions', () => { + it('should merge ChromeOptions args and extensions correctly', () => { + const base = { + args: ['--disable-gpu'], + extensions: ['ext1'], + prefs: { + homepage: 'https://example.com' + } + } + + const override = { + args: ['--headless'], + extensions: ['ext2'], + prefs: { + newtab: 'https://newtab.com' + } + } + + const result = mergeChromeOptions(base, override) + + expect(result.args).toEqual(['--disable-gpu', '--headless']) + expect(result.extensions).toEqual(['ext1', 'ext2']) + expect(result.prefs).toEqual({ + homepage: 'https://example.com', + newtab: 'https://newtab.com' + }) + }) + }) }) + From 57c051a12bc3575d8b38b8491c5128de5a0f6d13 Mon Sep 17 00:00:00 2001 From: Bhargavi-BS Date: Thu, 5 Jun 2025 18:51:01 +0530 Subject: [PATCH 5/8] Update packages/wdio-browserstack-service/src/launcher.ts Co-authored-by: Christian Bromann --- .../wdio-browserstack-service/src/launcher.ts | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/wdio-browserstack-service/src/launcher.ts b/packages/wdio-browserstack-service/src/launcher.ts index 5ca54f72f83..7d31d446ead 100644 --- a/packages/wdio-browserstack-service/src/launcher.ts +++ b/packages/wdio-browserstack-service/src/launcher.ts @@ -644,20 +644,21 @@ export default class BrowserstackLauncherService implements Services.ServiceInst }) } else if (typeof capabilities === 'object') { Object.entries(capabilities as Capabilities.RequestedMultiremoteCapabilities).forEach(([, caps]) => { - if (validateCapsWithNonBstackA11y( - (caps.capabilities as WebdriverIO.Capabilities).browserName, - (caps.capabilities as WebdriverIO.Capabilities).browserVersion - )) { - if (capType === 'goog:chromeOptions' && value) { - const chromeOptions = (caps.capabilities as WebdriverIO.Capabilities)['goog:chromeOptions'] as unknown as Capabilities.ChromeOptions - if (chromeOptions) { - const finalChromeOptions = mergeChromeOptions(chromeOptions, value); - (caps.capabilities as WebdriverIO.Capabilities)['goog:chromeOptions'] = finalChromeOptions - } else { - (caps.capabilities as WebdriverIO.Capabilities)['goog:chromeOptions'] = value - } - return + if ( + validateCapsWithNonBstackA11y( + (caps.capabilities as WebdriverIO.Capabilities).browserName, + (caps.capabilities as WebdriverIO.Capabilities).browserVersion + ) && + capType === 'goog:chromeOptions' && value + ) { + const chromeOptions = (caps.capabilities as WebdriverIO.Capabilities)['goog:chromeOptions'] as unknown as Capabilities.ChromeOptions + if (chromeOptions) { + const finalChromeOptions = mergeChromeOptions(chromeOptions, value); + (caps.capabilities as WebdriverIO.Capabilities)['goog:chromeOptions'] = finalChromeOptions + } else { + (caps.capabilities as WebdriverIO.Capabilities)['goog:chromeOptions'] = value } + return } if (!(caps.capabilities as WebdriverIO.Capabilities)['bstack:options']) { const extensionCaps = Object.keys(caps.capabilities).filter((cap) => cap.includes(':')) From d9ab95892588d9abcf8c3318bde80f42765d4d09 Mon Sep 17 00:00:00 2001 From: Bhargavi-BS Date: Thu, 5 Jun 2025 18:51:12 +0530 Subject: [PATCH 6/8] Update packages/wdio-browserstack-service/src/util.ts Co-authored-by: Christian Bromann --- packages/wdio-browserstack-service/src/util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wdio-browserstack-service/src/util.ts b/packages/wdio-browserstack-service/src/util.ts index c4e2c54bf5f..e76bd2d3252 100644 --- a/packages/wdio-browserstack-service/src/util.ts +++ b/packages/wdio-browserstack-service/src/util.ts @@ -499,7 +499,7 @@ export const validateCapsWithNonBstackA11y = (browserName?: string | undefined, BStackLogger.warn('Accessibility Automation will run only on Chrome browsers.') return false } - if ( !isUndefined(browserVersion) && !(browserVersion === 'latest' || parseFloat(browserVersion + '') > 100)) { + if (!isUndefined(browserVersion) && !(browserVersion === 'latest' || parseFloat(browserVersion + '') > 100)) { BStackLogger.warn('Accessibility Automation will run only on Chrome browser version greater than 100.') return false } From 37df5f9cb78a19c0bb44873ee99cdfb87192040f Mon Sep 17 00:00:00 2001 From: Bhargavi-BS Date: Thu, 5 Jun 2025 18:53:35 +0530 Subject: [PATCH 7/8] Update packages/wdio-browserstack-service/src/launcher.ts Co-authored-by: Christian Bromann --- .../wdio-browserstack-service/src/launcher.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/wdio-browserstack-service/src/launcher.ts b/packages/wdio-browserstack-service/src/launcher.ts index 7d31d446ead..de15b7ee712 100644 --- a/packages/wdio-browserstack-service/src/launcher.ts +++ b/packages/wdio-browserstack-service/src/launcher.ts @@ -597,18 +597,18 @@ export default class BrowserstackLauncherService implements Services.ServiceInst return c as WebdriverIO.Capabilities }) .forEach((capability: WebdriverIO.Capabilities) => { - if (validateCapsWithNonBstackA11y(capability.browserName, capability.browserVersion )){ - if (capType === 'goog:chromeOptions' && value) { - - const chromeOptions = capability['goog:chromeOptions'] as unknown as Capabilities.ChromeOptions - if (chromeOptions){ - const finalChromeOptions = mergeChromeOptions(chromeOptions, value) - capability['goog:chromeOptions'] = finalChromeOptions - } else { - capability['goog:chromeOptions'] = value - } - return + if ( + validateCapsWithNonBstackA11y(capability.browserName, capability.browserVersion) && + capType === 'goog:chromeOptions' && value + ) { + const chromeOptions = capability['goog:chromeOptions'] as unknown as Capabilities.ChromeOptions + if (chromeOptions){ + const finalChromeOptions = mergeChromeOptions(chromeOptions, value) + capability['goog:chromeOptions'] = finalChromeOptions + } else { + capability['goog:chromeOptions'] = value } + return } if (!capability['bstack:options']) { const extensionCaps = Object.keys(capability).filter((cap) => cap.includes(':')) From d15122057623e90c3a71d8d810aa4bcd7cd4fcc8 Mon Sep 17 00:00:00 2001 From: Christian Bromann Date: Thu, 5 Jun 2025 08:06:27 -0700 Subject: [PATCH 8/8] Update packages/wdio-browserstack-service/src/accessibility-handler.ts --- .../src/accessibility-handler.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/wdio-browserstack-service/src/accessibility-handler.ts b/packages/wdio-browserstack-service/src/accessibility-handler.ts index 1ce2cdc319b..86f141ee919 100644 --- a/packages/wdio-browserstack-service/src/accessibility-handler.ts +++ b/packages/wdio-browserstack-service/src/accessibility-handler.ts @@ -117,10 +117,18 @@ 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))){ - if (validateCapsWithNonBstackA11y(this._platformA11yMeta.browser_name as string, this._platformA11yMeta?.browser_version as string)){ - this._accessibility = true - } + if ( + isAccessibilityAutomationSession(this._accessibility) && + ( + this._turboscale || + !shouldAddServiceVersion(this._config, this._options.testObservability) + ) && + validateCapsWithNonBstackA11y( + this._platformA11yMeta.browser_name as string, + this._platformA11yMeta?.browser_version as string + ) + ){ + this._accessibility = true } else { if (isAccessibilityAutomationSession(this._accessibility) && !this.isAppAutomate) { const deviceName = this._getCapabilityValue(this._caps, 'deviceName', 'device')