import path from 'node:path'
import { describe, expect, it, vi, beforeEach } from 'vitest'
import aiSDK from '@browserstack/ai-sdk-node'
import AiHandler from '../src/ai-handler.js'
import * as bstackLogger from '../src/bstackLogger.js'
import * as funnelInstrumentation from '../src/instrumentation/funnelInstrumentation.js'
import type { Capabilities } from '@wdio/types'
import { TCG_URL } from '../src/constants.js'
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))
vi.mock('@browserstack/ai-sdk-node')
vi.useFakeTimers().setSystemTime(new Date('2020-01-01'))
vi.mock('uuid', () => ({ v4: () => '123456789' }))
vi.mock('node:fs', () => ({
default: {
readFileSync: vi.fn().mockReturnValue(Buffer.from('extension-content'))
}
}))
const bstackLoggerSpy = vi.spyOn(bstackLogger.BStackLogger, 'logToFile')
bstackLoggerSpy.mockImplementation(() => {})
describe('AiHandler', () => {
let config: any
let browser: any
beforeEach(() => {
vi.resetModules()
config = {
user: 'foobaruser',
key: '12345678901234567890',
selfHeal: true
}
browser = {
sessionId: 'test-session-id',
execute: vi.fn(),
installAddOn: vi.fn(),
overwriteCommand: vi.fn(),
capabilities: {
browserName: 'chrome'
}
}
})
describe('authenticateUser', () => {
it('should authenticate user', async () => {
const authResponse = {
message: 'Authentication successful',
isAuthenticated: true,
defaultLogDataEnabled: true,
isHealingEnabled: true,
sessionToken: 'test-token',
groupId: 123123,
userId: 342423,
isGroupAIEnabled: true,
}
const initSpy = vi.spyOn(aiSDK.BrowserstackHealing, 'init')
.mockReturnValue(Promise.resolve(authResponse) as any)
const result = await AiHandler.authenticateUser(config.user, config.key)
expect(initSpy).toHaveBeenCalledTimes(1)
expect(initSpy).toHaveBeenCalledWith(
config.key,
config.user,
'https://tcg.browserstack.com',
expect.any(String)
)
expect(result).toEqual(authResponse)
})
})
describe('updateCaps', () => {
it('should add the AI extension to capabilities', async () => {
const authResult = {
isAuthenticated: true,
defaultLogDataEnabled: true,
} as any
const caps = {
'goog:chromeOptions': {}
}
const mockExtension = 'mock-extension'
vi.spyOn(aiSDK.BrowserstackHealing, 'initializeCapabilities')
.mockReturnValue({ ...caps, 'goog:chromeOptions': { extensions: [mockExtension] } })
const updatedCaps = await AiHandler.updateCaps(authResult, config, caps) as any
expect(updatedCaps['goog:chromeOptions'].extensions).toEqual([mockExtension])
})
it('should not update capabilities if authentication failed', async () => {
const authResult = {
isAuthenticated: false,
message: 'Authentication failed'
} as any
const caps = { browserName: 'chrome' }
const updatedCaps = await AiHandler.updateCaps(authResult, config, caps)
expect(updatedCaps).toEqual(caps)
})
it('should not update capabilities if selfHeal is false', async () => {
const authResult = {
isAuthenticated: false,
message: 'Authentication failed'
} as any
config.selfHeal = false
const caps = { browserName: 'chrome' }
const updatedCaps = await AiHandler.updateCaps(authResult, config, caps)
expect(updatedCaps).toEqual(caps)
})
it('should handle array of capabilities', async () => {
const authResult = {
isAuthenticated: true,
defaultLogDataEnabled: true,
} as any
const caps = [{ browserName: 'chrome' }]
const mockExtension = 'mock-extension'
vi.spyOn(aiSDK.BrowserstackHealing, 'initializeCapabilities')
.mockReturnValue({ browserName: 'chrome', 'goog:chromeOptions': { extensions: [mockExtension] } })
const updatedCaps = await AiHandler.updateCaps(authResult, config, caps) as any
expect(updatedCaps[0]['goog:chromeOptions'].extensions).toEqual([mockExtension])
})
it('should handle mixed array and object capabilities', async () => {
const authResult = {
isAuthenticated: true,
defaultLogDataEnabled: true,
isHealingEnabled: true,
} as any
const capsArray = [{
browserName: 'chrome',
'goog:chromeOptions': {}
}]
const capsObject = {
browserName: 'firefox',
'moz:firefoxOptions': {}
}
const mockChromeExtension = 'mock-chrome-extension'
const mockFirefoxExtension = 'mock-firefox-extension'
const initializeCapabilitiesSpy = vi.spyOn(aiSDK.BrowserstackHealing, 'initializeCapabilities')
.mockReturnValueOnce({
browserName: 'chrome',
'goog:chromeOptions': { extensions: [mockChromeExtension] }
})
.mockReturnValueOnce({
browserName: 'firefox',
'moz:firefoxOptions': { extensions: [mockFirefoxExtension] }
})
const updatedCapsArray = await AiHandler.updateCaps(authResult, config, capsArray) as Array<Capabilities.ResolvedTestrunnerCapabilities>
const updatedCapsObject = await AiHandler.updateCaps(authResult, config, capsObject)
expect(initializeCapabilitiesSpy).toHaveBeenCalledTimes(2)
expect(initializeCapabilitiesSpy).toHaveBeenNthCalledWith(2, capsObject)
expect(updatedCapsArray).toBeInstanceOf(Array)
expect(updatedCapsArray[0]).toEqual({
browserName: 'chrome',
'goog:chromeOptions': { extensions: [mockChromeExtension] }
})
expect(updatedCapsObject).toEqual({
browserName: 'firefox',
'moz:firefoxOptions': { extensions: [mockFirefoxExtension] }
})
})
it('should update caps if selfHeal is true but defaultLogDataEnabled is false', async () => {
const authResult = {
isAuthenticated: true,
defaultLogDataEnabled: false,
} as any
const caps = { browserName: 'chrome' }
const updatedCaps = await AiHandler.updateCaps(authResult, config, caps)
expect(updatedCaps).not.toEqual(caps)
})
})
describe('handleHealing', () => {
it('should attempt healing if findElement fails', async () => {
const originalFunc = vi.fn().mockReturnValueOnce({ error: 'no such element' })
.mockReturnValueOnce({})
const healFailureResponse = { script: 'healing-script' }
const pollResultResponse = { selector: 'css selector', value: '.healed-element' }
AiHandler['authResult'] = {
isAuthenticated: true,
isHealingEnabled: true,
sessionToken: 'test-session-token',
groupId: 123123,
userId: 342423,
isGroupAIEnabled: true
} as any
vi.spyOn(aiSDK.BrowserstackHealing, 'healFailure')
.mockResolvedValue(healFailureResponse.script as string)
vi.spyOn(aiSDK.BrowserstackHealing, 'pollResult')
.mockResolvedValue(pollResultResponse as any)
vi.spyOn(aiSDK.BrowserstackHealing, 'logData')
.mockResolvedValue('logging-script' as string)
const result = await AiHandler.handleHealing(originalFunc, 'id', 'some-id', browser, config)
expect(aiSDK.BrowserstackHealing.healFailure).toHaveBeenCalledTimes(1)
expect(aiSDK.BrowserstackHealing.pollResult).toHaveBeenCalledTimes(1)
expect(originalFunc).toHaveBeenCalledTimes(2)
expect(browser.execute).toHaveBeenCalledWith('healing-script')
expect(result).toEqual({})
})
it('should attempt logging if findElement successfully runs', async () => {
const originalFunc = vi.fn().mockReturnValueOnce({ element: 'mock-element' })
.mockReturnValueOnce({})
AiHandler['authResult'] = {
isAuthenticated: true,
isHealingEnabled: true,
sessionToken: 'test-session-token',
groupId: 123123,
userId: 342423,
isGroupAIEnabled: true
} as any
vi.spyOn(aiSDK.BrowserstackHealing, 'logData')
.mockResolvedValue('logging-script' as any)
const result = await AiHandler.handleHealing(originalFunc, 'id', 'some-id', browser, config)
expect(originalFunc).toHaveBeenCalledTimes(1)
expect(browser.execute).toHaveBeenCalledWith('logging-script')
expect(result).toEqual({ 'element': 'mock-element' })
})
it('should call originalFunc if there is an error in try block', async () => {
const originalFunc = vi.fn().mockImplementationOnce(() => {
throw new Error('Some error occurred.')
})
AiHandler['authResult'] = {
isAuthenticated: true,
isHealingEnabled: true,
sessionToken: 'test-session-token',
groupId: 123123,
userId: 342423,
isGroupAIEnabled: true
} as any
const result = await AiHandler.handleHealing(originalFunc, 'id', 'some-id', browser, config)
expect(originalFunc).toHaveBeenCalledTimes(2)
expect(result).toEqual(undefined)
})
it('should return original error if selfHeal is false', async () => {
const originalFunc = vi.fn().mockImplementationOnce(() => {
throw new Error('Some error occurred.')
})
config.selfHeal = false
const warnSpy = vi.spyOn(bstackLogger.BStackLogger, 'warn')
const result = await AiHandler.handleHealing(originalFunc, 'id', 'some-id', browser, config)
expect(originalFunc).toHaveBeenCalledTimes(2)
expect(warnSpy).toHaveBeenCalledTimes(1)
expect(result).toEqual(undefined)
})
it('should return original result error if healed element is also missing', async () => {
const originalFunc = vi.fn().mockReturnValueOnce({ error: 'no such element' })
.mockReturnValueOnce({ error: 'no such element' })
const healFailureResponse = { script: 'healing-script' }
const pollResultResponse = { selector: 'css selector', value: '.healed-element' }
AiHandler['authResult'] = {
isAuthenticated: true,
isHealingEnabled: true,
sessionToken: 'test-session-token',
groupId: 123123,
userId: 342423,
isGroupAIEnabled: true
} as any
vi.spyOn(aiSDK.BrowserstackHealing, 'healFailure')
.mockResolvedValue(healFailureResponse.script as string)
vi.spyOn(aiSDK.BrowserstackHealing, 'pollResult')
.mockResolvedValue(pollResultResponse as any)
vi.spyOn(aiSDK.BrowserstackHealing, 'logData')
.mockResolvedValue('logging-script' as string)
const result = await AiHandler.handleHealing(originalFunc, 'id', 'some-id', browser, config)
expect(aiSDK.BrowserstackHealing.healFailure).toHaveBeenCalledTimes(1)
expect(aiSDK.BrowserstackHealing.pollResult).toHaveBeenCalledTimes(1)
expect(originalFunc).toHaveBeenCalledTimes(2)
expect(browser.execute).toHaveBeenCalledWith('healing-script')
expect(result).toEqual({ error: 'no such element' })
})
})
describe('setup', () => {
it('should authenticate user and update capabilities for supported browser', async () => {
const caps = { browserName: 'chrome' }
const mockAuthResult = {
isAuthenticated: true,
sessionToken: 'mock-session-token',
defaultLogDataEnabled: true,
isHealingEnabled: true,
groupId: 123123,
userId: 342423,
isGroupAIEnabled: true,
}
const authenticateUserSpy = vi.spyOn(AiHandler, 'authenticateUser')
.mockResolvedValue(mockAuthResult as any)
const handleHealingInstrumentationSpy = vi.spyOn(funnelInstrumentation, 'handleHealingInstrumentation')
const updateCapsSpy = vi.spyOn(AiHandler, 'updateCaps')
.mockResolvedValue({ ...caps, 'goog:chromeOptions': { extensions: ['mock-extension'] } })
const mockExtension = 'mock-extension'
vi.spyOn(aiSDK.BrowserstackHealing, 'initializeCapabilities')
.mockReturnValue({ ...caps, 'goog:chromeOptions': { extensions: [mockExtension] } })
const emptyObj = {} as any
await AiHandler.setup(config, emptyObj, emptyObj, caps, false)
expect(authenticateUserSpy).toHaveBeenCalledTimes(1)
expect(handleHealingInstrumentationSpy).toHaveBeenCalledTimes(1)
expect(updateCapsSpy).toHaveBeenCalledTimes(1)
})
it('should skip setup if accessKey is not present', async () => {
config.key = ''
const caps = { browserName: 'chrome' }
const authenticateUserSpy = vi.spyOn(AiHandler, 'authenticateUser')
const handleHealingInstrumentationSpy = vi.spyOn(funnelInstrumentation, 'handleHealingInstrumentation')
const updateCapsSpy = vi.spyOn(AiHandler, 'updateCaps')
const emptyObj = {} as any
vi.stubEnv('BROWSERSTACK_ACCESS_KEY', '')
const updatedCaps = await AiHandler.setup(config, emptyObj, emptyObj, caps, false)
expect(authenticateUserSpy).not.toHaveBeenCalled()
expect(handleHealingInstrumentationSpy).not.toHaveBeenCalled()
expect(updateCapsSpy).not.toHaveBeenCalled()
expect(updatedCaps).toEqual(caps)
})
it('should skip setup if userName is not present', async () => {
config.user = ''
const caps = { browserName: 'chrome' }
const authenticateUserSpy = vi.spyOn(AiHandler, 'authenticateUser')
const handleHealingInstrumentationSpy = vi.spyOn(funnelInstrumentation, 'handleHealingInstrumentation')
const updateCapsSpy = vi.spyOn(AiHandler, 'updateCaps')
const emptyObj = {} as any
vi.stubEnv('BROWSERSTACK_USERNAME', '')
const updatedCaps = await AiHandler.setup(config, emptyObj, emptyObj, caps, false)
expect(authenticateUserSpy).not.toHaveBeenCalled()
expect(handleHealingInstrumentationSpy).not.toHaveBeenCalled()
expect(updateCapsSpy).not.toHaveBeenCalled()
expect(updatedCaps).toEqual(caps)
})
it('should handle errors in setup', async () => {
const caps = { browserName: 'chrome' }
const authenticateUserSpy = vi.spyOn(AiHandler, 'authenticateUser')
.mockRejectedValue(new Error('Authentication failed'))
const warnSpy = vi.spyOn(bstackLogger.BStackLogger, 'warn')
const emptyObj = {} as any
const options = { selfHeal: true } as any
const updatedCaps = await AiHandler.setup(config, emptyObj, options, caps, false)
expect(authenticateUserSpy).toHaveBeenCalledTimes(1)
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Error while initiliazing Browserstack healing Extension'))
expect(updatedCaps).toEqual(caps)
})
})
describe('selfHeal', () => {
it('should set token, install extension for Firefox', async () => {
const caps = { browserName: 'firefox' } as Capabilities.ResolvedTestrunnerCapabilities
AiHandler['authResult'] = {
isAuthenticated: true,
sessionToken: 'mock-session-token',
defaultLogDataEnabled: true,
isHealingEnabled: true
} as any
const setTokenSpy = vi.spyOn(AiHandler, 'setToken')
const installFirefoxExtensionSpy = vi.spyOn(AiHandler, 'installFirefoxExtension')
browser.capabilities = caps
await AiHandler.selfHeal(config, caps, browser)
expect(setTokenSpy).toHaveBeenCalledTimes(1)
expect(setTokenSpy).toHaveBeenCalledWith(browser.sessionId, 'mock-session-token')
expect(installFirefoxExtensionSpy).toHaveBeenCalledTimes(1)
expect(installFirefoxExtensionSpy).toHaveBeenCalledWith(browser)
})
it('should set token for Chrome', async () => {
const caps = { browserName: 'chrome' } as Capabilities.ResolvedTestrunnerCapabilities
AiHandler['authResult'] = {
isAuthenticated: true,
sessionToken: 'mock-session-token',
defaultLogDataEnabled: true,
isHealingEnabled: true
} as any
const setTokenSpy = vi.spyOn(AiHandler, 'setToken')
browser.capabilities = caps
await AiHandler.selfHeal(config, caps, browser)
expect(setTokenSpy).toHaveBeenCalledTimes(1)
expect(setTokenSpy).toHaveBeenCalledWith(browser.sessionId, 'mock-session-token')
})
it('should skip self-healing if authResult is empty', async () => {
const caps = { browserName: 'chrome' } as Capabilities.ResolvedTestrunnerCapabilities
AiHandler['authResult'] = {} as any
const setTokenSpy = vi.spyOn(AiHandler, 'setToken')
await AiHandler.selfHeal(config, caps, browser)
expect(setTokenSpy).not.toHaveBeenCalled()
})
it('should call overwriteCommand for Chrome', async () => {
const caps = { browserName: 'chrome' } as Capabilities.ResolvedTestrunnerCapabilities
AiHandler['authResult'] = {
isAuthenticated: true,
sessionToken: 'mock-session-token',
defaultLogDataEnabled: true,
isHealingEnabled: true
} as any
const setTokenSpy = vi.spyOn(AiHandler, 'setToken')
const overwriteCommandSpy = vi.spyOn(browser, 'overwriteCommand')
vi.spyOn(aiSDK.BrowserstackHealing, 'logData')
.mockResolvedValue('logging-script')
browser.capabilities = caps
await AiHandler.selfHeal(config, caps, browser)
expect(setTokenSpy).toHaveBeenCalledTimes(1)
expect(setTokenSpy).toHaveBeenCalledWith(browser.sessionId, 'mock-session-token')
expect(overwriteCommandSpy).toHaveBeenCalledTimes(1)
expect(overwriteCommandSpy).toHaveBeenCalledWith('findElement', expect.any(Function))
})
it('should call overwriteCommand for Edge', async () => {
const caps = { browserName: 'microsoftedge' } as Capabilities.ResolvedTestrunnerCapabilities
AiHandler['authResult'] = {
isAuthenticated: true,
sessionToken: 'mock-session-token',
defaultLogDataEnabled: true,
isHealingEnabled: true
} as any
const setTokenSpy = vi.spyOn(AiHandler, 'setToken')
const overwriteCommandSpy = vi.spyOn(browser, 'overwriteCommand')
vi.spyOn(aiSDK.BrowserstackHealing, 'logData')
.mockResolvedValue('logging-script')
browser.capabilities = caps
await AiHandler.selfHeal(config, caps, browser)
expect(setTokenSpy).toHaveBeenCalledTimes(1)
expect(setTokenSpy).toHaveBeenCalledWith(browser.sessionId, 'mock-session-token')
expect(overwriteCommandSpy).toHaveBeenCalledTimes(1)
expect(overwriteCommandSpy).toHaveBeenCalledWith('findElement', expect.any(Function))
})
it('should skip selfHeal for unsupported browser', async () => {
const caps = { browserName: 'safari' } as Capabilities.ResolvedTestrunnerCapabilities
const setTokenSpy = vi.spyOn(AiHandler, 'setToken')
const installFirefoxExtensionSpy = vi.spyOn(AiHandler, 'installFirefoxExtension')
const overwriteCommandSpy = vi.spyOn(browser, 'overwriteCommand')
browser.capabilities = caps
await AiHandler.selfHeal(config, caps, browser)
expect(setTokenSpy).not.toHaveBeenCalled()
expect(installFirefoxExtensionSpy).not.toHaveBeenCalled()
expect(overwriteCommandSpy).not.toHaveBeenCalled()
})
it('should handle error in selfHeal function', async () => {
const caps = { browserName: 'chrome' } as Capabilities.ResolvedTestrunnerCapabilities
AiHandler['authResult'] = {
isAuthenticated: true,
sessionToken: 'mock-session-token',
defaultLogDataEnabled: true,
isHealingEnabled: true
} as any
const setTokenSpy = vi.spyOn(AiHandler, 'setToken').mockImplementationOnce(() => {
throw new Error('Some error occurred in setToken')
})
const warnSpy = vi.spyOn(bstackLogger.BStackLogger, 'warn')
config.selfHeal = true
await AiHandler.selfHeal(config, caps, browser)
expect(setTokenSpy).toHaveBeenCalledTimes(1)
expect(warnSpy).toHaveBeenCalledWith('Error while setting up self-healing: Error: Some error occurred in setToken. Disabling healing for this session.')
})
it('should not set token if isAuthenticated is false', async () => {
const caps = { browserName: 'chrome' } as Capabilities.ResolvedTestrunnerCapabilities
AiHandler['authResult'] = {
isAuthenticated: false,
sessionToken: 'mock-session-token',
} as any
const setTokenSpy = vi.spyOn(AiHandler, 'setToken')
browser.capabilities = caps
await AiHandler.selfHeal(config, caps, browser)
expect(setTokenSpy).not.toHaveBeenCalled()
})
it('should not overwrite findElement command if defaultLogDataEnabled and selfHeal are false', async () => {
const caps = { browserName: 'chrome' } as Capabilities.ResolvedTestrunnerCapabilities
config.selfHeal = false
AiHandler['authResult'] = {
isAuthenticated: true,
sessionToken: 'mock-session-token',
defaultLogDataEnabled: false,
} as any
const overwriteCommandSpy = vi.spyOn(browser, 'overwriteCommand')
browser.capabilities = caps
await AiHandler.selfHeal(config, caps, browser)
expect(overwriteCommandSpy).not.toHaveBeenCalled()
})
})
describe('setToken', () => {
it('should call setToken with correct parameters', async () => {
const setTokenSpy = vi.spyOn(aiSDK.BrowserstackHealing, 'setToken')
.mockResolvedValue(undefined)
await AiHandler.setToken('test-session-id', 'test-token')
expect(setTokenSpy).toHaveBeenCalledWith('test-session-id', 'test-token', TCG_URL)
})
})
describe('handle multi remote browser session', () => {
let config: any
let browserMock: any
let caps: any
const mockAuthResult = {
isAuthenticated: true,
sessionToken: 'mock-session-token',
defaultLogDataEnabled: true,
isHealingEnabled: true,
groupId: 123123,
userId: 342423,
isGroupAIEnabled: true,
}
beforeEach(() => {
config = {
capabilities: {
myChromeBrowser: {
hostname: 'localhost',
port: 4444,
protocol: 'http',
capabilities: {
browserName: 'chrome',
'goog:chromeOptions': {}
}
},
myFirefoxBrowser: {
hostname: 'localhost',
port: 4444,
protocol: 'http',
capabilities: {
browserName: 'firefox',
'moz:firefoxOptions': {}
}
}
},
maxInstances: 15,
user: 'foobaruser',
key: '12345678901234567890',
selfHeal: true
}
caps = {
myChromeBrowser: {
hostname: 'localhost',
port: 4444,
protocol: 'http',
capabilities: {
browserName: 'chrome',
'goog:chromeOptions': {}
}
},
myFirefoxBrowser: {
hostname: 'localhost',
port: 4444,
protocol: 'http',
capabilities: {
browserName: 'firefox',
'moz:firefoxOptions': {}
}
}
}
browserMock = {
myChromeBrowser: {
sessionId: 'chrome-session-id',
capabilities: { browserName: 'chrome' },
overwriteCommand: vi.fn(),
},
myFirefoxBrowser: {
sessionId: 'firefox-session-id',
capabilities: { browserName: 'firefox' },
overwriteCommand: vi.fn(),
installAddOn: vi.fn()
}
} as any
})
it('should setup capabilities for multiremote session not running on BrowserStack', async () => {
const mockExtension = 'mock-extension'
const handleHealingInstrumentationSpy = vi.spyOn(funnelInstrumentation, 'handleHealingInstrumentation')
const updateCapsSpy = vi.spyOn(AiHandler, 'updateCaps')
.mockResolvedValue({ 'goog:chromeOptions': { extensions: [mockExtension] } })
vi.spyOn(aiSDK.BrowserstackHealing, 'initializeCapabilities')
.mockReturnValue({ 'goog:chromeOptions': { extensions: [mockExtension] } })
const emptyObj = {} as any
AiHandler.handleMultiRemoteSetup(mockAuthResult, config, emptyObj, emptyObj, config.capabilities) as any
expect(handleHealingInstrumentationSpy).toHaveBeenCalledTimes(2)
expect(updateCapsSpy).toHaveBeenCalledTimes(2)
})
it('should call handleSelfHeal for each browser in multiremote setup', async () => {
AiHandler['authResult'] = {
isAuthenticated: true,
sessionToken: 'mock-session-token',
defaultLogDataEnabled: true,
isHealingEnabled: true
} as any
const setTokenSpy = vi.spyOn(AiHandler, 'setToken')
const installFirefoxExtensionSpy = vi.spyOn(AiHandler, 'installFirefoxExtension')
const handleSelfHealSpy = vi.spyOn(AiHandler, 'handleSelfHeal')
await AiHandler.selfHeal(config, caps, browserMock)
expect(handleSelfHealSpy).toHaveBeenCalledTimes(2)
expect(handleSelfHealSpy).toHaveBeenCalledWith(config, browserMock.myChromeBrowser)
expect(handleSelfHealSpy).toHaveBeenCalledWith(config, browserMock.myFirefoxBrowser)
expect(setTokenSpy).toHaveBeenCalledWith('chrome-session-id', 'mock-session-token')
expect(setTokenSpy).toHaveBeenCalledWith('firefox-session-id', 'mock-session-token')
expect(installFirefoxExtensionSpy).toHaveBeenCalledTimes(1)
expect(installFirefoxExtensionSpy).toHaveBeenCalledWith(browserMock.myFirefoxBrowser)
})
it('should skip setup for multiremote session if accessKey is not present', async () => {
config.key = ''
const authenticateUserSpy = vi.spyOn(AiHandler, 'authenticateUser')
.mockResolvedValue(mockAuthResult as any)
const handleHealingInstrumentationSpy = vi.spyOn(funnelInstrumentation, 'handleHealingInstrumentation')
const updateCapsSpy = vi.spyOn(AiHandler, 'updateCaps')
const emptyObj = {} as any
vi.stubEnv('BROWSERSTACK_ACCESS_KEY', '')
const authResult = {
isAuthenticated: true,
sessionToken: 'mock-session-token',
defaultLogDataEnabled: true,
isHealingEnabled: true
} as any
AiHandler.handleMultiRemoteSetup(authResult, config, emptyObj, emptyObj, config.capabilities) as any
expect(authenticateUserSpy).not.toHaveBeenCalled()
expect(handleHealingInstrumentationSpy).not.toHaveBeenCalled()
expect(updateCapsSpy).not.toHaveBeenCalled()
})
it('should handle multiremote setup', async () => {
const caps = {
browserA: {
capabilities: { browserName: 'chrome' }
},
browserB: {
capabilities: { browserName: 'firefox' }
}
} as any
const handleMultiRemoteSetupSpy = vi.spyOn(AiHandler, 'handleMultiRemoteSetup')
.mockResolvedValue(caps)
const emptyObj = {} as any
const updatedCaps = await AiHandler.setup(config, emptyObj, emptyObj, caps, true)
expect(handleMultiRemoteSetupSpy).toHaveBeenCalledTimes(1)
expect(updatedCaps).toEqual(caps)
})
})
})