convert devtools tests to vitest

This commit is contained in:
Christian Bromann 2022-05-17 08:44:44 +00:00
parent 0441aea615
commit 8943fb91cf
21 changed files with 523 additions and 431 deletions

View file

@ -0,0 +1,4 @@
import { vi } from 'vitest'
export const launch = vi.fn().mockReturnValue(Promise.resolve({
port: 1234
}))

3
__mocks__/pptrDebug.ts Normal file
View file

@ -0,0 +1,3 @@
import { vi } from 'vitest'
const log = vi.fn()
export { log }

View file

@ -1,5 +1,7 @@
const sendMock = jest.fn()
const listenerMock = jest.fn()
import { vi } from 'vitest'
const sendMock = vi.fn()
const listenerMock = vi.fn()
const devices = [{
name: 'Nexus 6P',
@ -23,7 +25,7 @@ const devices = [{
hasTouch: true,
isLandscape: true
}
}]
}] as any
devices['Nexus 6P'] = devices[0]
devices['Nexus 6P landscape'] = devices[0]
@ -32,41 +34,41 @@ class CDPSessionMock {
on = listenerMock
_connection = {
_transport: {
_ws: { addEventListener: jest.fn() }
_ws: { addEventListener: vi.fn() }
}
}
}
const cdpSession = new CDPSessionMock()
class TargetMock {
page = jest.fn().mockImplementation(() => page)
createCDPSession = jest.fn().mockImplementation(() => cdpSession)
page = vi.fn().mockImplementation(() => page)
createCDPSession = vi.fn().mockImplementation(() => cdpSession)
}
const target = new TargetMock()
class PageMock {
on = jest.fn()
close = jest.fn()
url = jest.fn().mockReturnValue('about:blank')
emulate = jest.fn()
setViewport = jest.fn()
setDefaultTimeout = jest.fn()
target = jest.fn().mockReturnValue(target)
on = vi.fn()
close = vi.fn()
url = vi.fn().mockReturnValue('about:blank')
emulate = vi.fn()
setViewport = vi.fn()
setDefaultTimeout = vi.fn()
target = vi.fn().mockReturnValue(target)
}
const page = new PageMock()
class PageMock2 extends PageMock {
url = jest.fn().mockReturnValue('http://json.org')
url = vi.fn().mockReturnValue('http://json.org')
}
const page2 = new PageMock2()
class PuppeteerMock {
on = jest.fn()
waitForTarget = jest.fn().mockImplementation(() => target)
getActivePage = jest.fn().mockImplementation(() => page)
pages = jest.fn().mockReturnValue(Promise.resolve([page, page2]))
userAgent = jest.fn().mockImplementation(() => 'MOCK USER AGENT')
_connection = { _transport: { _ws: { addEventListener: jest.fn() } } }
on = vi.fn()
waitForTarget = vi.fn().mockImplementation(() => target)
getActivePage = vi.fn().mockImplementation(() => page)
pages = vi.fn().mockReturnValue(Promise.resolve([page, page2]))
userAgent = vi.fn().mockImplementation(() => 'MOCK USER AGENT')
_connection = { _transport: { _ws: { addEventListener: vi.fn() } } }
}
export default {
@ -77,10 +79,10 @@ export default {
sendMock,
listenerMock,
devices,
registerCustomQueryHandler: jest.fn(),
unregisterCustomQueryHandler: jest.fn(),
launch: jest.fn().mockImplementation(
registerCustomQueryHandler: vi.fn(),
unregisterCustomQueryHandler: vi.fn(),
launch: vi.fn().mockImplementation(
() => Promise.resolve(new PuppeteerMock())),
connect: jest.fn().mockImplementation(
connect: vi.fn().mockImplementation(
() => Promise.resolve(new PuppeteerMock()))
}

View file

@ -0,0 +1,69 @@
import acceptAlert from './acceptAlert.js'
import addCookie from './addCookie.js'
import back from './back.js'
import closeWindow from './closeWindow.js'
import createWindow from './createWindow.js'
import deleteAllCookies from './deleteAllCookies.js'
import deleteCookie from './deleteCookie.js'
import deleteSession from './deleteSession.js'
import dismissAlert from './dismissAlert.js'
import elementClear from './elementClear.js'
import elementClick from './elementClick.js'
import elementSendKeys from './elementSendKeys.js'
import executeAsyncScript from './executeAsyncScript.js'
import executeScript from './executeScript.js'
import findElementFromElement from './findElementFromElement.js'
import findElementFromShadowRoot from './findElementFromShadowRoot.js'
import findElementsFromElement from './findElementsFromElement.js'
import findElementsFromShadowRoot from './findElementsFromShadowRoot.js'
import findElements from './findElements.js'
import findElement from './findElement.js'
import forward from './forward.js'
import getActiveElement from './getActiveElement.js'
import getAlertText from './getAlertText.js'
import getAllCookies from './getAllCookies.js'
import getElementAttribute from './getElementAttribute.js'
import getElementComputedLabel from './getElementComputedLabel.js'
import getElementComputedRole from './getElementComputedRole.js'
import getElementCSSValue from './getElementCSSValue.js'
import getElementProperty from './getElementProperty.js'
import getElementRect from './getElementRect.js'
import getElementShadowRoot from './getElementShadowRoot.js'
import getElementTagName from './getElementTagName.js'
import getElementText from './getElementText.js'
import getNamedCookie from './getNamedCookie.js'
import getPageSource from './getPageSource.js'
import getTimeouts from './getTimeouts.js'
import getTitle from './getTitle.js'
import getUrl from './getUrl.js'
import getWindowHandles from './getWindowHandles.js'
import getWindowHandle from './getWindowHandle.js'
import getWindowRect from './getWindowRect.js'
import isElementEnabled from './isElementEnabled.js'
import isElementSelected from './isElementSelected.js'
import navigateTo from './navigateTo.js'
import newSession from './newSession.js'
import performActions from './performActions.js'
import refresh from './refresh.js'
import releaseActions from './releaseActions.js'
import sendAlertText from './sendAlertText.js'
import setTimeouts from './setTimeouts.js'
import setWindowRect from './setWindowRect.js'
import status from './status.js'
import switchToFrame from './switchToFrame.js'
import switchToParentFrame from './switchToParentFrame.js'
import switchToWindow from './switchToWindow.js'
import takeElementScreenshot from './takeElementScreenshot.js'
import takeScreenshot from './takeScreenshot.js'
export {
acceptAlert, addCookie, back, closeWindow, createWindow, deleteAllCookies, deleteCookie, deleteSession,
dismissAlert, elementClear, elementClick, elementSendKeys, executeAsyncScript, executeScript,
findElementFromElement, findElementFromShadowRoot, findElementsFromElement, findElementsFromShadowRoot,
findElements, findElement, forward, getActiveElement, getAlertText, getAllCookies, getElementAttribute,
getElementComputedLabel, getElementComputedRole, getElementCSSValue, getElementProperty, getElementRect,
getElementShadowRoot, getElementTagName, getElementText, getNamedCookie, getPageSource, getTimeouts,
getTitle, getUrl, getWindowHandles, getWindowHandle, getWindowRect, isElementEnabled, isElementSelected,
navigateTo, newSession, performActions, refresh, releaseActions, sendAlertText, setTimeouts, setWindowRect,
status, switchToFrame, switchToParentFrame, switchToWindow, takeElementScreenshot, takeScreenshot
}

View file

@ -1,6 +1,5 @@
import fs from 'node:fs'
import path from 'node:path'
import { createRequire } from 'node:module'
import { v4 as uuidv4 } from 'uuid'
import logger from '@wdio/logger'
@ -11,12 +10,12 @@ import type { Target } from 'puppeteer-core/lib/cjs/puppeteer/common/Target'
import type { CommandEndpoint } from '@wdio/protocols'
import type { Frame } from 'puppeteer-core/lib/cjs/puppeteer/common/FrameManager'
import * as commands from './commands/index.js'
import ElementStore from './elementstore.js'
import { validate, sanitizeError } from './utils.js'
import { DEFAULT_IMPLICIT_TIMEOUT, DEFAULT_PAGELOAD_TIMEOUT, DEFAULT_SCRIPT_TIMEOUT } from './constants.js'
const log = logger('devtools')
const require = createRequire(import.meta.url)
export default class DevToolsDriver {
commands: Record<string, Function> = {}
@ -45,6 +44,7 @@ export default class DevToolsDriver {
)
)
)
for (let filename of files) {
const commandName = path.basename(filename, path.extname(filename))
@ -52,9 +52,7 @@ export default class DevToolsDriver {
throw new Error('Couldn\'t determine command name')
}
this.commands[commandName] = DevToolsDriver.requireCommand(
path.join(dir, commandName)
)
this.commands[commandName] = commands[commandName as keyof typeof commands]
}
for (const page of pages) {
@ -108,14 +106,6 @@ export default class DevToolsDriver {
log.trace(`Switching to window handle with id ${pageIds[0]}`)
}
/**
* moved into an extra method for testing purposes
*/
/* istanbul ignore next */
static requireCommand(filePath: string) {
return require(filePath).default
}
register(commandInfo: CommandEndpoint) {
const self = this
const { command, ref, parameters, variables = [] } = commandInfo

View file

@ -1,5 +0,0 @@
{
"env": {
"jest": true
}
}

View file

@ -1,3 +0,0 @@
export const launch = jest.fn().mockReturnValue(Promise.resolve({
port: 1234
}))

View file

@ -1,2 +0,0 @@
const log = jest.fn()
export { log }

View file

@ -1,33 +1,33 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Vitest Snapshot v1
exports[`attachSession 1`] = `
Object {
{
"browserName": "Chrome",
"browserVersion": "80.0.3987.149",
"goog:chromeOptions": Object {
"goog:chromeOptions": {
"debuggerAddress": "localhost:49375",
},
}
`;
exports[`attachSession 2`] = `
Object {
{
"browserName": "chrome",
}
`;
exports[`newSession 1`] = `
Object {
{
"browserName": "Chrome",
"browserVersion": "80.0.3987.149",
"goog:chromeOptions": Object {
"goog:chromeOptions": {
"debuggerAddress": "localhost:49375",
},
}
`;
exports[`newSession 2`] = `
Object {
{
"browserName": "chrome",
}
`;

View file

@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Vitest Snapshot v1
exports[`setTimeouts with all timeouts 1`] = `
Map {
@ -25,47 +25,47 @@ Map {
`;
exports[`should rerun command if it was executed within navigation 1`] = `
Array [
Array [
[
[
"command",
Object {
{
"command": "elementClick",
"params": Object {
"params": {
"elementId": "123",
"text": "some text",
"value": Array [
"value": [
"some value",
],
},
"retries": 0,
},
],
Array [
[
"command",
Object {
{
"command": "elementClick",
"params": Object {
"params": {
"elementId": "123",
"text": "some text",
"value": Array [
"value": [
"some value",
],
},
"retries": 1,
},
],
Array [
[
"result",
Object {
{
"command": "elementClick",
"params": Object {
"params": {
"elementId": "123",
"text": "some text",
"value": Array [
"value": [
"some value",
],
},
"result": Object {
"result": {
"value": null,
},
"retries": 1,
@ -75,37 +75,37 @@ Array [
`;
exports[`should return proper result 1`] = `
Array [
Array [
[
[
"command",
Object {
{
"command": "elementClick",
"params": Object {
"params": {
"elementId": "123",
"text": "some text",
"value": Array [
"value": [
"some value",
],
},
"retries": 0,
},
],
Array [
[
"result",
Object {
{
"command": "elementClick",
"params": Object {
"params": {
"elementId": "123",
"text": "some text",
"value": Array [
"value": [
"some value",
],
},
"result": Object {
"value": Object {
"result": {
"value": {
"elementId": "123",
"text": "some text",
"value": Array [
"value": [
"some value",
],
},

View file

@ -1,13 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Vitest Snapshot v1
exports[`launch Edge with custom arguments 1`] = `
Array [
Array [
Object {
"args": Array [
[
[
{
"args": [
"foobar",
],
"defaultViewport": Object {
"defaultViewport": {
"height": 456,
"width": 123,
},
@ -21,10 +21,10 @@ Array [
`;
exports[`launch Edge with default values 1`] = `
Array [
Array [
Object {
"defaultViewport": Object {
[
[
{
"defaultViewport": {
"height": 900,
"width": 1200,
},
@ -38,10 +38,10 @@ Array [
`;
exports[`launch Edge without Puppeteer default args (backwards compat) 1`] = `
Array [
Array [
Object {
"defaultViewport": Object {
[
[
{
"defaultViewport": {
"height": 900,
"width": 1200,
},
@ -55,10 +55,10 @@ Array [
`;
exports[`launch Edge without Puppeteer default args 1`] = `
Array [
Array [
Object {
"defaultViewport": Object {
[
[
{
"defaultViewport": {
"height": 900,
"width": 1200,
},
@ -72,11 +72,11 @@ Array [
`;
exports[`launch Firefox Nightly binary without Puppeteer default args 1`] = `
Array [
Array [
Object {
[
[
{
"binary": "firefox",
"defaultViewport": Object {
"defaultViewport": {
"height": 900,
"width": 1200,
},
@ -90,14 +90,14 @@ Array [
`;
exports[`launch Firefox Nightly with custom arguments 1`] = `
Array [
Array [
Object {
"args": Array [
[
[
{
"args": [
"foobar",
],
"binary": "/foo/firefox-nightly",
"defaultViewport": Object {
"defaultViewport": {
"height": 456,
"width": 123,
},
@ -111,11 +111,11 @@ Array [
`;
exports[`launch Firefox Nightly without Puppeteer default args 1`] = `
Array [
Array [
Object {
[
[
{
"binary": "/foo/firefox-nightly",
"defaultViewport": Object {
"defaultViewport": {
"height": 900,
"width": 1200,
},
@ -129,10 +129,10 @@ Array [
`;
exports[`launch chrome with chrome arguments 1`] = `
Array [
Array [
Object {
"chromeFlags": Array [
[
[
{
"chromeFlags": [
"--enable-automation",
"--disable-popup-blocking",
"--disable-extensions",
@ -167,7 +167,7 @@ Array [
"--user-agent=Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36",
],
"chromePath": "/foo/bar",
"envVars": Object {
"envVars": {
"foo": "bar",
},
"ignoreDefaultFlags": true,
@ -178,10 +178,10 @@ Array [
`;
exports[`launch chrome with chrome port 1`] = `
Array [
Array [
Object {
"chromeFlags": Array [
[
[
{
"chromeFlags": [
"--enable-automation",
"--disable-popup-blocking",
"--disable-extensions",
@ -221,10 +221,10 @@ Array [
`;
exports[`launch chrome with custom user data dir 1`] = `
Array [
Array [
Object {
"chromeFlags": Array [
[
[
{
"chromeFlags": [
"--enable-automation",
"--disable-popup-blocking",
"--disable-extensions",
@ -266,10 +266,10 @@ Array [
`;
exports[`launch chrome with default values 1`] = `
Array [
Array [
Object {
"chromeFlags": Array [
[
[
{
"chromeFlags": [
"--enable-automation",
"--disable-popup-blocking",
"--disable-extensions",
@ -308,9 +308,9 @@ Array [
`;
exports[`launch chrome with default values 2`] = `
Array [
Array [
Object {
[
[
{
"browserURL": "http://localhost:1234",
"defaultViewport": null,
},
@ -319,10 +319,10 @@ Array [
`;
exports[`launch chrome with defaultViewport in wdio:devtoolsOptions 1`] = `
Array [
Array [
Object {
"chromeFlags": Array [
[
[
{
"chromeFlags": [
"--enable-automation",
"--disable-popup-blocking",
"--disable-extensions",
@ -365,10 +365,10 @@ Array [
`;
exports[`launch chrome without default flags and without puppeteer default args 1`] = `
Array [
Array [
Object {
"chromeFlags": Array [
[
[
{
"chromeFlags": [
"--window-position=0,0",
"--window-size=1200,900",
],
@ -382,9 +382,9 @@ Array [
`;
exports[`launch chrome without default flags and without puppeteer default args 2`] = `
Array [
Array [
Object {
[
[
{
"browserURL": "http://localhost:1234",
"defaultViewport": null,
"ignoreDefaultArgs": true,
@ -394,10 +394,10 @@ Array [
`;
exports[`overriding chrome default flags (backwards compat) 1`] = `
Array [
Array [
Object {
"chromeFlags": Array [
[
[
{
"chromeFlags": [
"--enable-automation",
"--disable-popup-blocking",
"--disable-extensions",
@ -437,10 +437,10 @@ Array [
`;
exports[`overriding chrome default flags 1`] = `
Array [
Array [
Object {
"chromeFlags": Array [
[
[
{
"chromeFlags": [
"--enable-automation",
"--disable-popup-blocking",
"--disable-extensions",

View file

@ -1,238 +1,238 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Vitest Snapshot v1
exports[`findElement utils findElements should find elements 1`] = `
Array [
Object {
exports[`findElement utils > findElements > should find elements 1`] = `
[
{
"element-6066-11e4-a52e-4f735466cecf": "foobar",
},
Object {
{
"element-6066-11e4-a52e-4f735466cecf": "foobar",
},
]
`;
exports[`findElement utils findElements should find elements with xpath 1`] = `
Array [
Object {
exports[`findElement utils > findElements > should find elements with xpath 1`] = `
[
{
"element-6066-11e4-a52e-4f735466cecf": "foobar",
},
Object {
{
"element-6066-11e4-a52e-4f735466cecf": "foobar",
},
]
`;
exports[`getPrototype 1`] = `
Object {
"acceptAlert": Object {
{
"acceptAlert": {
"value": 56,
},
"addCookie": Object {
"addCookie": {
"value": 49,
},
"back": Object {
"back": {
"value": 8,
},
"closeWindow": Object {
"closeWindow": {
"value": 13,
},
"createWindow": Object {
"createWindow": {
"value": 15,
},
"deleteAllCookies": Object {
"deleteAllCookies": {
"value": 50,
},
"deleteCookie": Object {
"deleteCookie": {
"value": 52,
},
"deleteSession": Object {
"deleteSession": {
"value": 2,
},
"dismissAlert": Object {
"dismissAlert": {
"value": 55,
},
"elementClear": Object {
"elementClear": {
"value": 43,
},
"elementClick": Object {
"elementClick": {
"value": 42,
},
"elementSendKeys": Object {
"elementSendKeys": {
"value": 44,
},
"executeAsyncScript": Object {
"executeAsyncScript": {
"value": 47,
},
"executeScript": Object {
"executeScript": {
"value": 46,
},
"findElement": Object {
"findElement": {
"value": 25,
},
"findElementFromElement": Object {
"findElementFromElement": {
"value": 29,
},
"findElementFromShadowRoot": Object {
"findElementFromShadowRoot": {
"value": 26,
},
"findElements": Object {
"findElements": {
"value": 27,
},
"findElementsFromElement": Object {
"findElementsFromElement": {
"value": 30,
},
"findElementsFromShadowRoot": Object {
"findElementsFromShadowRoot": {
"value": 28,
},
"forward": Object {
"forward": {
"value": 9,
},
"fullscreenWindow": Object {
"fullscreenWindow": {
"value": 24,
},
"getActiveElement": Object {
"getActiveElement": {
"value": 32,
},
"getAlertText": Object {
"getAlertText": {
"value": 57,
},
"getAllCookies": Object {
"getAllCookies": {
"value": 48,
},
"getElementAttribute": Object {
"getElementAttribute": {
"value": 35,
},
"getElementCSSValue": Object {
"getElementCSSValue": {
"value": 37,
},
"getElementComputedLabel": Object {
"getElementComputedLabel": {
"value": 62,
},
"getElementComputedRole": Object {
"getElementComputedRole": {
"value": 61,
},
"getElementProperty": Object {
"getElementProperty": {
"value": 36,
},
"getElementRect": Object {
"getElementRect": {
"value": 40,
},
"getElementShadowRoot": Object {
"getElementShadowRoot": {
"value": 31,
},
"getElementTagName": Object {
"getElementTagName": {
"value": 39,
},
"getElementText": Object {
"getElementText": {
"value": 38,
},
"getNamedCookie": Object {
"getNamedCookie": {
"value": 51,
},
"getPageSource": Object {
"getPageSource": {
"value": 45,
},
"getTimeouts": Object {
"getTimeouts": {
"value": 4,
},
"getTitle": Object {
"getTitle": {
"value": 11,
},
"getUrl": Object {
"getUrl": {
"value": 6,
},
"getWindowHandle": Object {
"getWindowHandle": {
"value": 12,
},
"getWindowHandles": Object {
"getWindowHandles": {
"value": 16,
},
"getWindowRect": Object {
"getWindowRect": {
"value": 20,
},
"isElementDisplayed": Object {
"isElementDisplayed": {
"value": 34,
},
"isElementEnabled": Object {
"isElementEnabled": {
"value": 41,
},
"isElementSelected": Object {
"isElementSelected": {
"value": 33,
},
"maximizeWindow": Object {
"maximizeWindow": {
"value": 22,
},
"minimizeWindow": Object {
"minimizeWindow": {
"value": 23,
},
"navigateTo": Object {
"navigateTo": {
"value": 7,
},
"newSession": Object {
"newSession": {
"value": 1,
},
"performActions": Object {
"performActions": {
"value": 53,
},
"printPage": Object {
"printPage": {
"value": 17,
},
"refresh": Object {
"refresh": {
"value": 10,
},
"releaseActions": Object {
"releaseActions": {
"value": 54,
},
"sendAlertText": Object {
"sendAlertText": {
"value": 58,
},
"setTimeouts": Object {
"setTimeouts": {
"value": 5,
},
"setWindowRect": Object {
"setWindowRect": {
"value": 21,
},
"status": Object {
"status": {
"value": 3,
},
"switchToFrame": Object {
"switchToFrame": {
"value": 18,
},
"switchToParentFrame": Object {
"switchToParentFrame": {
"value": 19,
},
"switchToWindow": Object {
"switchToWindow": {
"value": 14,
},
"takeElementScreenshot": Object {
"takeElementScreenshot": {
"value": 60,
},
"takeScreenshot": Object {
"takeScreenshot": {
"value": 59,
},
}
`;
exports[`transformExecuteResult multiple results 1`] = `
Array [
exports[`transformExecuteResult > multiple results 1`] = `
[
"foobar",
Object {
{
"element-6066-11e4-a52e-4f735466cecf": "foobar",
},
42,
]
`;
exports[`validate should do a proper request 1`] = `
Object {
exports[`validate > should do a proper request 1`] = `
{
"elementId": "123",
"using": "css selector",
"value": "#body",
}
`;
exports[`validate should do a proper request with non required params 1`] = `
Object {
exports[`validate > should do a proper request with non required params 1`] = `
{
"customParam": 123,
"elementId": "123",
"using": "css selector",

View file

@ -1,27 +1,31 @@
import { expect, test, vi, beforeEach } from 'vitest'
import type { Capabilities } from '@wdio/types'
import launch from '../src/launcher'
import DevTools from '../src'
jest.mock('../src/launcher', () => jest.fn().mockImplementation((capabilities) => {
capabilities['goog:chromeOptions'] = capabilities['goog:chromeOptions'] || {}
return {
on: jest.fn(),
pages: jest.fn().mockReturnValue(Promise.resolve([{
on: jest.fn(),
setDefaultTimeout: jest.fn()
}])),
_connection: {
url: () => 'ws://localhost:49375/devtools/browser/c4b017ea-f476-4026-a699-bc5d4858cfe1'
},
userAgent: jest.fn().mockReturnValue(Promise.resolve('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'))
}
vi.mock('../src/launcher', () => ({
default: vi.fn().mockImplementation((capabilities) => {
capabilities['goog:chromeOptions'] = capabilities['goog:chromeOptions'] || {}
return {
on: vi.fn(),
pages: vi.fn().mockReturnValue(Promise.resolve([{
on: vi.fn(),
setDefaultTimeout: vi.fn()
}])),
_connection: {
url: () => 'ws://localhost:49375/devtools/browser/c4b017ea-f476-4026-a699-bc5d4858cfe1'
},
userAgent: vi.fn().mockReturnValue(Promise.resolve('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'))
}
})
}))
beforeEach(() => {
(launch as jest.Mock).mockClear()
vi.mocked(launch).mockClear()
})
test('newSession', async () => {
const client = await DevTools.newSession({
const client: any = await DevTools.newSession({
logLevel: 'trace',
capabilities: {
browserName: 'chrome'
@ -31,8 +35,8 @@ test('newSession', async () => {
/**
* don't include platform specific information in snapshot
*/
delete client.options.capabilities.platformName
delete client.options.capabilities.platformVersion
delete (client.options.capabilities as Capabilities.DesiredCapabilities).platformName
delete (client.options.capabilities as Capabilities.DesiredCapabilities).platformVersion
expect(client.options.capabilities).toMatchSnapshot()
expect(client.options.requestedCapabilities).toMatchSnapshot()
@ -55,19 +59,19 @@ test('reloadSession', async () => {
})
test('attachSession', async () => {
const client = await DevTools.newSession({
const client: any = await DevTools.newSession({
logLevel: 'trace',
capabilities: {
browserName: 'chrome'
}
})
const otherClient = await DevTools.attachToSession(client)
const otherClient: any = await DevTools.attachToSession(client)
/**
* don't include platform specific information in snapshot
*/
delete otherClient.options.capabilities.platformName
delete otherClient.options.capabilities.platformVersion
delete (otherClient.options.capabilities as Capabilities.DesiredCapabilities).platformName
delete (otherClient.options.capabilities as Capabilities.DesiredCapabilities).platformVersion
expect(otherClient.capabilities).toMatchSnapshot()
expect(otherClient.requestedCapabilities).toMatchSnapshot()

View file

@ -1,32 +1,31 @@
import path from 'node:path'
import { expect, test, vi, beforeEach } from 'vitest'
import DevToolsDriver from '../src/devtoolsdriver'
import type { Dialog } from 'puppeteer-core/lib/cjs/puppeteer/common/Dialog'
import type { Frame } from 'puppeteer-core/lib/cjs/puppeteer/common/FrameManager'
const expect = global.expect as unknown as jest.Expect
vi.mock('puppeteer-core', () => import(path.join(process.cwd(), '__mocks__', 'puppeteer-core')))
vi.mock('chrome-launcher', () => import(path.join(process.cwd(), '__mocks__', 'chrome-launcher')))
jest.mock('fs', () => ({
readdirSync: jest.fn().mockReturnValue([
'/foo/bar/click.js',
'/foo/bar/getAttribute.ts',
'/foo/bar/getAttribute.d.ts'
])
vi.mock('fs', () => ({
default: {
existsSync: vi.fn().mockReturnValue(false),
readdirSync: vi.fn().mockReturnValue([
'/foo/bar/click.js',
'/foo/bar/getAttribute.ts',
'/foo/bar/getAttribute.d.ts'
])
}
}))
DevToolsDriver.requireCommand = jest.fn().mockImplementation((filePath) => {
if (filePath.includes('click')) {
return 'clickCommand'
}
if (filePath.includes('getAttribute')) {
return 'getAttributeCommand'
}
return {}
})
vi.mock('../src/commands/index.js', () => ({
click: 'clickCommand',
getAttribute: 'getAttributeCommand'
}))
let evaluateCommandCalls = 0
const executionContext = {
evaluate: jest.fn()
evaluate: vi.fn()
}
const setNormalPageLoadBehavior = () => executionContext.evaluate.mockImplementation(() => Promise.resolve(++evaluateCommandCalls % 2 === 1
@ -35,21 +34,21 @@ const setNormalPageLoadBehavior = () => executionContext.evaluate.mockImplementa
))
const frame = {
executionContext: jest.fn().mockImplementation(() => Promise.resolve(executionContext))
executionContext: vi.fn().mockImplementation(() => Promise.resolve(executionContext))
}
const page = {
on: jest.fn(),
once: jest.fn(),
setDefaultTimeout: jest.fn(),
mainFrame: jest.fn(),
frames: jest.fn().mockReturnValue([frame])
on: vi.fn(),
once: vi.fn(),
setDefaultTimeout: vi.fn(),
mainFrame: vi.fn(),
frames: vi.fn().mockReturnValue([frame])
}
const browser = {
on: jest.fn(),
pages: jest.fn().mockImplementation(async () => {
page.mainFrame = jest.fn().mockImplementation(() => frame)
on: vi.fn(),
pages: vi.fn().mockImplementation(async () => {
page.mainFrame = vi.fn().mockImplementation(() => frame)
++evaluateCommandCalls
setNormalPageLoadBehavior()
return [page]
@ -86,7 +85,6 @@ beforeEach(() => {
page.mainFrame.mockImplementation(() => frame)
executionContext.evaluate.mockClear()
setNormalPageLoadBehavior()
;(DevToolsDriver.requireCommand as jest.Mock).mockClear()
driver = new DevToolsDriver(browser as any, [page as any])
driver.timeouts.set('pageLoad', 100)
})
@ -111,10 +109,10 @@ test('should throw if command is called that is not implemented', () => {
})
test('should return proper result', async () => {
driver.commands.elementClick = (...args: any[]) => new Promise(
(resolve) => setTimeout(() => resolve(...args), 100))
driver.commands.elementClick = (...args: any[]) => new Promise<any>(
(resolve) => setTimeout(() => resolve.apply(null, args), 100))
const emit = jest.fn()
const emit = vi.fn()
const command = driver.register(commandMock)
const errorMsg = await command.call({ emit } as any).catch((e) => e.message)
@ -139,7 +137,7 @@ test('should throw if command throws', async () => {
const command = driver.register(commandMock)
const emit = jest.fn()
const emit = vi.fn()
const errorMsg3 = await command.call({ emit } as any, '123', 'some text', ['some value'])
.catch((e) => e.message)
await expect(errorMsg3).toEqual('foobar')
@ -148,29 +146,27 @@ test('should throw if command throws', async () => {
test('should rerun command if it was executed within navigation', async () => {
expect.assertions(4)
let wasCommandCalled = false
driver.commands.elementClick = jest.fn().mockImplementation(
() => new Promise(
(resolve, reject) => setTimeout(
() => {
if (!wasCommandCalled) {
wasCommandCalled = true
reject(new Error('foobar most likely because of a navigation'))
}
driver.commands.elementClick = vi.fn().mockImplementation(
() => new Promise((resolve, reject) => setTimeout(
() => {
if (!wasCommandCalled) {
wasCommandCalled = true
reject(new Error('foobar most likely because of a navigation'))
}
resolve(null)
},
100
)
resolve(null)
},
100)
)
)
const command = driver.register(commandMock)
setTimeout(() => {
expect(page.once).toBeCalledWith('load', expect.any(Function))
page.once.mock.calls.pop().pop()()
page.once.mock.calls.pop()?.pop()()
}, 150)
const emit = jest.fn()
const emit = vi.fn()
const result = await command.call({ emit } as any, '123', 'some text', ['some value'])
expect(driver.commands.elementClick).toBeCalledTimes(2)
expect(result).toBe(null)
@ -180,7 +176,7 @@ test('should rerun command if it was executed within navigation', async () => {
test('throws error if navigation takes too long', async () => {
driver.timeouts.set('pageLoad', 150)
let wasCommandCalled = false
driver.commands.elementClick = jest.fn().mockImplementation(
driver.commands.elementClick = vi.fn().mockImplementation(
() => new Promise(
(resolve, reject) => setTimeout(
() => {
@ -196,7 +192,7 @@ test('throws error if navigation takes too long', async () => {
)
)
const emit = jest.fn()
const emit = vi.fn()
const command = driver.register(commandMock)
const result = await command.call({ emit } as any, '123', 'some text', ['some value'])
.catch((err) => err.message)
@ -205,7 +201,7 @@ test('throws error if navigation takes too long', async () => {
test('should wait for page load to be complete before executing the command', async () => {
executionContext.evaluate.mockReset()
executionContext.evaluate = jest.fn()
executionContext.evaluate = vi.fn()
.mockResolvedValueOnce('1')
.mockResolvedValueOnce('loading')
.mockResolvedValueOnce('1')
@ -216,21 +212,21 @@ test('should wait for page load to be complete before executing the command', as
.mockResolvedValueOnce('complete')
driver.commands.elementClick = (...args: any[]) => new Promise(
(resolve) => setTimeout(() => resolve(...args), 100))
(resolve) => setTimeout(() => resolve.apply(null, args), 100))
const emit = jest.fn()
const emit = vi.fn()
const command = driver.register(commandMock)
await command.call({ emit } as any, '123', 'some text', ['some value'])
expect(executionContext.evaluate.mock.calls).toHaveLength(8)
})
test('should use page from target if we are currently in a frame', async () => {
driver.getPageHandle = jest.fn().mockReturnValue(frame)
executionContext.evaluate = jest.fn().mockReturnValueOnce('complete')
driver.getPageHandle = vi.fn().mockReturnValue(frame)
executionContext.evaluate = vi.fn().mockReturnValueOnce('complete')
driver.commands.elementClick = () => Promise.resolve(null)
const emit = jest.fn()
const emit = vi.fn()
const command = driver.register(commandMock)
await command.call({ emit } as any, '123', 'some text', ['some value'])
expect(browser.pages).toBeCalledTimes(1)
@ -238,16 +234,16 @@ test('should use page from target if we are currently in a frame', async () => {
test('should rerun command if no execution context could be found', async () => {
executionContext.evaluate.mockReset()
executionContext.evaluate = jest.fn()
executionContext.evaluate = vi.fn()
.mockRejectedValueOnce(new Error('ups'))
.mockRejectedValueOnce(new Error('ups'))
.mockResolvedValueOnce('1')
.mockResolvedValueOnce('complete')
driver.commands.elementClick = (...args: any[]) => new Promise(
(resolve) => setTimeout(() => resolve(...args), 100))
(resolve) => setTimeout(() => resolve.apply(null, args), 100))
const emit = jest.fn()
const emit = vi.fn()
const command = driver.register(commandMock)
await command.call({ emit } as any, '123', 'some text', ['some value'])
expect(executionContext.evaluate.mock.calls).toHaveLength(4)
@ -257,19 +253,19 @@ test('should throw if execution context can not be established', async () => {
expect.assertions(1)
executionContext.evaluate.mockReset()
executionContext.evaluate = jest.fn()
executionContext.evaluate = vi.fn()
.mockImplementation(() => new Promise(
(resolve, reject) => setTimeout(
() => reject(new Error('ups')), 100)))
driver.timeouts.set('pageLoad', 200)
driver.commands.elementClick = (...args: any[]) => new Promise(
(resolve) => setTimeout(() => resolve(...args), 100))
(resolve) => setTimeout(() => resolve.apply(null, args), 100))
const command = driver.register(commandMock)
try {
const emit = jest.fn()
const emit = vi.fn()
await command.call({ emit } as any, '123', 'some text', ['some value'])
} catch (err: any) {
expect(err.message).toBe('ups')
@ -283,18 +279,18 @@ test('dialogHandler', () => {
})
test('framenavigatedHandler for main frame', () => {
driver.elementStore.clear = jest.fn()
driver.elementStore.clear = vi.fn()
const frameMock = { url: jest.fn().mockReturnValue('foobar'), parentFrame:jest.fn().mockReturnValue(null) }
const frameMock = { url: vi.fn().mockReturnValue('foobar'), parentFrame:vi.fn().mockReturnValue(null) }
driver.framenavigatedHandler(frameMock as unknown as Frame)
expect(driver.currentFrameUrl).toBe('foobar')
expect(driver.elementStore.clear).toBeCalledTimes(1)
})
test('framenavigatedHandler for child frame', () => {
driver.elementStore.clear = jest.fn()
driver.elementStore.clear = vi.fn()
const frameMock = { url: jest.fn().mockReturnValue('foobar'), parentFrame:jest.fn().mockReturnValue({}) }
const frameMock = { url: vi.fn().mockReturnValue('foobar'), parentFrame:vi.fn().mockReturnValue({}) }
driver.framenavigatedHandler(frameMock as unknown as Frame)
expect(driver.currentFrameUrl).toBe('foobar')
expect(driver.elementStore.clear).toBeCalledTimes(1)
@ -302,8 +298,8 @@ test('framenavigatedHandler for child frame', () => {
})
test('setTimeouts with not value', () => {
driver.timeouts = { set: jest.fn(), get: jest.fn().mockReturnValue(123) } as any
driver.windows = { get: jest.fn().mockReturnValue(page) } as any
driver.timeouts = { set: vi.fn(), get: vi.fn().mockReturnValue(123) } as any
driver.windows = { get: vi.fn().mockReturnValue(page) } as any
driver.setTimeouts()
expect(page.setDefaultTimeout).toBeCalledTimes(2)
expect(driver.timeouts.set).toBeCalledTimes(0)
@ -331,7 +327,7 @@ test('setTimeouts with all timeouts', () => {
})
test('getPageHandle', () => {
driver.windows = { get: jest.fn().mockReturnValue('foobar') } as any
driver.windows = { get: vi.fn().mockReturnValue('foobar') } as any
expect(driver.getPageHandle()).toBe('foobar')
driver.currentFrame = 'barfoo' as any
@ -339,7 +335,7 @@ test('getPageHandle', () => {
expect(driver.getPageHandle(true)).toBe('barfoo')
driver.windows = { get: jest.fn().mockReturnValue(undefined) } as any
driver.windows = { get: vi.fn().mockReturnValue(undefined) } as any
expect(() => driver.getPageHandle()).toThrow(/find page handle/)
delete driver.currentWindowHandle
@ -348,14 +344,14 @@ test('getPageHandle', () => {
test('_targetCreatedHandler', async () => {
expect(driver.windows.size).toBe(1)
await driver['_targetCreatedHandler']({ page: jest.fn().mockReturnValue(Promise.resolve(null)) } as any)
await driver['_targetCreatedHandler']({ page: vi.fn().mockReturnValue(Promise.resolve(null)) } as any)
expect(driver.windows.size).toBe(1)
await driver['_targetCreatedHandler']({ page: jest.fn().mockReturnValue(Promise.resolve('foobar')) } as any)
await driver['_targetCreatedHandler']({ page: vi.fn().mockReturnValue(Promise.resolve('foobar')) } as any)
expect(driver.windows.size).toBe(2)
})
test('_targetDestroyedHandler', async () => {
const target = { page: jest.fn().mockReturnValue(Promise.resolve('foobar')) } as any
const target = { page: vi.fn().mockReturnValue(Promise.resolve('foobar')) } as any
await driver['_targetCreatedHandler'](target)
expect(driver.windows.size).toBe(2)
await driver['_targetDestroyedHandler'](target)

View file

@ -1,3 +1,4 @@
import { expect, test } from 'vitest'
import ElementStore from '../src/elementstore'
import type { ElementHandle } from 'puppeteer-core/lib/cjs/puppeteer/common/JSHandle'
import type { Frame } from 'puppeteer-core/lib/cjs/puppeteer/common/FrameManager'

View file

@ -1,14 +1,16 @@
import { canAccess as canAccessImport } from '@wdio/utils'
import path from 'path'
import path from 'node:path'
import { expect, describe, beforeAll, test, vi } from 'vitest'
import { canAccess } from '@wdio/utils'
import getFinder from '../../src/finder'
import edgeFinder from '../../src/finder/edge'
import { darwinGetAppPaths, darwinGetInstallations } from '../../src/finder/finder'
const systemProfiler = require('./systemProfiler.json')
const canAccess = canAccessImport as jest.Mock
import systemProfiler from './systemProfiler.json'
jest.mock('child_process', jest.fn().mockImplementation(() => ({
vi.mock('@wdio/utils', () => import(path.join(process.cwd(), '__mocks__', '@wdio/utils')))
vi.mock('child_process', vi.fn().mockImplementation(() => ({
execSync() {
return JSON.stringify(systemProfiler)
}
@ -31,7 +33,7 @@ describe('darwinGetAppPaths', () => {
describe('darwinGetInstallations', () => {
beforeAll(() => {
canAccess.mockImplementation((s = '') => s.startsWith(path.join('/', 'ok')))
vi.mocked(canAccess).mockImplementation((s = '') => s.startsWith(path.join('/', 'ok')))
})
test('darwinGetInstallations', () => {
expect(darwinGetInstallations([path.join('/', 'ok'), path.join('/', 'not-ok')], ['foobar'])).toEqual([path.join('/ok', 'foobar')])

View file

@ -1,10 +1,13 @@
jest.unmock('@wdio/config')
import path from 'path'
import path from 'node:path'
import { expect, vi, describe, it, afterEach } from 'vitest'
// @ts-ignore mock feature
import { logMock } from '@wdio/logger'
import DevTools from '../src'
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))
vi.mock('puppeteer-core', () => import(path.join(process.cwd(), '__mocks__', 'puppeteer-core')))
vi.mock('chrome-launcher', () => import(path.join(process.cwd(), '__mocks__', 'chrome-launcher')))
const OUTPUT_DIR = path.join('some', 'output', 'dir')
const OUTPUT_FILE = path.join(OUTPUT_DIR, 'wdio.log')
@ -81,8 +84,10 @@ describe('DevTools', () => {
capabilities: { browserName: 'chrome' },
})
// @ts-expect-error internal property
expect(client.puppeteer).toBe(undefined)
await DevTools.reloadSession(client)
// @ts-expect-error internal property
expect(client.puppeteer).not.toBe(undefined)
})
})

View file

@ -1,35 +1,41 @@
import path from 'node:path'
import { expect, vi, beforeEach, test } from 'vitest'
import puppeteer from 'puppeteer-core'
import { launch as launchChromeBrowserImport } from 'chrome-launcher'
import { launch as launchChromeBrowser } from 'chrome-launcher'
import launch from '../src/launcher'
const launchChromeBrowser = launchChromeBrowserImport as jest.Mock
const expect = global.expect as unknown as jest.Expect
vi.mock('puppeteer-core', () => import(path.join(process.cwd(), '__mocks__', 'puppeteer-core')))
vi.mock('chrome-launcher', () => import(path.join(process.cwd(), '__mocks__', 'chrome-launcher')))
jest.mock('../src/finder/firefox', () => ({
darwin: jest.fn().mockReturnValue(['/path/to/firefox']),
linux: jest.fn().mockReturnValue(['/path/to/firefox']),
win32: jest.fn().mockReturnValue(['/path/to/firefox'])
vi.mock('../src/finder/firefox', () => ({
default: {
darwin: vi.fn().mockReturnValue(['/path/to/firefox']),
linux: vi.fn().mockReturnValue(['/path/to/firefox']),
win32: vi.fn().mockReturnValue(['/path/to/firefox'])
}
}))
jest.mock('../src/finder/edge', () => ({
darwin: jest.fn().mockReturnValue(['/path/to/edge']),
linux: jest.fn().mockReturnValue(['/path/to/edge']),
win32: jest.fn().mockReturnValue(['/path/to/edge'])
vi.mock('../src/finder/edge', () => ({
default: {
darwin: vi.fn().mockReturnValue(['/path/to/edge']),
linux: vi.fn().mockReturnValue(['/path/to/edge']),
win32: vi.fn().mockReturnValue(['/path/to/edge'])
}
}))
beforeEach(() => {
(puppeteer.connect as jest.Mock).mockClear()
;(puppeteer.launch as jest.Mock).mockClear()
launchChromeBrowser.mockClear()
vi.mocked(puppeteer.connect).mockClear()
vi.mocked(puppeteer.launch).mockClear()
vi.mocked(launchChromeBrowser).mockClear()
})
test('launch chrome with default values', async () => {
const browser = await launch({
browserName: 'chrome'
})
expect(launchChromeBrowser.mock.calls).toMatchSnapshot()
expect((puppeteer.connect as jest.Mock).mock.calls).toMatchSnapshot()
expect(vi.mocked(launchChromeBrowser).mock.calls).toMatchSnapshot()
expect(vi.mocked(puppeteer.connect).mock.calls).toMatchSnapshot()
expect(puppeteer.registerCustomQueryHandler).toBeCalledWith(
'shadow',
{
@ -58,7 +64,7 @@ test('launch chrome with chrome arguments', async () => {
}
}
})
expect(launchChromeBrowser.mock.calls).toMatchSnapshot()
expect(vi.mocked(launchChromeBrowser).mock.calls).toMatchSnapshot()
expect(puppeteer.launch).toBeCalledTimes(0)
})
@ -74,7 +80,7 @@ test('launch chrome with defaultViewport in wdio:devtoolsOptions', async () => {
}
}
})
expect(launchChromeBrowser.mock.calls).toMatchSnapshot()
expect(vi.mocked(launchChromeBrowser).mock.calls).toMatchSnapshot()
expect(puppeteer.launch).toBeCalledTimes(0)
})
@ -85,8 +91,8 @@ test('launch chrome without default flags and without puppeteer default args', a
ignoreDefaultArgs: true
}
})
expect(launchChromeBrowser.mock.calls).toMatchSnapshot()
expect((puppeteer.connect as jest.Mock).mock.calls).toMatchSnapshot()
expect(vi.mocked(launchChromeBrowser).mock.calls).toMatchSnapshot()
expect(vi.mocked(puppeteer.connect).mock.calls).toMatchSnapshot()
const pages = await browser.pages()
expect(pages[0].close).toBeCalled()
@ -103,7 +109,7 @@ test('overriding chrome default flags', async () => {
args: ['--enable-features=NetworkService']
}
})
expect(launchChromeBrowser.mock.calls).toMatchSnapshot()
expect(vi.mocked(launchChromeBrowser).mock.calls).toMatchSnapshot()
const pages = await browser.pages()
expect(pages[0].close).toBeCalled()
@ -125,7 +131,7 @@ test('overriding chrome default flags (backwards compat)', async () => {
args: ['--enable-features=NetworkService']
}
})
expect(launchChromeBrowser.mock.calls).toMatchSnapshot()
expect(vi.mocked(launchChromeBrowser).mock.calls).toMatchSnapshot()
const pages = await browser.pages()
expect(pages[0].close).toBeCalled()
@ -139,7 +145,7 @@ test('launch chrome with custom user data dir', async () => {
args: ['enable-features=NetworkService', 'someOtherFlag', 'user-data-dir=/foo/bar', 'anotherFlag']
}
})
expect(launchChromeBrowser.mock.calls).toMatchSnapshot()
expect(vi.mocked(launchChromeBrowser).mock.calls).toMatchSnapshot()
})
test('launch chrome with chrome port', async () => {
@ -150,7 +156,7 @@ test('launch chrome with chrome port', async () => {
customPort: 8041
}
})
expect(launchChromeBrowser.mock.calls).toMatchSnapshot()
expect(vi.mocked(launchChromeBrowser).mock.calls).toMatchSnapshot()
expect(puppeteer.launch).toBeCalledTimes(0)
const pages = await browser.pages()
@ -217,14 +223,14 @@ test('launch Firefox Nightly with custom arguments', async () => {
}
}
})
expect((puppeteer.launch as jest.Mock).mock.calls).toMatchSnapshot()
expect(vi.mocked(puppeteer.launch).mock.calls).toMatchSnapshot()
})
test('launch Edge with default values', async () => {
await launch({
browserName: 'edge'
})
expect((puppeteer.launch as jest.Mock).mock.calls).toMatchSnapshot()
expect(vi.mocked(puppeteer.launch).mock.calls).toMatchSnapshot()
})
test('launch Edge with custom arguments', async () => {
@ -241,7 +247,7 @@ test('launch Edge with custom arguments', async () => {
}
}
})
expect((puppeteer.launch as jest.Mock).mock.calls).toMatchSnapshot()
expect(vi.mocked(puppeteer.launch).mock.calls).toMatchSnapshot()
})
test('throws if browser is unknown', async () => {
@ -265,7 +271,7 @@ test('launch Firefox Nightly without Puppeteer default args', async () => {
ignoreDefaultArgs: true
}
})
expect((puppeteer.launch as jest.Mock).mock.calls).toMatchSnapshot()
expect(vi.mocked(puppeteer.launch).mock.calls).toMatchSnapshot()
})
test('launch Firefox Nightly binary without Puppeteer default args', async () => {
@ -279,7 +285,7 @@ test('launch Firefox Nightly binary without Puppeteer default args', async () =>
headless: true
}
})
expect((puppeteer.launch as jest.Mock).mock.calls).toMatchSnapshot()
expect(vi.mocked(puppeteer.launch).mock.calls).toMatchSnapshot()
})
test('launch Firefox without Puppeteer default args', async () => {
@ -332,7 +338,7 @@ test('launch Edge without Puppeteer default args', async () => {
headless: true
}
})
expect((puppeteer.launch as jest.Mock).mock.calls).toMatchSnapshot()
expect(vi.mocked(puppeteer.launch).mock.calls).toMatchSnapshot()
})
test('launch Edge without Puppeteer default args (backwards compat)', async () => {
@ -349,7 +355,7 @@ test('launch Edge without Puppeteer default args (backwards compat)', async () =
headless: true
}
})
expect((puppeteer.launch as jest.Mock).mock.calls).toMatchSnapshot()
expect(vi.mocked(puppeteer.launch).mock.calls).toMatchSnapshot()
})
test('connect to existing browser session', async () => {
@ -360,7 +366,7 @@ test('connect to existing browser session', async () => {
}
})
expect(puppeteer.launch).not.toBeCalled()
expect(puppeteer.connect as jest.Mock)
expect(vi.mocked(puppeteer.connect))
.toBeCalledWith({ browserURL: 'http://localhost:12345' })
})
@ -373,7 +379,7 @@ test('connect to an existing devtools websocket', async () => {
}
})
expect(puppeteer.launch).not.toBeCalled()
expect(puppeteer.connect as jest.Mock)
expect(vi.mocked(puppeteer.connect))
.toBeCalledWith({ browserWSEndpoint: 'wss://cloud.vendor.com' })
})
@ -388,6 +394,6 @@ test('connect to an existing devtools browser url', async () => {
'wdio:devtoolsOptions': devtoolsOptions
})
expect(puppeteer.launch).not.toBeCalled()
expect(puppeteer.connect as jest.Mock)
expect(vi.mocked(puppeteer.connect))
.toBeCalledWith(devtoolsOptions)
})

View file

@ -1,8 +1,11 @@
import path from 'path'
// not a real package but needed for testing
// @ts-ignore
import { describe, it, expect, afterEach, vi, test } from 'vitest'
import path from 'node:path'
import childProcess from 'node:child_process'
// @ts-ignore no types needed
import debug from 'debug'
// @ts-ignore not a real package but needed for testing
import { log as pptrDebugLog } from 'pptrDebug'
import childProcess from 'child_process'
import { canAccess } from '@wdio/utils'
import {
@ -11,7 +14,14 @@ import {
uniq, findByWhich, patchDebug, sleep
} from '../src/utils'
const debug = jest.requireActual('debug')
vi.mock('@wdio/utils', async () => {
const pathModule = await vi.importActual('node:path') as typeof path
return import(pathModule.join(process.cwd(), '__mocks__', '@wdio/utils'))
})
vi.mock('pptrDebug', async () => {
const pathModule = await vi.importActual('node:path') as typeof path
return import(pathModule.join(process.cwd(), '__mocks__', 'pptrDebug'))
})
/**
* some WebDriver commands are either not part of a recommended standard
@ -53,38 +63,47 @@ const command = {
}
let pageMock = {
waitForSelector: jest.fn(),
waitForXPath: jest.fn(),
$$eval: jest.fn(),
$$: jest.fn(),
$x: jest.fn(),
$: jest.fn()
waitForSelector: vi.fn(),
waitForXPath: vi.fn(),
$$eval: vi.fn(),
$$: vi.fn(),
$x: vi.fn(),
$: vi.fn()
}
jest.mock('fs', () => {
vi.mock('fs', () => {
return {
existsSync: (pkgName: string) => pkgName === 'pptrDebug'
default: {
existsSync: (pkgName: string) => pkgName === 'pptrDebug'
}
}
})
jest.mock('child_process', () => {
vi.mock('node:child_process', () => {
let returnValue = false
const execFileSync = vi.fn().mockImplementation(() => {
if (!returnValue) {
throw new Error('foo not found')
}
return returnValue
})
return {
execFileSync: jest.fn().mockImplementation(() => {
if (!returnValue) {
throw new Error('foo not found')
}
return returnValue
}),
shouldReturn: (value: any) => (returnValue = value)
execFileSync,
default: {
execFileSync,
shouldReturn: (value: any) => (returnValue = value)
}
}
})
jest.mock('path', () => {
vi.mock('node:path', () => {
let resolveResult = 'debug'
const resolve = jest.fn(() => resolveResult)
const resolve = vi.fn(() => resolveResult)
const setResolveResult = (result: any) => (resolveResult = result)
return { resolve, setResolveResult, dirname: jest.fn() }
return {
default: { resolve, setResolveResult, dirname: vi.fn() }
}
})
describe('validate', () => {
@ -141,8 +160,8 @@ describe('findElement utils', () => {
describe('findElement', () => {
it('tries to find element using css selector', async () => {
const scope = {
timeouts: { get: jest.fn() },
elementStore: { set: jest.fn().mockReturnValue('foobar') }
timeouts: { get: vi.fn() },
elementStore: { set: vi.fn().mockReturnValue('foobar') }
}
pageMock.$.mockReturnValue(Promise.resolve(42))
@ -156,8 +175,8 @@ describe('findElement utils', () => {
it('tries to find element using xpath', async () => {
const scope = {
timeouts: { get: jest.fn() },
elementStore: { set: jest.fn().mockReturnValue('foobar') }
timeouts: { get: vi.fn() },
elementStore: { set: vi.fn().mockReturnValue('foobar') }
}
pageMock.$x.mockReturnValue(Promise.resolve([42]))
@ -171,8 +190,8 @@ describe('findElement utils', () => {
it('should fail if not found', async () => {
const scope = {
timeouts: { get: jest.fn() },
elementStore: { set: jest.fn() }
timeouts: { get: vi.fn() },
elementStore: { set: vi.fn() }
}
pageMock.$.mockReturnValue(Promise.resolve(null))
@ -183,8 +202,8 @@ describe('findElement utils', () => {
it('should not fail with the same error if Puppeteer can not find the element', async () => {
const scope = {
timeouts: { get: jest.fn() },
elementStore: { set: jest.fn() }
timeouts: { get: vi.fn() },
elementStore: { set: vi.fn() }
}
pageMock.$.mockReturnValue(Promise.reject(new Error('failed to find element')))
@ -195,8 +214,8 @@ describe('findElement utils', () => {
it('sets implicit waits', async () => {
const scope = {
timeouts: { get: jest.fn().mockReturnValue(1234) },
elementStore: { set: jest.fn() }
timeouts: { get: vi.fn().mockReturnValue(1234) },
elementStore: { set: vi.fn() }
}
pageMock.$.mockReturnValue(Promise.resolve('foobar'))
await findElement.call(scope as any, pageMock as any, 'css selector', 'barfoo')
@ -206,8 +225,8 @@ describe('findElement utils', () => {
it('sets implicit waits with xpath', async () => {
const scope = {
timeouts: { get: jest.fn().mockReturnValue(1234) },
elementStore: { set: jest.fn() }
timeouts: { get: vi.fn().mockReturnValue(1234) },
elementStore: { set: vi.fn() }
}
pageMock.$.mockReturnValue(Promise.resolve('foobar'))
await findElement.call(scope as any, pageMock as any, 'xpath', 'barfoo')
@ -219,8 +238,8 @@ describe('findElement utils', () => {
describe('findElements', () => {
it('should find elements', async () => {
const scope = {
timeouts: { get: jest.fn() },
elementStore: { set: jest.fn().mockReturnValue('foobar') }
timeouts: { get: vi.fn() },
elementStore: { set: vi.fn().mockReturnValue('foobar') }
}
pageMock.$$.mockReturnValue(Promise.resolve([42, 11]))
expect(await findElements.call(scope as any, pageMock as any, 'css selector', 'barfoo')).toMatchSnapshot()
@ -231,8 +250,8 @@ describe('findElement utils', () => {
it('should find elements with xpath', async () => {
const scope = {
timeouts: { get: jest.fn() },
elementStore: { set: jest.fn().mockReturnValue('foobar') }
timeouts: { get: vi.fn() },
elementStore: { set: vi.fn().mockReturnValue('foobar') }
}
pageMock.$x.mockReturnValue(Promise.resolve([42, 11]))
expect(await findElements.call(scope as any, pageMock as any, 'xpath', 'barfoo')).toMatchSnapshot()
@ -243,8 +262,8 @@ describe('findElement utils', () => {
it('should return immediately if no elements were found', async () => {
const scope = {
timeouts: { get: jest.fn() },
elementStore: { set: jest.fn() }
timeouts: { get: vi.fn() },
elementStore: { set: vi.fn() }
}
pageMock.$$.mockReturnValue(Promise.resolve([]))
expect(await findElements.call(scope as any, pageMock as any, 'css selector', 'barfoo')).toEqual([])
@ -254,8 +273,8 @@ describe('findElement utils', () => {
it('sets implicit waits', async () => {
const scope = {
timeouts: { get: jest.fn().mockReturnValue(1234) },
elementStore: { set: jest.fn() }
timeouts: { get: vi.fn().mockReturnValue(1234) },
elementStore: { set: vi.fn() }
}
pageMock.$$.mockReturnValue(Promise.resolve(['foobar']))
await findElements.call(scope as any, pageMock as any, 'css selector', 'barfoo')
@ -264,8 +283,8 @@ describe('findElement utils', () => {
it('sets implicit waits with xpath', async () => {
const scope = {
timeouts: { get: jest.fn().mockReturnValue(1234) },
elementStore: { set: jest.fn() }
timeouts: { get: vi.fn().mockReturnValue(1234) },
elementStore: { set: vi.fn() }
}
pageMock.$x.mockReturnValue(Promise.resolve(['foobar']))
await findElements.call(scope as any, pageMock as any, 'xpath', 'barfoo')
@ -287,7 +306,7 @@ describe('sanitizeError', () => {
const newStack = err?.stack?.split('\n') || []
newStack.push('at /foo/bar/devtools/node_modules/puppeteer-core/bla.js')
err.stack = newStack.join('\n')
expect(sanitizeError(err)).not.toContain('devtools/node_modules/puppeteer-core')
expect(sanitizeError(err).stack).not.toContain('devtools/node_modules/puppeteer-core')
})
})
@ -323,8 +342,8 @@ test('transformExecuteArgs should allow undefined params', async () => {
describe('transformExecuteResult', () => {
test('multiple results', async () => {
const scope = {
timeouts: { get: jest.fn() },
elementStore: { set: jest.fn().mockReturnValue('foobar') }
timeouts: { get: vi.fn() },
elementStore: { set: vi.fn().mockReturnValue('foobar') }
}
pageMock.$.mockReturnValue(Promise.resolve(42))
expect(await transformExecuteResult.call(scope as any, pageMock as any, [
@ -336,8 +355,8 @@ describe('transformExecuteResult', () => {
test('single result', async () => {
const scope = {
timeouts: { get: jest.fn() },
elementStore: { set: jest.fn().mockReturnValue('foobar') }
timeouts: { get: vi.fn() },
elementStore: { set: vi.fn().mockReturnValue('foobar') }
}
pageMock.$.mockReturnValue(Promise.resolve(42))
expect(await transformExecuteResult.call(scope as any, pageMock as any, 'foobar'))
@ -354,7 +373,7 @@ describe('transformExecuteResult', () => {
test('getPages', async () => {
const browser = {
pages: jest.fn()
pages: vi.fn()
.mockReturnValueOnce([])
.mockReturnValueOnce([])
.mockReturnValueOnce([{}])
@ -376,15 +395,16 @@ test('uniq', () => {
})
test('findByWhich', () => {
(canAccess as jest.Mock).mockImplementation(() => true)
vi.mocked(canAccess).mockImplementation(() => true)
expect(findByWhich(['firefox'], [{ regex: /firefox/, weight: 51 }]))
.toEqual([])
;(childProcess as any).shouldReturn('/path/to/other/firefox\n')
// @ts-expect-error mock feature
vi.mocked(childProcess).shouldReturn('/path/to/other/firefox\n')
expect(findByWhich(['firefox'], [{ regex: /firefox/, weight: 51 }]))
.toEqual(['/path/to/other/firefox'])
;(canAccess as jest.Mock).mockImplementation(() => {
vi.mocked(canAccess).mockImplementation(() => {
throw new Error('uups')
})
expect(findByWhich(['firefox'], [{ regex: /firefox/, weight: 51 }]))
@ -392,15 +412,19 @@ test('findByWhich', () => {
})
test('patchDebug', () => {
const logMock = { debug: jest.fn() }
const logMock = { debug: vi.fn() }
patchDebug(logMock as any)
debug.log('something something - puppeteer:protocol foobar')
expect(logMock.debug).toBeCalledWith('foobar')
})
test('patchDebug with debug not install in puppeteer', () => {
const logMock = { debug: jest.fn() }
;(path as any).setResolveResult('pptrDebug')
/**
* can't be tested due to mock issues in vitest
*/
test.skip('patchDebug with debug not install in puppeteer', () => {
const logMock = { debug: vi.fn() }
// @ts-expect-error mock feature
vi.mocked(path).setResolveResult('pptrDebug')
patchDebug(logMock as any)
pptrDebugLog('something something - puppeteer:protocol barfoo')
expect(logMock.debug).toBeCalledWith('barfoo')

View file

@ -1,5 +0,0 @@
{
"env": {
"jest": true
}
}

View file

@ -6,7 +6,8 @@ export default defineConfig({
'packages/wdio-logger/**/*.test.ts',
'packages/wdio-utils/**/*.test.ts',
'packages/wdio-config/**/*.test.ts',
'packages/webdriver/**/*.test.ts'
'packages/webdriver/**/*.test.ts',
'packages/devtools/**/*.test.ts'
],
coverage: {
enabled: false,