import path from 'node:path'
import { expect, describe, it, vi, beforeEach, beforeAll } from 'vitest'
import puppeteer from 'puppeteer-core'
import { remote } from '../../../src/index.js'
vi.mock('fetch')
vi.mock('puppeteer-core')
* Given that Puppeteer is not a direct dependency of this package, we can't mock
* it and dynamically import it. Instead, we mock the "userImport" helper and make
* it resolve to the mocked Puppeteer.
*/
vi.mock('@wdio/utils', async (origMod) => {
const orig = await origMod() as any
const puppeteer = await import('puppeteer-core')
return {
...orig,
userImport: vi.fn().mockResolvedValue(puppeteer.default)
}
})
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))
const puppeteerConnect = vi.mocked(puppeteer.connect)
describe('attach Puppeteer', () => {
let browser: WebdriverIO.Browser
beforeEach(() => {
puppeteerConnect.mockClear()
})
beforeAll(async () => {
browser = await remote({
baseUrl: 'http://foobar.com',
capabilities: {
browserName: 'foobar'
},
headers: {
Authorization: 'OAuth token'
}
})
})
it('should pass for Chrome', async () => {
const pptr = await browser.getPuppeteer.call({
...browser,
options: browser.options,
capabilities: {
browserName: 'chrome',
'goog:chromeOptions': {
debuggerAddress: 'localhost:1234'
}
},
requestedCapabilities: {}
} as WebdriverIO.Browser)
expect(typeof pptr).toBe('object')
expect(puppeteerConnect.mock.calls).toMatchSnapshot()
})
it('should pass for Firefox', async () => {
const pprt = await browser.getPuppeteer.call({
...browser,
options: browser.options,
capabilities: {
browserName: 'firefox',
browserVersion: '79.0b'
},
requestedCapabilities: {
'moz:firefoxOptions': {
args: ['foo', 'bar', '-remote-debugging-port', 4321, 'barfoo']
} as any
}
} as WebdriverIO.Browser)
expect(typeof pprt).toBe('object')
expect(puppeteerConnect.mock.calls).toMatchSnapshot()
})
it('should pass for Firefox (DevTools)', async () => {
const pptr = await browser.getPuppeteer.call({
...browser,
options: browser.options,
capabilities: {
browserName: 'firefox',
browserVersion: '79.0b',
'moz:firefoxOptions': {
debuggerAddress: 'localhost:1234'
}
},
requestedCapabilities: {
'moz:firefoxOptions': {
args: []
} as any
}
} as WebdriverIO.Browser)
expect(typeof pptr).toBe('object')
expect(puppeteerConnect.mock.calls).toMatchSnapshot()
})
it('should pass for Firefox and moz:debuggerAddress flag enabled', async () => {
const pptr = await browser.getPuppeteer.call({
...browser,
options: browser.options,
capabilities: {
browserName: 'firefox',
browserVersion: '79.0b',
'moz:debuggerAddress': 'localhost:1234'
},
requestedCapabilities: {
'moz:firefoxOptions': {
args: []
} as any
}
} as WebdriverIO.Browser)
expect(typeof pptr).toBe('object')
expect(puppeteerConnect.mock.calls).toMatchSnapshot()
})
it('should fail for Firefox if no info is given', async () => {
await expect(browser.getPuppeteer.call({
...browser,
options: browser.options,
capabilities: {
browserName: 'firefox',
browserVersion: '79.0b'
},
requestedCapabilities: {
'moz:firefoxOptions': {
args: []
} as any
}
} as WebdriverIO.Browser)).rejects.toThrow('Could\'t find a websocket url')
})
it('should pass for Edge', async () => {
const pptr = await browser.getPuppeteer.call({
...browser,
options: browser.options,
capabilities: {
browserName: 'edge',
'ms:edgeOptions': {
debuggerAddress: 'localhost:1234'
}
},
requestedCapabilities: {}
} as WebdriverIO.Browser)
expect(typeof pptr).toBe('object')
expect(puppeteerConnect.mock.calls).toMatchSnapshot()
})
it('should fail for old Firefox version', async () => {
const err = await browser.getPuppeteer.call({
...browser,
options: browser.options,
capabilities: {
browserName: 'firefox',
browserVersion: '78.0b'
},
requestedCapabilities: {
'moz:firefoxOptions': {
args: ['foo', 'bar', '-remote-debugging-port', 4321, 'barfoo']
} as any
}
} as WebdriverIO.Browser).catch(err => err)
expect(err.message).toContain('Using DevTools capabilities is not supported for this session.')
})
it('should not re-attach if connection was already established', async () => {
const pptr = await browser.getPuppeteer.call({
...browser,
options: browser.options,
capabilities: {
browserName: 'chrome',
'goog:chromeOptions': {
debuggerAddress: 'localhost:1234'
}
},
puppeteer: {
connected: true
} as any
} as WebdriverIO.Browser)
expect(typeof pptr).toBe('object')
expect(puppeteerConnect).toHaveBeenCalledTimes(0)
})
it('should pass for Selenium CDP', async () => {
const pptr = await browser.getPuppeteer.call({
...browser,
options: browser.options,
capabilities: {
'se:cdp': 'http://my.grid:1234/session/mytestsession/se/cdp'
}
} as WebdriverIO.Browser)
expect(typeof pptr).toBe('object')
expect(puppeteerConnect.mock.calls).toMatchSnapshot()
})
it('should pass for Aerokube Selenoid CDP', async () => {
const pptr = await browser.getPuppeteer.call({
...browser,
capabilities: {
'selenoid:options': {
foo: 'bar'
} as any
},
requestedCapabilities: {
'selenoid:options': {
foo: 'bar'
} as any
},
options: {
hostname: 'my.grid',
port: 4444,
path: '/wd/hub',
headers: {
Authorization: 'OAuth token'
}
} as any
} as WebdriverIO.Browser)
expect(typeof pptr).toBe('object')
expect(puppeteerConnect.mock.calls).toMatchSnapshot()
})
it('should pass for Aerokube Moon CDP', async () => {
const pptr = await browser.getPuppeteer.call({
...browser,
capabilities: {
'moon:options': {
foo: 'bar'
} as any
},
requestedCapabilities: {
'moon:options': {
foo: 'bar'
} as any
},
options: {
hostname: 'my.grid',
port: 4444,
path: '/wd/hub',
headers: {
Authorization: 'OAuth token'
}
} as any
} as WebdriverIO.Browser)
expect(typeof pptr).toBe('object')
expect(puppeteerConnect.mock.calls).toMatchSnapshot()
})
it('should throw an error if Puppeteer is not supported', async () => {
globalThis.wdio = true
await expect(browser.getPuppeteer.call({
...browser,
options: browser.options,
capabilities: { browserName: 'chrome' }
} as WebdriverIO.Browser)).rejects.toThrow('Puppeteer is not supported in browser runner')
})
})