Skip to content

Commit 98ba397

Browse files
feat(browserstack-service): add accessibility support for Safari and Chrome for Testing (webdriverio#15208)
* added support for safari and cft * fixed lint errors * added try catch block for validateCapsWithNonBstackA11y * updated chromeForTesting version * updated version for safari * Copilot fix. --------- Co-authored-by: Tanmay Lokhande <tanmay.l@browserstack.com>
1 parent 526768c commit 98ba397

3 files changed

Lines changed: 167 additions & 29 deletions

File tree

packages/wdio-browserstack-service/src/constants.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,20 @@ export const EDS_URL = 'https://eds.browserstack.com'
7676

7777
export const SUPPORTED_BROWSERS_FOR_AI = ['chrome', 'microsoftedge', 'firefox']
7878

79+
export const SUPPORTED_BROWSERS_FOR_ACCESSIBILITY = ['chrome', 'chromefortesting', 'safari']
80+
81+
export const MIN_BROWSER_VERSIONS_A11Y = {
82+
chrome: 95,
83+
chromefortesting: 141,
84+
safari: 18.4
85+
} as const
86+
87+
export const MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK = {
88+
chrome: 100,
89+
chromefortesting: 141,
90+
safari: 18.4
91+
} as const
92+
7993
export const TCG_URL = 'https://tcg.browserstack.com'
8094

8195
export const TCG_INFO = {

packages/wdio-browserstack-service/src/util.ts

Lines changed: 76 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ import {
4141
APP_ALLY_ISSUES_SUMMARY_ENDPOINT,
4242
APP_ALLY_ISSUES_ENDPOINT,
4343
CLI_DEBUG_LOGS_FILE,
44-
WDIO_NAMING_PREFIX
44+
WDIO_NAMING_PREFIX,
45+
MIN_BROWSER_VERSIONS_A11Y,
46+
MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK,
47+
SUPPORTED_BROWSERS_FOR_ACCESSIBILITY
4548
} from './constants.js'
4649
import CrashReporter from './crash-reporter.js'
4750
import { BStackLogger } from './bstackLogger.js'
@@ -482,39 +485,92 @@ export const validateCapsWithA11y = (deviceName?: any, platformMeta?: { [key: st
482485
return false
483486
}
484487

485-
if (platformMeta?.browser_name?.toLowerCase() !== 'chrome') {
486-
BStackLogger.warn('Accessibility Automation will run only on Chrome browsers.')
487-
return false
488-
}
488+
const browserName = platformMeta?.browser_name?.toLowerCase()
489489
const browserVersion = platformMeta?.browser_version
490-
if ( !isUndefined(browserVersion) && !(browserVersion === 'latest' || parseFloat(browserVersion + '') > 94)) {
491-
BStackLogger.warn('Accessibility Automation will run only on Chrome browser version greater than 94.')
490+
491+
const validBrowsers = SUPPORTED_BROWSERS_FOR_ACCESSIBILITY
492+
if (!browserName || !validBrowsers.includes(browserName)) {
493+
BStackLogger.warn(`Accessibility Automation supports Chrome 95+, Chrome for Testing 141+, and Safari 18.4+. Current browser: ${browserName}`)
492494
return false
493495
}
494496

495-
if (chromeOptions?.args?.includes('--headless')) {
496-
BStackLogger.warn('Accessibility Automation will not run on legacy headless mode. Switch to new headless mode or avoid using headless mode.')
497-
return false
497+
if (browserName === 'chrome' || browserName === 'chromefortesting') {
498+
const minVersion = MIN_BROWSER_VERSIONS_A11Y[browserName as keyof typeof MIN_BROWSER_VERSIONS_A11Y]
499+
if (browserVersion && browserVersion !== 'latest') {
500+
const version = parseInt(browserVersion.toString().split('.')[0] || '0', 10)
501+
if (version < minVersion) {
502+
BStackLogger.warn(`Accessibility Automation requires ${browserName === 'chrome' ? 'Chrome' : 'Chrome for Testing'} version ${minVersion} or higher.`)
503+
return false
504+
}
505+
}
506+
507+
if (chromeOptions?.args?.includes('--headless')) {
508+
BStackLogger.warn('Accessibility Automation will not run on legacy headless mode. Switch to new headless mode or avoid using headless mode.')
509+
return false
510+
}
511+
}
512+
513+
// Safari validation
514+
if (browserName === 'safari') {
515+
if (browserVersion && browserVersion !== 'latest') {
516+
const [currentMajor = 0, currentMinor = 0] = browserVersion.toString().split('.').map(Number)
517+
const [requiredMajor = 0, requiredMinor = 0] = MIN_BROWSER_VERSIONS_A11Y.safari.toString().split('.').map(Number)
518+
519+
if (currentMajor < requiredMajor || (currentMajor === requiredMajor && currentMinor < requiredMinor)) {
520+
BStackLogger.warn(`Accessibility Automation requires Safari version ${MIN_BROWSER_VERSIONS_A11Y.safari} or higher.`)
521+
return false
522+
}
523+
}
498524
}
525+
499526
return true
500527
} catch (error) {
501528
BStackLogger.debug(`Exception in checking capabilities compatibility with Accessibility. Error: ${error}`)
502529
}
503530
return false
504531
}
505532

506-
export const validateCapsWithNonBstackA11y = (browserName?: string | undefined, browserVersion?:string | undefined ) => {
533+
export const validateCapsWithNonBstackA11y = (browserName?: string | undefined, browserVersion?:string | undefined) => {
534+
try {
535+
const browser = browserName?.toLowerCase()
507536

508-
if (browserName?.toLowerCase() !== 'chrome') {
509-
BStackLogger.warn('Accessibility Automation will run only on Chrome browsers.')
510-
return false
511-
}
512-
if (!isUndefined(browserVersion) && !(browserVersion === 'latest' || parseFloat(browserVersion + '') > 100)) {
513-
BStackLogger.warn('Accessibility Automation will run only on Chrome browser version greater than 100.')
514-
return false
515-
}
516-
return true
537+
// Support Chrome, Chrome for Testing (ChromeForTesting), and Safari on non-BrowserStack infrastructure
538+
const validBrowsers = ['chrome', 'chromefortesting', 'safari']
539+
if (!browser || !validBrowsers.includes(browser)) {
540+
BStackLogger.warn('Accessibility Automation on non-BrowserStack infrastructure supports Chrome 100+, Chrome for Testing 141+, and Safari 18.4+.')
541+
return false
542+
}
543+
544+
// Chrome/Chrome for Testing validation
545+
if (browser === 'chrome' || browser === 'chromefortesting') {
546+
const minVersion = MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK[browser as keyof typeof MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK]
547+
if (browserVersion && browserVersion !== 'latest') {
548+
const version = parseInt(browserVersion.toString().split('.')[0] || '0', 10)
549+
if (version < minVersion) {
550+
BStackLogger.warn(`Accessibility Automation requires ${browser === 'chrome' ? 'Chrome' : 'Chrome for Testing'} version ${minVersion}+ on non-BrowserStack infrastructure.`)
551+
return false
552+
}
553+
}
554+
}
555+
556+
// Safari validation
557+
if (browser === 'safari') {
558+
if (browserVersion && browserVersion !== 'latest') {
559+
const [currentMajor = 0, currentMinor = 0] = browserVersion.toString().split('.').map(Number)
560+
const [requiredMajor = 0, requiredMinor = 0] = MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK.safari.toString().split('.').map(Number)
517561

562+
if (currentMajor < requiredMajor || (currentMajor === requiredMajor && currentMinor < requiredMinor)) {
563+
BStackLogger.warn(`Accessibility Automation requires Safari version ${MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK.safari}+ on non-BrowserStack infrastructure.`)
564+
return false
565+
}
566+
}
567+
}
568+
569+
return true
570+
} catch (error) {
571+
BStackLogger.debug(`Exception in checking capabilities compatibility with Accessibility. Error: ${error}`)
572+
}
573+
return false
518574
}
519575

520576
export const shouldScanTestForAccessibility = (suiteTitle: string | undefined, testTitle: string, accessibilityOptions?: { [key: string]: string; }, world?: { [key: string]: unknown; }, isCucumber?: boolean ) => {

packages/wdio-browserstack-service/tests/util.test.ts

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,25 +1256,25 @@ describe('validateCapsWithA11y', () => {
12561256
.toContain('Accessibility Automation will run only on Desktop browsers.')
12571257
})
12581258

1259-
it('returns false if browser is not chrome', async () => {
1259+
it('returns false if browser is not supported', async () => {
12601260
const platformMeta = {
1261-
'browser_name': 'safari'
1261+
'browser_name': 'firefox'
12621262
}
12631263

12641264
expect(validateCapsWithA11y(undefined, platformMeta)).toEqual(false)
12651265
expect(logInfoMock.mock.calls[0][0])
1266-
.toContain('Accessibility Automation will run only on Chrome browsers.')
1266+
.toContain('Accessibility Automation supports Chrome 95+, Chrome for Testing 141+, and Safari 18.4+')
12671267
})
12681268

1269-
it('returns false if browser version is lesser than 94', async () => {
1269+
it('returns false if browser version is lesser than 95', async () => {
12701270
const platformMeta = {
12711271
'browser_name': 'chrome',
12721272
'browser_version': '90'
12731273
}
12741274

12751275
expect(validateCapsWithA11y(undefined, platformMeta)).toEqual(false)
12761276
expect(logInfoMock.mock.calls[0][0])
1277-
.toContain('Accessibility Automation will run only on Chrome browser version greater than 94.')
1277+
.toContain('Accessibility Automation requires Chrome version 95 or higher')
12781278
})
12791279

12801280
it('returns false if browser version is lesser than 94', async () => {
@@ -1300,6 +1300,50 @@ describe('validateCapsWithA11y', () => {
13001300

13011301
expect(validateCapsWithA11y(undefined, platformMeta, chromeOptions)).toEqual(true)
13021302
})
1303+
1304+
it('returns true for Safari 18.4+', async () => {
1305+
const platformMeta = {
1306+
'browser_name': 'safari',
1307+
'browser_version': '18.4'
1308+
}
1309+
expect(validateCapsWithA11y(undefined, platformMeta)).toEqual(true)
1310+
})
1311+
1312+
it('returns true for Safari latest', async () => {
1313+
const platformMeta = {
1314+
'browser_name': 'safari',
1315+
'browser_version': 'latest'
1316+
}
1317+
expect(validateCapsWithA11y(undefined, platformMeta)).toEqual(true)
1318+
})
1319+
1320+
it('returns false for Safari < 18.4', async () => {
1321+
const platformMeta = {
1322+
'browser_name': 'safari',
1323+
'browser_version': '16.0'
1324+
}
1325+
expect(validateCapsWithA11y(undefined, platformMeta)).toEqual(false)
1326+
expect(logInfoMock.mock.calls[0][0])
1327+
.toContain('Safari version 18.4 or higher')
1328+
})
1329+
1330+
it('returns true for ChromeForTesting 141+', async () => {
1331+
const platformMeta = {
1332+
'browser_name': 'ChromeForTesting',
1333+
'browser_version': '141'
1334+
}
1335+
expect(validateCapsWithA11y(undefined, platformMeta)).toEqual(true)
1336+
})
1337+
1338+
it('returns false for ChromeForTesting < 141', async () => {
1339+
const platformMeta = {
1340+
'browser_name': 'ChromeForTesting',
1341+
'browser_version': '140'
1342+
}
1343+
expect(validateCapsWithA11y(undefined, platformMeta)).toEqual(false)
1344+
expect(logInfoMock.mock.calls[0][0])
1345+
.toContain('Accessibility Automation requires Chrome for Testing version 141 or higher')
1346+
})
13031347
})
13041348

13051349
describe('validateCapsWithNonBstackA11y', () => {
@@ -1308,14 +1352,38 @@ describe('validateCapsWithNonBstackA11y', () => {
13081352
logInfoMock = vi.spyOn(log, 'warn')
13091353
})
13101354

1311-
it('returns false if browser is not chrome', async () => {
1355+
it('returns true for safari 18.4+', async () => {
1356+
expect(validateCapsWithNonBstackA11y('safari', '18.4')).toEqual(true)
1357+
})
1358+
1359+
it('returns true for safari latest', async () => {
1360+
expect(validateCapsWithNonBstackA11y('safari', 'latest')).toEqual(true)
1361+
})
1362+
1363+
it('returns false for safari < 18.4', async () => {
1364+
expect(validateCapsWithNonBstackA11y('safari', '16.0')).toEqual(false)
1365+
expect(logInfoMock.mock.calls[0][0])
1366+
.toContain('Safari version 18.4+')
1367+
})
1368+
1369+
it('returns true for ChromeForTesting 141+', async () => {
1370+
expect(validateCapsWithNonBstackA11y('ChromeForTesting', '141')).toEqual(true)
1371+
})
1372+
1373+
it('returns false for ChromeForTesting < 141', async () => {
1374+
expect(validateCapsWithNonBstackA11y('ChromeForTesting', '140')).toEqual(false)
1375+
expect(logInfoMock.mock.calls[0][0])
1376+
.toContain('Accessibility Automation requires Chrome for Testing version 141+')
1377+
})
1378+
1379+
it('returns false if browser is not supported', async () => {
13121380

1313-
const browserName = 'safari'
1381+
const browserName = 'firefox'
13141382
const browserVersion = 'latest'
13151383

13161384
expect(validateCapsWithNonBstackA11y(browserName, browserVersion)).toEqual(false)
13171385
expect(logInfoMock.mock.calls[0][0])
1318-
.toContain('Accessibility Automation will run only on Chrome browsers.')
1386+
.toContain('Accessibility Automation on non-BrowserStack infrastructure supports Chrome 100+, Chrome for Testing 141+, and Safari 18.4+')
13191387
})
13201388

13211389
it('returns false if browser version is lesser than 100', async () => {
@@ -1325,7 +1393,7 @@ describe('validateCapsWithNonBstackA11y', () => {
13251393

13261394
expect(validateCapsWithNonBstackA11y(browserName, browserVersion)).toEqual(false)
13271395
expect(logInfoMock.mock.calls[0][0])
1328-
.toContain('Accessibility Automation will run only on Chrome browser version greater than 100.')
1396+
.toContain('Accessibility Automation requires Chrome version 100+')
13291397
})
13301398

13311399
it('returns true if validation done', async () => {

0 commit comments

Comments
 (0)