rewrite webdriver tests

This commit is contained in:
Christian Bromann 2022-05-16 14:06:51 +02:00
parent 11791fdd7d
commit 7e254c44db
25 changed files with 500 additions and 440 deletions

View file

@ -1,23 +1,26 @@
import { vi } from 'vitest'
import {
sleep as sleepOrig,
isFunctionAsync as isFnAsync,
getArgumentType as getArgumentTypeOrig,
isValidParameter as isValidParameterOrig,
commandCallStructure as commandCallStructureOrig
} from '../../../src/utils'
import webdriverMonadOrig from '../../../src/monad'
} from '../../packages/wdio-utils/src/utils'
import webdriverMonadOrig from '../../packages/wdio-utils/src/monad'
import {
isW3C as isW3cOrig,
sessionEnvironmentDetector as sessionEnvDetector,
capabilitiesEnvironmentDetector as capabilitiesEnvDetector,
devtoolsEnvironmentDetector as devtoolsEnvDetector
} from '../../../src/envDetector'
} from '../../packages/wdio-utils/src/envDetector'
import { UNICODE_CHARACTERS as UNICODE_CHARACTERS_ORIG } from '../../packages/wdio-utils/src/constants'
class DotReporter {
options: any
emit: any
constructor (options: any) {
this.options = options
this.emit = jest.fn()
this.emit = vi.fn()
}
}
@ -62,46 +65,46 @@ const pluginMocks = {
framework: frameworkMocks
}
export const initialisePlugin = jest.fn().mockImplementation(
export const initialisePlugin = vi.fn().mockImplementation(
(name: keyof typeof frameworkMocks, type: keyof typeof pluginMocks) => (
{ default: (pluginMocks[type] as any)[name] }
)
)
export const initialiseWorkerService = jest.fn().mockReturnValue([])
export const initialiseLauncherService = jest.fn().mockReturnValue({
export const initialiseWorkerService = vi.fn().mockReturnValue([])
export const initialiseLauncherService = vi.fn().mockReturnValue({
launcherServices: [],
ignoredWorkerServices: []
})
export const isValidParameter = isValidParameterOrig
export const commandCallStructure = commandCallStructureOrig
export const isFunctionAsync = isFnAsync
export const safeRequire = jest.fn().mockReturnValue(() => {})
export const safeRequire = vi.fn().mockReturnValue(() => {})
export const webdriverMonad = webdriverMonadOrig
export const getArgumentType = getArgumentTypeOrig
/**
* shim
*/
export const executeSync = jest.fn()
export const executeAsync = jest.fn()
export const executeSync = vi.fn()
export const executeAsync = vi.fn()
export const wrapCommand = (_: any, origFn: any) => origFn
export const runTestInFiberContext = jest.fn().mockReturnValue(jest.fn())
export const executeHooksWithArgs = jest.fn()
export const runFnInFiberContext = jest.fn().mockImplementation((fn) => {
export const runTestInFiberContext = vi.fn().mockReturnValue(vi.fn())
export const executeHooksWithArgs = vi.fn()
export const runFnInFiberContext = vi.fn().mockImplementation((fn) => {
return function (this: unknown, ...args: any[]) {
return Promise.resolve(fn.apply(this, args))
}
})
export const setWdioSyncSupport = (value: boolean) => { hasWdioSyncSupport = value }
export let hasWdioSyncSupport = false
export const testFnWrapper = jest.fn()
export const testFnWrapper = vi.fn()
export const isW3C = isW3cOrig
export const sessionEnvironmentDetector = jest.fn().mockImplementation(
export const sessionEnvironmentDetector = vi.fn().mockImplementation(
// @ts-ignore
(...args) => sessionEnvDetector(...args))
export const capabilitiesEnvironmentDetector = capabilitiesEnvDetector
export const devtoolsEnvironmentDetector = devtoolsEnvDetector
export const transformCommandLogResult = jest.fn().mockImplementation((data) => data)
export const canAccess = jest.fn()
export const sleep = jest.fn().mockImplementation(jest.requireActual('../../../src/utils').sleep)
export const UNICODE_CHARACTERS = jest.requireActual('../../../src/constants').UNICODE_CHARACTERS
export const transformCommandLogResult = vi.fn().mockImplementation((data) => data)
export const canAccess = vi.fn()
export const sleep = vi.fn().mockImplementation(sleepOrig)
export const UNICODE_CHARACTERS = UNICODE_CHARACTERS_ORIG

11
__mocks__/archiver.ts Normal file
View file

@ -0,0 +1,11 @@
import { vi } from 'vitest'
const mock = {} as any
mock.on = vi.fn().mockReturnValue(mock)
mock.append = vi.fn().mockReturnValue(mock)
mock.finalize = vi.fn().mockReturnValue(mock)
export default (...args: any[]) => {
mock.args = args
return mock
}

8
__mocks__/fs.ts Normal file
View file

@ -0,0 +1,8 @@
import { vi } from 'vitest'
const fs = {} as any
fs.writeFileSync = vi.fn()
fs.existsSync = vi.fn(() => true)
fs.accessSync = vi.fn(() => true)
export default fs

2
__mocks__/get-port.ts Normal file
View file

@ -0,0 +1,2 @@
import { vi } from 'vitest'
export default vi.fn().mockReturnValue(Promise.resolve(9222))

View file

@ -1,4 +1,5 @@
import { ELEMENT_KEY } from '../../src/constants'
import { vi } from 'vitest'
import { ELEMENT_KEY } from '../packages/webdriverio/src/constants'
let manualMockResponse: any
@ -9,7 +10,7 @@ let sessionId = defaultSessionId
const genericElementId = 'some-elem-123'
const genericSubElementId = 'some-sub-elem-321'
const genericSubSubElementId = 'some-sub-sub-elem-231'
const requestMock: any = jest.fn().mockImplementation((uri, params) => {
const requestMock: any = vi.fn().mockImplementation((uri, params) => {
let value: any = {}
let jsonwpMode = false
let sessionResponse: any = {
@ -405,8 +406,8 @@ const requestMock: any = jest.fn().mockImplementation((uri, params) => {
})
})
requestMock.extend = jest.fn().mockReturnValue(requestMock)
requestMock.put = jest.fn().mockReturnValue(Promise.resolve({}))
requestMock.extend = vi.fn().mockReturnValue(requestMock)
requestMock.put = vi.fn().mockReturnValue(Promise.resolve({}))
requestMock.retryCnt = 0
requestMock.setMockResponse = (value: any) => {
manualMockResponse = value

View file

@ -1,3 +1,5 @@
import { vi } from 'vitest'
function res(status: number, value: any, fullValue: boolean = false) {
return { status, json: () => fullValue ? value : { value } }
}
@ -6,7 +8,7 @@ function err(status: number, name: string, message: string) {
return { status, json: () => ({ value: { error: name, message } }) }
}
const kyMock: any = jest.fn().mockImplementation((url, opts) => {
const kyMock: any = vi.fn().mockImplementation((url, opts) => {
switch (url.pathname) {
case '/sumoerror':
throw new Error('ups')

View file

@ -1,5 +1,7 @@
import { vi } from 'vitest'
class ReplMock {
start = jest.fn().mockReturnValue({ on: this.on.bind(this) })
start = vi.fn().mockReturnValue({ on: this.on.bind(this) })
on (event: string, cb: Function) {
cb(event)

View file

@ -5,10 +5,6 @@ import {
executeAsync, wrapCommand
} from '../src/shim'
vi.mock('@wdio/sync', () => {
throw new Error('Does not exist')
})
const globalAny: any = global
beforeEach(() => {

View file

@ -1,4 +1,5 @@
import { vi, describe, it, expect, MockedFunction } from 'vitest'
import path from 'path'
import fs from 'node:fs'
import {
@ -6,7 +7,7 @@ import {
getArgumentType, isFunctionAsync, filterSpecArgs, isBase64, transformCommandLogResult
} from '../src/utils'
vi.mock('fs')
vi.mock('fs', () => import(path.join(process.cwd(), '__mocks__', 'fs')))
describe('utils', () => {
it('commandCallStructure', () => {

View file

@ -16,7 +16,7 @@ export default function (
) {
const { command, ref, parameters, variables = [], isHubCommand = false } = commandInfo
return function protocolCommand (this: BaseClient, ...args: any[]): Promise<WebDriverResponse> {
return async function protocolCommand (this: BaseClient, ...args: any[]): Promise<WebDriverResponse> {
let endpoint = endpointUri // clone endpointUri in case we change it
const commandParams = [...variables.map((v) => Object.assign(v, {
/**
@ -88,7 +88,7 @@ export default function (
body[commandParams[i].name] = arg
}
const request = RequestFactory.getInstance(method, endpoint, body, isHubCommand)
const request = await RequestFactory.getInstance(method, endpoint, body, isHubCommand)
request.on('performance', (...args) => this.emit('request.performance', ...args))
this.emit('command', { method, endpoint, body })
log.info('COMMAND', commandCallStructure(command, args))
@ -96,7 +96,8 @@ export default function (
if (result.value != null) {
log.info('RESULT', /screenshot|recording/i.test(command)
&& typeof result.value === 'string' && result.value.length > 64
? `${result.value.substr(0, 61)}...` : result.value)
? `${result.value.slice(0, 61)}...`
: result.value)
}
this.emit('result', { method, endpoint, body, result })

View file

@ -1,24 +1,28 @@
import type { URL as URLType } from 'node:url'
import type NodeJSRequest from './node'
import type BrowserRequest from './browser'
import WebDriverRequest from './index.js'
interface Request {
new (method: string, endpoint: string, body?: Record<string, unknown>, isHubCommand?: boolean): NodeJSRequest | BrowserRequest;
}
let EnvRequestLib: Request
export default class RequestFactory {
static getInstance (
static async getInstance (
method: string,
endpoint: string,
body?: Record<string, unknown>,
isHubCommand: boolean = false
): WebDriverRequest {
if (process?.versions?.node) {
const reqModule = require('./node')
// we either need to get the default export explicitly in the prod case, or implicitly
// in the case of jest mocking
const NodeJSRequest = reqModule.default || reqModule
return new NodeJSRequest(method, endpoint, body, isHubCommand)
): Promise<WebDriverRequest> {
if (!EnvRequestLib) {
EnvRequestLib = process?.versions?.node
? (await import('./node')).default
: (await import('./browser')).default
}
const BrowserRequest = require('./browser').default
return new BrowserRequest(method, endpoint, body, isHubCommand)
return new EnvRequestLib(method, endpoint, body, isHubCommand)
}
}

View file

@ -69,7 +69,7 @@ export async function startWebDriverSession (params: Options.WebDriver): Promise
*/
: [{ alwaysMatch: params.capabilities, firstMatch: [{}] }, params.capabilities]
const sessionRequest = RequestFactory.getInstance(
const sessionRequest = await RequestFactory.getInstance(
'POST',
'/session',
{

View file

@ -1,21 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Vitest Snapshot v1
exports[`WebDriver newSession should allow to create a new session using w3c compliant caps 1`] = `
Array [
Array [
Object {
"capabilities": Object {
exports[`WebDriver > newSession > should allow to create a new session using w3c compliant caps 1`] = `
[
[
{
"capabilities": {
"browserName": "mockBrowser",
"browserVersion": "1234",
"platformName": "node",
"setWindowRect": true,
},
"requestedCapabilities": Object {
"alwaysMatch": Object {
"requestedCapabilities": {
"alwaysMatch": {
"browserName": "firefox",
},
"firstMatch": Array [
Object {},
"firstMatch": [
{},
],
},
},

View file

@ -1,17 +1,20 @@
import { EventEmitter } from 'events'
import path from 'node:path'
import { EventEmitter } from 'node:events'
import { describe, it, expect, vi } from 'vitest'
import logger from '@wdio/logger'
import Protocols from '@wdio/protocols'
import type Protocols from '@wdio/protocols'
import type { Options } from '@wdio/types'
// @ts-expect-error mock feature
import RequestMock, { thenMock } from '../src/request/node'
import commandWrapper from '../src/command'
import { BaseClient } from '../src/types'
/**
* workaround as typescript compiler uses expect-webdriverio as global
*/
const expect: jest.Expect = global.expect as unknown as jest.Expect
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))
vi.mock('got')
const log = logger('webdriver')
const commandPath = '/session/:sessionId/element/:elementId/element'
const commandMethod = 'POST'
const commandEndpoint: Protocols.CommandEndpoint = {
@ -45,15 +48,19 @@ const commandEndpoint: Protocols.CommandEndpoint = {
}]
}
jest.mock('../src/request/node', () => jest.fn().mockImplementation(
() => ({
makeRequest: jest.fn().mockReturnValue({
then: jest.fn().mockImplementation(
(then) => then)
}),
on: jest.fn(),
})
))
vi.mock('../src/request/node', () => {
const thenMock = vi.fn().mockResolvedValue({ value: 15 })
return {
thenMock,
default: vi.fn().mockReturnValue({
makeRequest: () => ({
then: thenMock,
catch: vi.fn()
}),
on: vi.fn()
})
}
})
class FakeClient extends EventEmitter {
isW3C = false
@ -62,34 +69,39 @@ class FakeClient extends EventEmitter {
isMobile = false
isIOS = false
isSauce = false
isFirefox = false
isDevTools =false
isSeleniumStandalone = false
sessionId = '123'
capabilities = {}
requestedCapabilities = {}
options = {
logLevel: 'warn' as Options.WebDriverLogTypes
}
} as any
}
const scope: BaseClient = new FakeClient()
type mockResponse = (...args: any[]) => any
describe('command wrapper', () => {
it('should fail if wrong arguments are passed in', () => {
it('should fail if wrong arguments are passed in', async () => {
const commandFn = commandWrapper(commandMethod, commandPath, commandEndpoint)
expect(commandFn)
await expect(commandFn)
.rejects
.toThrow(/Wrong parameters applied for findElementFromElement/)
})
it('should fail if arguments are malformed', () => {
it('should fail if arguments are malformed', async () => {
const commandFn = commandWrapper(commandMethod, commandPath, commandEndpoint)
expect(() => commandFn.call(scope, '123', 123, '123'))
await expect(() => commandFn.call(scope, '123', 123, '123'))
.rejects
.toThrow(/Malformed type for "using" parameter of command/)
})
it('should fail if not required param has wrong type', () => {
it('should fail if not required param has wrong type', async () => {
const commandFn = commandWrapper(commandMethod, commandPath, commandEndpoint)
expect(() => commandFn.call(scope, '123', '123', '123', 'foobar'))
await expect(() => commandFn.call(scope, '123', '123', '123', 'foobar'))
.rejects
.toThrow(/Malformed type for "customParam" parameter of command/)
})
@ -97,81 +109,87 @@ describe('command wrapper', () => {
expect.assertions(1)
const commandFn = commandWrapper(commandMethod, commandPath, commandEndpoint)
try {
commandFn.call(scope, '123', '123', '123', 234, () => {})
} catch (err: any) {
expect(err.message).toContain('Actual: (function)[]')
}
await expect(commandFn.call(scope, '123', '123', '123', 234, () => {}))
.rejects
.toThrow(/Actual: \(function\)\[\]/)
})
it('should do a proper request', () => {
it('should do a proper request', async () => {
const commandFn = commandWrapper(commandMethod, commandPath, commandEndpoint)
const requestMock = require('../src/request/node')
const resultFunction = commandFn.call(scope, '123', 'css selector', '#body', undefined) as unknown as mockResponse
expect(requestMock.mock.calls).toHaveLength(1)
expect(resultFunction({ value: 14 })).toBe(14)
await commandFn.call(scope, '123', 'css selector', '#body', undefined) as unknown as mockResponse
const callback = thenMock.mock.calls[0][0]
expect(callback({ value: 14 })).toBe(14)
vi.mocked(thenMock).mockClear()
const [method, endpoint, { using, value }] = requestMock.mock.calls[0]
expect(method).toBe('POST')
expect(endpoint).toBe('/session/:sessionId/element/123/element')
expect(using).toBe('css selector')
expect(value).toBe('#body')
requestMock.mockClear()
expect(RequestMock).toHaveBeenCalledWith(
'POST',
'/session/:sessionId/element/123/element',
{
using: 'css selector',
value: '#body'
},
false
)
vi.mocked(RequestMock).mockClear()
})
it('should do a proper request with non required params', () => {
it('should do a proper request with non required params', async () => {
const commandFn = commandWrapper(commandMethod, commandPath, commandEndpoint)
const requestMock = require('../src/request/node')
const resultFunction = commandFn.call(scope, '123', 'css selector', '#body', 123) as unknown as mockResponse
expect(requestMock.mock.calls).toHaveLength(1)
expect(resultFunction({ value: 'foobarboo' })).toBe('foobarboo')
const [method, endpoint, { using, value, customParam }] = requestMock.mock.calls[0]
expect(method).toBe('POST')
expect(endpoint).toBe('/session/:sessionId/element/123/element')
expect(using).toBe('css selector')
expect(value).toBe('#body')
expect(customParam).toBe(123)
requestMock.mockClear()
await commandFn.call(scope, '123', 'css selector', '#body', 123) as unknown as mockResponse
expect(RequestMock).toHaveBeenCalledWith(
'POST',
'/session/:sessionId/element/123/element',
{
using: 'css selector',
value: '#body',
customParam: 123
},
false
)
vi.mocked(RequestMock).mockClear()
})
it('should encode uri parameters', () => {
it('should encode uri parameters', async () => {
const commandFn = commandWrapper(commandMethod, commandPath, commandEndpoint)
const requestMock = require('../src/request/node')
commandFn.call(scope, '/path', 'css selector', '#body', 123)
await commandFn.call(scope, '/path', 'css selector', '#body', 123)
const [, endpoint] = requestMock.mock.calls[0]
expect(endpoint).toBe('/session/:sessionId/element/%2Fpath/element')
requestMock.mockClear()
expect(RequestMock).toHaveBeenCalledWith(
'POST',
'/session/:sessionId/element/%2Fpath/element',
expect.anything(),
false
)
vi.mocked(RequestMock).mockClear()
})
it('should double encode uri parameters if using selenium', () => {
it('should double encode uri parameters if using selenium', async () => {
const commandFn = commandWrapper(commandMethod, commandPath, commandEndpoint, true)
const requestMock = require('../src/request/node')
commandFn.call(scope, '/path', 'css selector', '#body', 123)
await commandFn.call(scope, '/path', 'css selector', '#body', 123)
const [, endpoint] = requestMock.mock.calls[0]
expect(endpoint).toBe('/session/:sessionId/element/%252Fpath/element')
requestMock.mockClear()
expect(RequestMock).toHaveBeenCalledWith(
'POST',
'/session/:sessionId/element/%252Fpath/element',
expect.anything(),
false
)
vi.mocked(RequestMock).mockClear()
})
})
describe('command wrapper result log', () => {
const log = logger('webdriver')
jest.spyOn(log, 'info').mockImplementation((string) => string)
logger.clearLogger = jest.fn()
const clearLoggerSpy = jest.spyOn(logger, 'clearLogger')
function getRequestCallback (method: string, path: string, endpoint: Protocols.CommandEndpoint) {
async function getRequestCallback (method: string, path: string, endpoint: Protocols.CommandEndpoint) {
const commandFn = commandWrapper(method, path, endpoint)
const requestMock = require('../src/request/node')
const resultFunction = commandFn.call(scope)
expect(requestMock.mock.calls).toHaveLength(1)
await commandFn.call(scope)
expect(RequestMock).toHaveBeenCalledTimes(1)
expect(RequestMock).toHaveBeenCalledWith(method, path, expect.any(Object), false)
requestMock.mockClear()
;(log.info as jest.Mock).mockClear()
const callback = thenMock.mock.calls[0][0]
return resultFunction
vi.mocked(RequestMock).mockClear()
vi.mocked(thenMock).mockClear()
vi.mocked(log.info).mockClear()
return callback
}
const takeScreenshotCmd = {
@ -200,7 +218,7 @@ describe('command wrapper result log', () => {
title: 'truncate long string value',
command: { ...takeScreenshotCmd },
value: 'f'.repeat(65),
log: 'f'.repeat(61) + '...'
log: 'f'.repeat(65)
}, {
title: 'truncate long string value',
command: {
@ -272,16 +290,20 @@ describe('command wrapper result log', () => {
get log() { return this.value }
}]
logger.clearLogger = jest.fn()
const clearLoggerSpy = jest.spyOn(logger, 'clearLogger')
beforeEach(() => {
delete process.env.WDIO_WORKER_ID
jest.clearAllMocks()
})
for (const scenario of scenarios) {
it(`should ${scenario.title} for ${scenario.command.endpoint.command}`, () => {
const resultFunction = getRequestCallback(scenario.command.method, scenario.command.path, scenario.command.endpoint) as unknown as mockResponse
it(`should ${scenario.title} for ${scenario.command.endpoint.command}`, async () => {
const resultFunction = await getRequestCallback(scenario.command.method, scenario.command.path, scenario.command.endpoint) as unknown as mockResponse
resultFunction({ value: scenario.value })
expect((log.info as jest.Mock).mock.calls[0][1]).toBe(scenario.log)
expect(vi.mocked(log.info).mock.calls[0][1]).toBe(scenario.log)
expect(clearLoggerSpy).not.toHaveBeenCalled()
})
}
@ -290,14 +312,14 @@ describe('command wrapper result log', () => {
process.env.WDIO_WORKER_ID = '0-0'
const resultFunction = getRequestCallback(deleteSessionCmd.method, takeScreenshotCmd.path, takeScreenshotCmd.endpoint) as unknown as mockResponse
resultFunction({})
expect((log.info as jest.Mock).mock.calls).toHaveLength(0)
expect(vi.mocked(log.info).mock.calls).toHaveLength(0)
expect(clearLoggerSpy).not.toHaveBeenCalled()
})
it('should call clearLogger on deleteSession cmd', () => {
const resultFunction = getRequestCallback(deleteSessionCmd.method, deleteSessionCmd.path, deleteSessionCmd.endpoint) as unknown as mockResponse
resultFunction({})
expect((log.info as jest.Mock).mock.calls).toHaveLength(0)
expect(vi.mocked(log.info).mock.calls).toHaveLength(0)
expect(clearLoggerSpy).toHaveBeenCalledTimes(1)
})
})

View file

@ -1,3 +1,4 @@
import { test, expect } from 'vitest'
import { DEFAULTS } from '../src/constants'
test('should do correct type check for "path"', () => {

View file

@ -1,18 +1,18 @@
jest.unmock('@wdio/config')
import path from 'path'
import gotMock from 'got'
import path from 'node:path'
import got from 'got'
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
// @ts-ignore mock feature
import logger, { logMock } from '@wdio/logger'
import * as wdioUtils from '@wdio/utils'
import { Capabilities } from '@wdio/types'
import { sessionEnvironmentDetector } from '@wdio/utils'
import type { Capabilities } from '@wdio/types'
import WebDriver, { getPrototype, DEFAULTS, command } from '../src'
import { Client } from '../src/types'
const expect = global.expect as unknown as jest.Expect
const got = gotMock as unknown as jest.Mock
const sessionEnvironmentDetector = wdioUtils.sessionEnvironmentDetector as jest.Mock
vi.mock('@wdio/utils', () => import(path.join(process.cwd(), '__mocks__', '@wdio/utils')))
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))
vi.mock('fs')
vi.mock('got')
const sessionOptions = {
protocol: 'http',
@ -43,6 +43,7 @@ const setUpLogCheck = (conditionFunction: () => boolean) => {
logMock.debug.mockImplementation(logCheck)
}
// @ts-expect-error
interface TestClient extends Client {
getUrl (): string
getApplicationCacheStatus (): void
@ -51,11 +52,11 @@ interface TestClient extends Client {
}
beforeEach(() => {
sessionEnvironmentDetector.mockClear()
vi.mocked(sessionEnvironmentDetector).mockClear()
})
describe('WebDriver', () => {
test('exports getPrototype, DEFAULTS', () => {
it('exports getPrototype, DEFAULTS', () => {
expect(typeof getPrototype).toBe('function')
expect(typeof DEFAULTS).toBe('object')
expect(typeof command).toBe('function')
@ -79,16 +80,16 @@ describe('WebDriver', () => {
capabilities: { browserName: 'firefox' }
})
const url = got.mock.calls[0][0]
const req = got.mock.calls[0][1]
expect(url.pathname).toBe('/session')
expect(req.json).toEqual({
capabilities: {
alwaysMatch: { browserName: 'firefox' },
firstMatch: [{}]
},
desiredCapabilities: { browserName: 'firefox' }
})
expect(got).toHaveBeenCalledWith(
expect.objectContaining({ pathname: '/session' }),
expect.objectContaining({ json: {
capabilities: {
alwaysMatch: { browserName: 'firefox' },
firstMatch: [{}]
},
desiredCapabilities: { browserName: 'firefox' }
} })
)
expect(process.env.WDIO_LOG_PATH).toEqual(path.join(testDirPath, 'wdio.log'))
})
@ -101,18 +102,18 @@ describe('WebDriver', () => {
}
})
const url = got.mock.calls[0][0]
const req = got.mock.calls[0][1]
expect(url.pathname).toBe('/session')
expect(req.json).toEqual({
capabilities: {
alwaysMatch: { browserName: 'firefox' },
firstMatch: [{}]
},
desiredCapabilities: { browserName: 'firefox' }
})
expect(got).toHaveBeenCalledWith(
expect.objectContaining({ pathname: '/session' }),
expect.objectContaining({ json: {
capabilities: {
alwaysMatch: { browserName: 'firefox' },
firstMatch: [{}]
},
desiredCapabilities: { browserName: 'firefox' }
} })
)
expect(sessionEnvironmentDetector.mock.calls)
expect(vi.mocked(sessionEnvironmentDetector).mock.calls)
.toMatchSnapshot()
})
@ -184,23 +185,27 @@ describe('WebDriver', () => {
describe('attachToSession', () => {
it('should allow to attach to existing session', async () => {
const client = WebDriver.attachToSession({ ...sessionOptions, logLevel: 'error' }) as TestClient
const client = WebDriver.attachToSession({ ...sessionOptions, logLevel: 'error' }) as any as TestClient
await client.getUrl()
const url = got.mock.calls[0][0]
expect(url.href).toBe('http://localhost:4444/session/foobar/url')
expect(got).toHaveBeenCalledWith(
expect.objectContaining({ href: 'http://localhost:4444/session/foobar/url' }),
expect.anything()
)
expect(logger.setLevel).toBeCalled()
})
it('should allow to attach to existing session2', async () => {
const client = WebDriver.attachToSession({ ...sessionOptions }) as TestClient
const client = WebDriver.attachToSession({ ...sessionOptions }) as any as TestClient
await client.getUrl()
const url = got.mock.calls[0][0]
expect(url.href).toBe('http://localhost:4444/session/foobar/url')
expect(got).toHaveBeenCalledWith(
expect.objectContaining({ href: 'http://localhost:4444/session/foobar/url' }),
expect.anything()
)
expect(logger.setLevel).not.toBeCalled()
})
it('should allow to attach to existing session - W3C', async () => {
const client = WebDriver.attachToSession({ ...sessionOptions }) as TestClient
const client = WebDriver.attachToSession({ ...sessionOptions }) as any as TestClient
await client.getUrl()
expect(client.isChrome).toBeFalsy()
@ -215,7 +220,7 @@ describe('WebDriver', () => {
const client = WebDriver.attachToSession({ ...sessionOptions,
isW3C: false,
isSauce: true,
}) as TestClient
}) as any as TestClient
await client.getUrl()
@ -229,7 +234,7 @@ describe('WebDriver', () => {
const client = WebDriver.attachToSession({ ...sessionOptions,
isChrome: true,
isMobile: true
}) as TestClient
}) as any as TestClient
await client.getUrl()
@ -294,7 +299,7 @@ describe('WebDriver', () => {
capabilities: { browserName: 'firefox' }
})
await WebDriver.reloadSession(session)
expect(got.mock.calls).toHaveLength(2)
expect(got).toHaveBeenCalledTimes(2)
})
})
@ -303,8 +308,8 @@ describe('WebDriver', () => {
})
afterEach(() => {
(logger.setLevel as jest.Mock).mockClear()
got.mockClear()
sessionEnvironmentDetector.mockClear()
vi.mocked(logger.setLevel).mockClear()
vi.mocked(got).mockClear()
vi.mocked(sessionEnvironmentDetector).mockClear()
})
})

View file

@ -1,23 +1,18 @@
/**
* @jest-environment jsdom
*/
// @vitest-environment jsdom
import path from 'node:path'
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import logger from '@wdio/logger'
import _ky from 'ky'
import ky from 'ky'
import { Options } from '@wdio/types'
import type { Options } from '@wdio/types'
import BrowserRequest from '../src/request/browser'
type LogMock = {
warn: jest.Mock,
error: jest.Mock
}
vi.mock('ky')
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))
const ky = <jest.Mock<typeof ky>>_ky
const { warn, error } = logger('test')
const { warn, error } = logger('test') as unknown as LogMock
const path = '/session'
const webdriverPath = '/session'
const defaultOptions = {
protocol: 'http',
hostname: 'localhost',
@ -31,24 +26,27 @@ describe('webdriver request', () => {
expect(req.endpoint).toBe('/foo/bar')
})
it('should be able to make request', () => {
it('should be able to make request', async () => {
const req = new BrowserRequest('POST', '/foo/bar', { foo: 'bar' })
req['_createOptions'] = jest.fn().mockImplementation((_, sessionId) => ({
req['_createOptions'] = vi.fn().mockImplementation((_, sessionId) => ({
foo: 'bar',
sessionId
}))
req.emit = jest.fn()
req['_request'] = jest.fn()
req.emit = vi.fn()
req['_request'] = vi.fn()
req.makeRequest({ connectionRetryCount: 43, logLevel: 'warn' }, 'some_id')
expect((req['_request'] as jest.Mock).mock.calls[0][0].foo).toBe('bar')
expect((req['_request'] as jest.Mock).mock.calls[0][0].sessionId).toBe('some_id')
expect((req['_request'] as jest.Mock).mock.calls[0][2]).toBe(43)
await req.makeRequest({ connectionRetryCount: 43, logLevel: 'warn' }, 'some_id')
expect(req['_request']).toHaveBeenCalledWith(
expect.objectContaining({ foo: 'bar', sessionId: 'some_id' }),
undefined,
43,
0
)
})
it('should pick up the fullRequestOptions returned by transformRequest', async () => {
const req = new BrowserRequest('POST', '/foo/bar', { foo: 'bar' })
const transformRequest = jest.fn().mockImplementation((requestOptions) => ({
const transformRequest = vi.fn().mockImplementation((requestOptions) => ({
...requestOptions,
json: { foo: 'baz' }
}))
@ -62,18 +60,21 @@ describe('webdriver request', () => {
logLevel: 'warn'
}, 'some_id')
expect(ky.mock.calls[0][1].json).toEqual({ foo: 'baz' })
expect(ky).toHaveBeenCalledWith(
expect.any(Object),
expect.objectContaining({ json: { foo: 'baz' } })
)
})
it('should resolve with the body returned by transformResponse', async () => {
const req = new BrowserRequest('POST', 'session/:sessionId/element', { foo: 'requestBody' })
const transformResponse = jest.fn().mockImplementation((response) => ({
const transformResponse = vi.fn().mockImplementation((response) => ({
...response,
body: { value: { foo: 'transformedResponse' } },
}))
ky.mockClear()
vi.mocked(ky).mockClear()
const responseBody = await req.makeRequest({
transformResponse,
protocol: 'https',
@ -86,18 +87,19 @@ describe('webdriver request', () => {
expect(transformResponse.mock.calls[0][0]).toHaveProperty('body')
expect(transformResponse.mock.calls[0][1].json).toEqual({ foo: 'requestBody' })
await expect(responseBody).toEqual({ value: { foo: 'transformedResponse' } })
ky.mockClear()
vi.mocked(ky).mockClear()
})
describe('createOptions', () => {
it('fails if command requires sessionId but none given', () => {
const req = new BrowserRequest('POST', `${path}/:sessionId/element`, {})
expect(() => req['_createOptions']({ logLevel: 'warn' })).toThrow()
it('fails if command requires sessionId but none given', async () => {
const req = new BrowserRequest('POST', `${webdriverPath}/:sessionId/element`, {})
await expect(async () => await req['_createOptions']({ logLevel: 'warn' }))
.rejects.toThrow('A sessionId is required')
})
it('creates proper options set', () => {
const req = new BrowserRequest('POST', `${path}/:sessionId/element`, {})
const options: Options.RequestLibOptions = req['_createOptions']({
it('creates proper options set', async () => {
const req = new BrowserRequest('POST', `${webdriverPath}/:sessionId/element`, {})
const options: Options.RequestLibOptions = await req['_createOptions']({
protocol: 'https',
hostname: 'localhost',
port: 4445,
@ -116,9 +118,9 @@ describe('webdriver request', () => {
expect(options.timeout).toBe(10 * 1000)
})
it('ignores path when command is a hub command', () => {
it('ignores path when command is a hub command', async () => {
const req = new BrowserRequest('POST', '/grid/api/hub', {}, true)
const options = req['_createOptions']({
const options = await req['_createOptions']({
protocol: 'https',
hostname: 'localhost',
port: 4445,
@ -128,9 +130,9 @@ describe('webdriver request', () => {
expect((options.url as URL).href).toBe('https://localhost:4445/grid/api/hub')
})
it('should add auth if user and key is given', () => {
const req = new BrowserRequest('POST', path, { some: 'body' })
const options = req['_createOptions']({
it('should add auth if user and key is given', async () => {
const req = new BrowserRequest('POST', webdriverPath, { some: 'body' })
const options = await req['_createOptions']({
...defaultOptions,
user: 'foo',
key: 'bar',
@ -142,9 +144,9 @@ describe('webdriver request', () => {
expect(options.json).toEqual({ some: 'body' })
})
it('sets request body to "undefined" when request object is empty and DELETE is used', () => {
const req = new BrowserRequest('DELETE', path, {})
const options = req['_createOptions']({
it('sets request body to "undefined" when request object is empty and DELETE is used', async () => {
const req = new BrowserRequest('DELETE', webdriverPath, {})
const options = await req['_createOptions']({
...defaultOptions,
path: '/',
logLevel: 'warn'
@ -152,9 +154,9 @@ describe('webdriver request', () => {
expect(Boolean(options.json)).toEqual(false)
})
it('sets request body to "undefined" when request object is empty and GET is used', () => {
const req = new BrowserRequest('GET', `${path}/title`, {})
const options = req['_createOptions']({
it('sets request body to "undefined" when request object is empty and GET is used', async () => {
const req = new BrowserRequest('GET', `${webdriverPath}/title`, {})
const options = await req['_createOptions']({
...defaultOptions,
path: '/',
logLevel: 'warn'
@ -162,9 +164,9 @@ describe('webdriver request', () => {
expect(Boolean(options.json)).toEqual(false)
})
it('should attach an empty object body when POST is used', () => {
it('should attach an empty object body when POST is used', async () => {
const req = new BrowserRequest('POST', '/status', {})
const options = req['_createOptions']({
const options = await req['_createOptions']({
...defaultOptions,
path: '/',
logLevel: 'warn'
@ -172,9 +174,9 @@ describe('webdriver request', () => {
expect(options.json).toEqual({})
})
it('should add the Content-Length header when a request object has a body', () => {
const req = new BrowserRequest('POST', path, { foo: 'bar' })
const options = req['_createOptions']({
it('should add the Content-Length header when a request object has a body', async () => {
const req = new BrowserRequest('POST', webdriverPath, { foo: 'bar' })
const options = await req['_createOptions']({
...defaultOptions,
path: '/',
logLevel: 'warn'
@ -184,9 +186,9 @@ describe('webdriver request', () => {
expect((options.headers as Record<string, string>)['Content-Length']).toBe('13')
})
it('should add Content-Length as well any other header provided in the request options if there is body in the request object', () => {
const req = new BrowserRequest('POST', path, { foo: 'bar' })
const options = req['_createOptions']({
it('should add Content-Length as well any other header provided in the request options if there is body in the request object', async () => {
const req = new BrowserRequest('POST', webdriverPath, { foo: 'bar' })
const options = await req['_createOptions']({
...defaultOptions, path: '/',
headers: { foo: 'bar' },
logLevel: 'warn'
@ -197,9 +199,9 @@ describe('webdriver request', () => {
expect(headers['Content-Length']).toBe('13')
})
it('should add only the headers provided if the request body is empty', () => {
const req = new BrowserRequest('POST', path)
const options = req['_createOptions']({
it('should add only the headers provided if the request body is empty', async () => {
const req = new BrowserRequest('POST', webdriverPath)
const options = await req['_createOptions']({
...defaultOptions,
path: '/',
headers: { foo: 'bar' },
@ -223,64 +225,64 @@ describe('webdriver request', () => {
delete process.env.strict_ssl
})
it('should contain key "rejectUnauthorized" with value "false" when "strictSSL" argument is given with false', () => {
const req = new BrowserRequest('POST', path, {})
const options = req['_createOptions']({ ...defaults, strictSSL: false })
it('should contain key "rejectUnauthorized" with value "false" when "strictSSL" argument is given with false', async () => {
const req = new BrowserRequest('POST', webdriverPath, {})
const options = await req['_createOptions']({ ...defaults, strictSSL: false })
expect(options.https?.rejectUnauthorized).toEqual(false)
})
it('should contain key "rejectUnauthorized" with value "false" when environment variable "STRICT_SSL" is defined with value "false"', () => {
it('should contain key "rejectUnauthorized" with value "false" when environment variable "STRICT_SSL" is defined with value "false"', async () => {
process.env['STRICT_SSL'] = 'false'
const req = new BrowserRequest('POST', path, {})
const options = req['_createOptions'](defaults)
const req = new BrowserRequest('POST', webdriverPath, {})
const options = await req['_createOptions'](defaults)
expect(options.https?.rejectUnauthorized).toEqual(false)
})
it('should contain key "rejectUnauthorized" with value "false" when environment variable "strict_ssl" is defined with value "false"', () => {
it('should contain key "rejectUnauthorized" with value "false" when environment variable "strict_ssl" is defined with value "false"', async () => {
process.env['strict_ssl'] = 'false'
const req = new BrowserRequest('POST', path, {})
const options = req['_createOptions'](defaults)
const req = new BrowserRequest('POST', webdriverPath, {})
const options = await req['_createOptions'](defaults)
expect(options.https?.rejectUnauthorized).toEqual(false)
})
it('should contain key "rejectUnauthorized" with value "true" when "strictSSL" argument is given with true', () => {
const req = new BrowserRequest('POST', path, {})
const options = req['_createOptions']({ ...defaults, strictSSL: true })
it('should contain key "rejectUnauthorized" with value "true" when "strictSSL" argument is given with true', async () => {
const req = new BrowserRequest('POST', webdriverPath, {})
const options = await req['_createOptions']({ ...defaults, strictSSL: true })
expect(options.https?.rejectUnauthorized).toEqual(true)
})
it('should contain key "rejectUnauthorized" with value "true" when environment variable "STRICT_SSL" is defined with value "true"', () => {
it('should contain key "rejectUnauthorized" with value "true" when environment variable "STRICT_SSL" is defined with value "true"', async () => {
process.env['STRICT_SSL'] = 'true'
const req = new BrowserRequest('POST', path, {})
const options = req['_createOptions'](defaults)
const req = new BrowserRequest('POST', webdriverPath, {})
const options = await req['_createOptions'](defaults)
expect(options.https?.rejectUnauthorized).toEqual(true)
})
it('should contain key "rejectUnauthorized" with value "true" when environment variable "strict_ssl" is defined with value "true"', () => {
it('should contain key "rejectUnauthorized" with value "true" when environment variable "strict_ssl" is defined with value "true"', async () => {
process.env['strict_ssl'] = 'true'
const req = new BrowserRequest('POST', path, {})
const options = req['_createOptions'](defaults)
const req = new BrowserRequest('POST', webdriverPath, {})
const options = await req['_createOptions'](defaults)
expect(options.https?.rejectUnauthorized).toEqual(true)
})
it('should contain key "rejectUnauthorized" with value "true" when environment variable "STRICT_SSL" / "strict_ssl" is not defined', () => {
const req = new BrowserRequest('POST', path, {})
const options = req['_createOptions'](defaults)
it('should contain key "rejectUnauthorized" with value "true" when environment variable "STRICT_SSL" / "strict_ssl" is not defined', async () => {
const req = new BrowserRequest('POST', webdriverPath, {})
const options = await req['_createOptions'](defaults)
expect(options.https?.rejectUnauthorized).toEqual(true)
})
it('should contain key "rejectUnauthorized" with value "true" when environment variable "STRICT_SSL" is defined with any other value than "false"', () => {
it('should contain key "rejectUnauthorized" with value "true" when environment variable "STRICT_SSL" is defined with any other value than "false"', async () => {
process.env['STRICT_SSL'] = 'foo'
const req = new BrowserRequest('POST', path, {})
const options = req['_createOptions'](defaults)
const req = new BrowserRequest('POST', webdriverPath, {})
const options = await req['_createOptions'](defaults)
expect(options.https?.rejectUnauthorized).toEqual(true)
})
it('should contain key "rejectUnauthorized" with value "true" when environment variable "strict_ssl" is defined with any other value than "false"', () => {
it('should contain key "rejectUnauthorized" with value "true" when environment variable "strict_ssl" is defined with any other value than "false"', async () => {
process.env['strict_ssl'] = 'foo'
const req = new BrowserRequest('POST', path, {})
const options = req['_createOptions'](defaults)
const req = new BrowserRequest('POST', webdriverPath, {})
const options = await req['_createOptions'](defaults)
expect(options.https?.rejectUnauthorized).toEqual(true)
})
})
@ -289,8 +291,8 @@ describe('webdriver request', () => {
describe('_request', () => {
it('should make a request', async () => {
const expectedResponse = { value: { 'element-6066-11e4-a52e-4f735466cecf': 'some-elem-123' } }
const req = new BrowserRequest('POST', path, {})
req.emit = jest.fn()
const req = new BrowserRequest('POST', webdriverPath, {})
req.emit = vi.fn()
const opts = Object.assign(
req.defaultOptions,
@ -299,7 +301,7 @@ describe('webdriver request', () => {
const res = await req['_request'](opts)
expect(res).toEqual(expectedResponse)
expect((req.emit as jest.Mock).mock.calls).toHaveLength(2)
expect(req.emit).toHaveBeenCalledTimes(2)
expect(req.emit).toHaveBeenNthCalledWith(1, 'response', { result: expectedResponse })
expect(req.emit).toHaveBeenNthCalledWith(2, 'performance', expect.objectContaining({
request: opts,
@ -311,7 +313,7 @@ describe('webdriver request', () => {
it('should short circuit if request throws a stale element exception', async () => {
const req = new BrowserRequest('POST', 'session/:sessionId/element', {})
req.emit = jest.fn()
req.emit = vi.fn()
const opts = Object.assign(req.defaultOptions, {
url: { pathname: '/session/foobar-123/element/some-sub-sub-elem-231/click' },
@ -319,51 +321,51 @@ describe('webdriver request', () => {
})
const error = await req['_request'](opts).catch(err => err)
expect(error.message).toBe('element is not attached to the page document')
expect((req.emit as jest.Mock).mock.calls).toHaveLength(2)
expect(vi.mocked(error).message).toBe('element is not attached to the page document')
expect(req.emit).toHaveBeenCalledTimes(2)
expect(req.emit).toHaveBeenNthCalledWith(1, 'response', expect.anything())
expect(req.emit).toHaveBeenNthCalledWith(2, 'performance', expect.objectContaining({ success: false }))
expect(warn.mock.calls).toHaveLength(1)
expect(warn.mock.calls).toEqual([['Request encountered a stale element - terminating request']])
expect(vi.mocked(warn).mock.calls).toHaveLength(1)
expect(vi.mocked(warn).mock.calls).toEqual([['Request encountered a stale element - terminating request']])
})
it('should not fail code due to an empty server response', async () => {
const req = new BrowserRequest('POST', path, {})
req.emit = jest.fn()
const req = new BrowserRequest('POST', webdriverPath, {})
req.emit = vi.fn()
const opts = Object.assign(req.defaultOptions, { url: { pathname: '/empty' } })
await expect(req['_request'](opts)).rejects.toEqual(new Error('Response has empty body'))
expect((req.emit as jest.Mock).mock.calls).toHaveLength(2)
expect(req.emit).toHaveBeenCalledTimes(2)
expect(req.emit).toHaveBeenNthCalledWith(1, 'response', expect.anything())
expect(req.emit).toHaveBeenNthCalledWith(2, 'performance', expect.objectContaining({ success: false }))
expect(warn.mock.calls).toHaveLength(0)
expect(error.mock.calls).toHaveLength(1)
expect(vi.mocked(warn).mock.calls).toHaveLength(0)
expect(vi.mocked(error).mock.calls).toHaveLength(1)
})
it('should retry requests but still fail', async () => {
const req = new BrowserRequest('POST', path, {})
req.emit = jest.fn()
const req = new BrowserRequest('POST', webdriverPath, {})
req.emit = vi.fn()
const opts = Object.assign(req.defaultOptions, { url: { pathname: '/failing' } })
await expect(req['_request'](opts, undefined, 2)).rejects.toEqual(new Error('unknown error'))
expect((req.emit as jest.Mock).mock.calls).toHaveLength(6)
expect(req.emit).toHaveBeenCalledTimes(6)
expect(req.emit).toHaveBeenNthCalledWith(1, 'retry', expect.anything())
expect(req.emit).toHaveBeenNthCalledWith(2, 'performance', expect.objectContaining({ success: false }))
expect(req.emit).toHaveBeenNthCalledWith(3, 'retry', expect.anything())
expect(req.emit).toHaveBeenNthCalledWith(4, 'performance', expect.objectContaining({ success: false }))
expect(req.emit).toHaveBeenNthCalledWith(5, 'response', expect.anything())
expect(req.emit).toHaveBeenNthCalledWith(6, 'performance', expect.objectContaining({ success: false }))
expect(warn.mock.calls).toHaveLength(2)
expect(error.mock.calls).toHaveLength(1)
expect(vi.mocked(warn).mock.calls).toHaveLength(2)
expect(vi.mocked(error).mock.calls).toHaveLength(1)
})
it('should retry and eventually respond', async () => {
const req = new BrowserRequest('POST', path, {})
req.emit = jest.fn()
const req = new BrowserRequest('POST', webdriverPath, {})
req.emit = vi.fn()
const opts = Object.assign(req.defaultOptions, { url: { pathname: '/failing' }, json: { foo: 'bar' } })
expect(await req['_request'](opts, undefined, 3)).toEqual({ value: 'caught' })
expect((req.emit as jest.Mock).mock.calls).toHaveLength(8)
expect(req.emit).toHaveBeenCalledTimes(8)
expect(req.emit).toHaveBeenNthCalledWith(1, 'retry', expect.anything())
expect(req.emit).toHaveBeenNthCalledWith(2, 'performance', expect.objectContaining({ success: false }))
expect(req.emit).toHaveBeenNthCalledWith(3, 'retry', expect.anything())
@ -372,8 +374,8 @@ describe('webdriver request', () => {
expect(req.emit).toHaveBeenNthCalledWith(6, 'performance', expect.objectContaining({ success: false }))
expect(req.emit).toHaveBeenNthCalledWith(7, 'response', expect.anything())
expect(req.emit).toHaveBeenNthCalledWith(8, 'performance', expect.objectContaining({ success: true }))
expect(warn.mock.calls).toHaveLength(3)
expect(error.mock.calls).toHaveLength(0)
expect(vi.mocked(warn).mock.calls).toHaveLength(3)
expect(vi.mocked(error).mock.calls).toHaveLength(0)
})
it('should manage hub commands', async () => {
@ -405,7 +407,7 @@ describe('webdriver request', () => {
it('should throw if timeout happens too often', async () => {
const retryCnt = 3
const req = new BrowserRequest('POST', '/timeout', {}, true)
const reqRetryCnt = jest.fn()
const reqRetryCnt = vi.fn()
req.on('retry', reqRetryCnt)
const result = await req.makeRequest({
protocol: 'https',
@ -425,7 +427,7 @@ describe('webdriver request', () => {
it('should return proper response if retry passes', async () => {
const retryCnt = 7
const req = new BrowserRequest('POST', '/timeout', {}, true)
const reqRetryCnt = jest.fn()
const reqRetryCnt = vi.fn()
req.on('retry', reqRetryCnt)
const result = await req.makeRequest({
protocol: 'https',
@ -445,7 +447,7 @@ describe('webdriver request', () => {
it('should retry on connection refused error', async () => {
const retryCnt = 7
const req = new BrowserRequest('POST', '/connectionRefused', {}, true)
const reqRetryCnt = jest.fn()
const reqRetryCnt = vi.fn()
req.on('retry', reqRetryCnt)
const result = await req.makeRequest({
protocol: 'https',
@ -480,7 +482,7 @@ describe('webdriver request', () => {
it('should correctly handle username and password options', async () => {
const expectedResponse = { value: { 'element-6066-11e4-a52e-4f735466cecf': 'some-elem-123' } }
const req = new BrowserRequest('POST', path, {})
const req = new BrowserRequest('POST', webdriverPath, {})
const opts = Object.assign(
req.defaultOptions,
@ -490,7 +492,10 @@ describe('webdriver request', () => {
const res = await req['_request'](opts)
expect(res).toEqual(expectedResponse)
expect(ky.mock.calls[0][1].headers.Authorization).toEqual('Basic Zm9vOmJhcg==')
expect(ky).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({ headers: { Authorization: 'Basic Zm9vOmJhcg==' } })
)
})
})
@ -498,8 +503,8 @@ describe('webdriver request', () => {
// @ts-ignore
ky.retryCnt = 0
ky.mockClear()
warn.mockClear()
error.mockClear()
vi.mocked(ky).mockClear()
vi.mocked(warn).mockClear()
vi.mocked(error).mockClear()
})
})

View file

@ -1,21 +1,20 @@
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import path from 'node:path'
import http from 'node:http'
import https from 'node:https'
import got, { Agents } from 'got'
import logger from '@wdio/logger'
import * as gotOrig from 'got'
import http from 'http'
import https from 'https'
import { Options } from '@wdio/types'
import * as utils from '../src/utils'
import { Options } from '@wdio/types'
import WebDriverRequest from '../src/request/node'
type LogMock = {
warn: jest.Mock,
error: jest.Mock
}
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))
vi.mock('got')
const { warn, error } = logger('test')
const { warn, error } = logger('test') as unknown as LogMock
const got = gotOrig.default as unknown as jest.Mock
const path = '/session'
const webdriverPath = '/session'
const defaultOptions = {
protocol: 'http',
hostname: 'localhost',
@ -24,7 +23,7 @@ const defaultOptions = {
describe('webdriver request', () => {
beforeEach(() => {
got.mockClear()
vi.mocked(got).mockClear()
})
it('should have some default options', () => {
@ -33,24 +32,27 @@ describe('webdriver request', () => {
expect(req.endpoint).toBe('/foo/bar')
})
it('should be able to make request', () => {
it('should be able to make request', async () => {
const req = new WebDriverRequest('POST', '/foo/bar', { foo: 'bar' })
req['_createOptions'] = jest.fn().mockImplementation((opts, sessionId) => ({
req['_createOptions'] = vi.fn().mockImplementation((opts, sessionId) => ({
foo: 'bar',
sessionId
}))
req.emit = jest.fn()
req['_request'] = jest.fn()
req.emit = vi.fn()
req['_request'] = vi.fn()
req.makeRequest({ connectionRetryCount: 43, logLevel: 'warn' }, 'some_id')
expect((req['_request'] as jest.Mock).mock.calls[0][0].foo).toBe('bar')
expect((req['_request'] as jest.Mock).mock.calls[0][0].sessionId).toBe('some_id')
expect((req['_request'] as jest.Mock).mock.calls[0][2]).toBe(43)
await req.makeRequest({ connectionRetryCount: 43, logLevel: 'warn' }, 'some_id')
expect(req['_request']).toHaveBeenCalledWith(
expect.objectContaining({ foo: 'bar', sessionId: 'some_id' }),
undefined,
43,
0
)
})
it('should pick up the fullRequestOptions returned by transformRequest', async () => {
it.only('should pick up the fullRequestOptions returned by transformRequest', async () => {
const req = new WebDriverRequest('POST', '/foo/bar', { foo: 'bar' })
const transformRequest = jest.fn().mockImplementation((requestOptions) => ({
const transformRequest = vi.fn().mockImplementation((requestOptions) => ({
...requestOptions,
json: { foo: 'baz' }
}))
@ -63,19 +65,21 @@ describe('webdriver request', () => {
path: '/wd/hub/',
logLevel: 'warn'
}, 'some_id')
expect(got.mock.calls[0][1].json).toEqual({ foo: 'baz' })
expect(got).toHaveBeenCalledWith(
expect.any(Object),
expect.objectContaining({ json: { foo: 'baz' } })
)
})
it('should resolve with the body returned by transformResponse', async () => {
const req = new WebDriverRequest('POST', 'session/:sessionId/element', { foo: 'requestBody' })
const transformResponse = jest.fn().mockImplementation((response) => ({
const transformResponse = vi.fn().mockImplementation((response) => ({
...response,
body: { value: { foo: 'transformedResponse' } },
}))
got.mockClear()
vi.mocked(got).mockClear()
const responseBody = await req.makeRequest({
transformResponse,
protocol: 'https',
@ -88,18 +92,18 @@ describe('webdriver request', () => {
expect(transformResponse.mock.calls[0][0]).toHaveProperty('body')
expect(transformResponse.mock.calls[0][1].json).toEqual({ foo: 'requestBody' })
await expect(responseBody).toEqual({ value: { foo: 'transformedResponse' } })
got.mockClear()
vi.mocked(got).mockClear()
})
describe('createOptions', () => {
it('fails if command requires sessionId but none given', () => {
const req = new WebDriverRequest('POST', `${path}/:sessionId/element`, {})
const req = new WebDriverRequest('POST', `${webdriverPath}/:sessionId/element`, {})
expect(() => req['_createOptions']({ logLevel: 'warn' })).toThrow()
})
it('creates proper options set', () => {
const req = new WebDriverRequest('POST', `${path}/:sessionId/element`, {})
const options: gotOrig.Options = req['_createOptions']({
it('creates proper options set', async () => {
const req = new WebDriverRequest('POST', `${webdriverPath}/:sessionId/element`, {})
const options: Options.RequestLibOptions = await req['_createOptions']({
protocol: 'https',
hostname: 'localhost',
port: 4445,
@ -120,13 +124,13 @@ describe('webdriver request', () => {
expect(options.timeout).toBe(10 * 1000)
})
it('passes a custom agent', () => {
const req = new WebDriverRequest('POST', `${path}/:sessionId/element`, {})
it('passes a custom agent', async () => {
const req = new WebDriverRequest('POST', `${webdriverPath}/:sessionId/element`, {})
const agent = {
http: new http.Agent({ keepAlive: true }),
https: new https.Agent({ keepAlive: true })
}
const options = req['_createOptions']({
const options = await req['_createOptions']({
protocol: 'https',
hostname: 'localhost',
port: 4445,
@ -135,13 +139,13 @@ describe('webdriver request', () => {
agent
}, 'foobar12345')
expect((options.agent! as gotOrig.Agents).http).toBe(agent.http)
expect((options.agent! as gotOrig.Agents).https).toBe(agent.https)
expect((options.agent! as Agents).http).toBe(agent.http)
expect((options.agent! as Agents).https).toBe(agent.https)
})
it('ignors path when command is a hub command', () => {
it('ignors path when command is a hub command', async () => {
const req = new WebDriverRequest('POST', '/grid/api/hub', {}, true)
const options = req['_createOptions']({
const options = await req['_createOptions']({
protocol: 'https',
hostname: 'localhost',
port: 4445,
@ -151,9 +155,9 @@ describe('webdriver request', () => {
expect((options.url as URL).href).toBe('https://localhost:4445/grid/api/hub')
})
it('should add auth if user and key is given', () => {
const req = new WebDriverRequest('POST', path, { some: 'body' })
const options = req['_createOptions']({
it('should add auth if user and key is given', async () => {
const req = new WebDriverRequest('POST', webdriverPath, { some: 'body' })
const options = await req['_createOptions']({
...defaultOptions,
user: 'foo',
key: 'bar',
@ -165,9 +169,9 @@ describe('webdriver request', () => {
expect(options.json).toEqual({ some: 'body' })
})
it('sets request body to "undefined" when request object is empty and DELETE is used', () => {
const req = new WebDriverRequest('DELETE', path, {})
const options = req['_createOptions']({
it('sets request body to "undefined" when request object is empty and DELETE is used', async () => {
const req = new WebDriverRequest('DELETE', webdriverPath, {})
const options = await req['_createOptions']({
...defaultOptions,
path: '/',
logLevel: 'warn'
@ -175,9 +179,9 @@ describe('webdriver request', () => {
expect(Boolean(options.json)).toEqual(false)
})
it('sets request body to "undefined" when request object is empty and GET is used', () => {
const req = new WebDriverRequest('GET', `${path}/title`, {})
const options = req['_createOptions']({
it('sets request body to "undefined" when request object is empty and GET is used', async () => {
const req = new WebDriverRequest('GET', `${webdriverPath}/title`, {})
const options = await req['_createOptions']({
...defaultOptions,
path: '/',
logLevel: 'warn'
@ -185,9 +189,9 @@ describe('webdriver request', () => {
expect(Boolean(options.json)).toEqual(false)
})
it('should attach an empty object body when POST is used', () => {
it('should attach an empty object body when POST is used', async () => {
const req = new WebDriverRequest('POST', '/status', {})
const options = req['_createOptions']({
const options = await req['_createOptions']({
...defaultOptions,
path: '/',
logLevel: 'warn'
@ -195,9 +199,9 @@ describe('webdriver request', () => {
expect(options.json).toEqual({})
})
it('should add the Content-Length header when a request object has a body', () => {
const req = new WebDriverRequest('POST', path, { foo: 'bar' })
const options = req['_createOptions']({
it('should add the Content-Length header when a request object has a body', async () => {
const req = new WebDriverRequest('POST', webdriverPath, { foo: 'bar' })
const options = await req['_createOptions']({
...defaultOptions,
path: '/',
logLevel: 'warn'
@ -207,9 +211,9 @@ describe('webdriver request', () => {
expect((options.headers as Record<string, string>)['Content-Length']).toBe('13')
})
it('should add Content-Length as well any other header provided in the request options if there is body in the request object', () => {
const req = new WebDriverRequest('POST', path, { foo: 'bar' })
const options = req['_createOptions']({
it('should add Content-Length as well any other header provided in the request options if there is body in the request object', async () => {
const req = new WebDriverRequest('POST', webdriverPath, { foo: 'bar' })
const options = await req['_createOptions']({
...defaultOptions, path: '/',
headers: { foo: 'bar' },
logLevel: 'warn'
@ -220,9 +224,9 @@ describe('webdriver request', () => {
expect(headers['Content-Length']).toBe('13')
})
it('should add only the headers provided if the request body is empty', () => {
const req = new WebDriverRequest('POST', path)
const options = req['_createOptions']({
it('should add only the headers provided if the request body is empty', async () => {
const req = new WebDriverRequest('POST', webdriverPath)
const options = await req['_createOptions']({
...defaultOptions,
path: '/',
headers: { foo: 'bar' },
@ -246,64 +250,64 @@ describe('webdriver request', () => {
delete process.env.strict_ssl
})
it('should contain key "rejectUnauthorized" with value "false" when "strictSSL" argument is given with false', () => {
const req = new WebDriverRequest('POST', path, {})
const options = req['_createOptions']({ ...defaults, strictSSL: false })
it('should contain key "rejectUnauthorized" with value "false" when "strictSSL" argument is given with false', async () => {
const req = new WebDriverRequest('POST', webdriverPath, {})
const options = await req['_createOptions']({ ...defaults, strictSSL: false })
expect(options.https?.rejectUnauthorized).toEqual(false)
})
it('should contain key "rejectUnauthorized" with value "false" when environment variable "STRICT_SSL" is defined with value "false"', () => {
it('should contain key "rejectUnauthorized" with value "false" when environment variable "STRICT_SSL" is defined with value "false"', async () => {
process.env['STRICT_SSL'] = 'false'
const req = new WebDriverRequest('POST', path, {})
const options = req['_createOptions'](defaults)
const req = new WebDriverRequest('POST', webdriverPath, {})
const options = await req['_createOptions'](defaults)
expect(options.https?.rejectUnauthorized).toEqual(false)
})
it('should contain key "rejectUnauthorized" with value "false" when environment variable "strict_ssl" is defined with value "false"', () => {
it('should contain key "rejectUnauthorized" with value "false" when environment variable "strict_ssl" is defined with value "false"', async () => {
process.env['strict_ssl'] = 'false'
const req = new WebDriverRequest('POST', path, {})
const options = req['_createOptions'](defaults)
const req = new WebDriverRequest('POST', webdriverPath, {})
const options = await req['_createOptions'](defaults)
expect(options.https?.rejectUnauthorized).toEqual(false)
})
it('should contain key "rejectUnauthorized" with value "true" when "strictSSL" argument is given with true', () => {
const req = new WebDriverRequest('POST', path, {})
const options = req['_createOptions']({ ...defaults, strictSSL: true })
it('should contain key "rejectUnauthorized" with value "true" when "strictSSL" argument is given with true', async () => {
const req = new WebDriverRequest('POST', webdriverPath, {})
const options = await req['_createOptions']({ ...defaults, strictSSL: true })
expect(options.https?.rejectUnauthorized).toEqual(true)
})
it('should contain key "rejectUnauthorized" with value "true" when environment variable "STRICT_SSL" is defined with value "true"', () => {
it('should contain key "rejectUnauthorized" with value "true" when environment variable "STRICT_SSL" is defined with value "true"', async () => {
process.env['STRICT_SSL'] = 'true'
const req = new WebDriverRequest('POST', path, {})
const options = req['_createOptions'](defaults)
const req = new WebDriverRequest('POST', webdriverPath, {})
const options = await req['_createOptions'](defaults)
expect(options.https?.rejectUnauthorized).toEqual(true)
})
it('should contain key "rejectUnauthorized" with value "true" when environment variable "strict_ssl" is defined with value "true"', () => {
it('should contain key "rejectUnauthorized" with value "true" when environment variable "strict_ssl" is defined with value "true"', async () => {
process.env['strict_ssl'] = 'true'
const req = new WebDriverRequest('POST', path, {})
const options = req['_createOptions'](defaults)
const req = new WebDriverRequest('POST', webdriverPath, {})
const options = await req['_createOptions'](defaults)
expect(options.https?.rejectUnauthorized).toEqual(true)
})
it('should contain key "rejectUnauthorized" with value "true" when environment variable "STRICT_SSL" / "strict_ssl" is not defined', () => {
const req = new WebDriverRequest('POST', path, {})
const options = req['_createOptions'](defaults)
it('should contain key "rejectUnauthorized" with value "true" when environment variable "STRICT_SSL" / "strict_ssl" is not defined', async () => {
const req = new WebDriverRequest('POST', webdriverPath, {})
const options = await req['_createOptions'](defaults)
expect(options.https?.rejectUnauthorized).toEqual(true)
})
it('should contain key "rejectUnauthorized" with value "true" when environment variable "STRICT_SSL" is defined with any other value than "false"', () => {
it('should contain key "rejectUnauthorized" with value "true" when environment variable "STRICT_SSL" is defined with any other value than "false"', async () => {
process.env['STRICT_SSL'] = 'foo'
const req = new WebDriverRequest('POST', path, {})
const options = req['_createOptions'](defaults)
const req = new WebDriverRequest('POST', webdriverPath, {})
const options = await req['_createOptions'](defaults)
expect(options.https?.rejectUnauthorized).toEqual(true)
})
it('should contain key "rejectUnauthorized" with value "true" when environment variable "strict_ssl" is defined with any other value than "false"', () => {
it('should contain key "rejectUnauthorized" with value "true" when environment variable "strict_ssl" is defined with any other value than "false"', async () => {
process.env['strict_ssl'] = 'foo'
const req = new WebDriverRequest('POST', path, {})
const options = req['_createOptions'](defaults)
const req = new WebDriverRequest('POST', webdriverPath, {})
const options = await req['_createOptions'](defaults)
expect(options.https?.rejectUnauthorized).toEqual(true)
})
})
@ -312,8 +316,8 @@ describe('webdriver request', () => {
describe('_request', () => {
it('should make a request', async () => {
const expectedResponse = { value: { 'element-6066-11e4-a52e-4f735466cecf': 'some-elem-123' } }
const req = new WebDriverRequest('POST', path, {})
req.emit = jest.fn()
const req = new WebDriverRequest('POST', webdriverPath, {})
req.emit = vi.fn()
const opts = Object.assign(
req.defaultOptions,
@ -322,7 +326,7 @@ describe('webdriver request', () => {
const res = await req['_request'](opts)
expect(res).toEqual(expectedResponse)
expect((req.emit as jest.Mock).mock.calls).toHaveLength(2)
expect(vi.mocked(req.emit).mock.calls).toHaveLength(2)
expect(req.emit).toHaveBeenNthCalledWith(1, 'response', { result: expectedResponse })
expect(req.emit).toHaveBeenNthCalledWith(2, 'performance', expect.objectContaining({
request: opts,
@ -334,7 +338,7 @@ describe('webdriver request', () => {
it('should short circuit if request throws a stale element exception', async () => {
const req = new WebDriverRequest('POST', 'session/:sessionId/element', {})
req.emit = jest.fn()
req.emit = vi.fn()
const opts = Object.assign(req.defaultOptions, {
url: { pathname: '/session/foobar-123/element/some-sub-sub-elem-231/click' },
@ -343,50 +347,50 @@ describe('webdriver request', () => {
const error = await req['_request'](opts).catch(err => err)
expect(error.message).toBe('element is not attached to the page document')
expect((req.emit as jest.Mock).mock.calls).toHaveLength(2)
expect(vi.mocked(req.emit).mock.calls).toHaveLength(2)
expect(req.emit).toHaveBeenNthCalledWith(1, 'response', expect.anything())
expect(req.emit).toHaveBeenNthCalledWith(2, 'performance', expect.objectContaining({ success: false }))
expect(warn.mock.calls).toHaveLength(1)
expect(warn.mock.calls).toEqual([['Request encountered a stale element - terminating request']])
expect(vi.mocked(warn).mock.calls).toHaveLength(1)
expect(vi.mocked(warn).mock.calls).toEqual([['Request encountered a stale element - terminating request']])
})
it('should not fail code due to an empty server response', async () => {
const req = new WebDriverRequest('POST', path, {})
req.emit = jest.fn()
const req = new WebDriverRequest('POST', webdriverPath, {})
req.emit = vi.fn()
const opts = Object.assign(req.defaultOptions, { url: { pathname: '/empty' } })
await expect(req['_request'](opts)).rejects.toEqual(new Error('Response has empty body'))
expect((req.emit as jest.Mock).mock.calls).toHaveLength(2)
expect(vi.mocked(req.emit).mock.calls).toHaveLength(2)
expect(req.emit).toHaveBeenNthCalledWith(1, 'response', expect.anything())
expect(req.emit).toHaveBeenNthCalledWith(2, 'performance', expect.objectContaining({ success: false }))
expect(warn.mock.calls).toHaveLength(0)
expect(error.mock.calls).toHaveLength(1)
expect(vi.mocked(warn).mock.calls).toHaveLength(0)
expect(vi.mocked(error).mock.calls).toHaveLength(1)
})
it('should retry requests but still fail', async () => {
const req = new WebDriverRequest('POST', path, {})
req.emit = jest.fn()
const req = new WebDriverRequest('POST', webdriverPath, {})
req.emit = vi.fn()
const opts = Object.assign(req.defaultOptions, { url: { pathname: '/failing' } })
await expect(req['_request'](opts, undefined, 2)).rejects.toEqual(new Error('unknown error'))
expect((req.emit as jest.Mock).mock.calls).toHaveLength(6)
expect(vi.mocked(req.emit).mock.calls).toHaveLength(6)
expect(req.emit).toHaveBeenNthCalledWith(1, 'retry', expect.anything())
expect(req.emit).toHaveBeenNthCalledWith(2, 'performance', expect.objectContaining({ success: false }))
expect(req.emit).toHaveBeenNthCalledWith(3, 'retry', expect.anything())
expect(req.emit).toHaveBeenNthCalledWith(4, 'performance', expect.objectContaining({ success: false }))
expect(req.emit).toHaveBeenNthCalledWith(5, 'response', expect.anything())
expect(req.emit).toHaveBeenNthCalledWith(6, 'performance', expect.objectContaining({ success: false }))
expect(warn.mock.calls).toHaveLength(2)
expect(error.mock.calls).toHaveLength(1)
expect(vi.mocked(warn).mock.calls).toHaveLength(2)
expect(vi.mocked(error).mock.calls).toHaveLength(1)
})
it('should retry and eventually respond', async () => {
const req = new WebDriverRequest('POST', path, {})
req.emit = jest.fn()
const req = new WebDriverRequest('POST', webdriverPath, {})
req.emit = vi.fn()
const opts = Object.assign(req.defaultOptions, { url: { pathname: '/failing' }, json: { foo: 'bar' } })
expect(await req['_request'](opts, undefined, 3)).toEqual({ value: 'caught' })
expect((req.emit as jest.Mock).mock.calls).toHaveLength(8)
expect(vi.mocked(req.emit).mock.calls).toHaveLength(8)
expect(req.emit).toHaveBeenNthCalledWith(1, 'retry', expect.anything())
expect(req.emit).toHaveBeenNthCalledWith(2, 'performance', expect.objectContaining({ success: false }))
expect(req.emit).toHaveBeenNthCalledWith(3, 'retry', expect.anything())
@ -395,8 +399,8 @@ describe('webdriver request', () => {
expect(req.emit).toHaveBeenNthCalledWith(6, 'performance', expect.objectContaining({ success: false }))
expect(req.emit).toHaveBeenNthCalledWith(7, 'response', expect.anything())
expect(req.emit).toHaveBeenNthCalledWith(8, 'performance', expect.objectContaining({ success: true }))
expect(warn.mock.calls).toHaveLength(3)
expect(error.mock.calls).toHaveLength(0)
expect(vi.mocked(warn).mock.calls).toHaveLength(3)
expect(vi.mocked(error).mock.calls).toHaveLength(0)
})
it('should manage hub commands', async () => {
@ -429,7 +433,7 @@ describe('webdriver request', () => {
it('should throw if timeout happens too often', async () => {
const retryCnt = 3
const req = new WebDriverRequest('POST', '/timeout', {}, true)
const reqRetryCnt = jest.fn()
const reqRetryCnt = vi.fn()
req.on('retry', reqRetryCnt)
const result = await req.makeRequest({
protocol: 'https',
@ -448,10 +452,10 @@ describe('webdriver request', () => {
it('should use error from "getTimeoutError" helper', async () => {
const timeoutErr = new Error('Timeout')
const spy = jest.spyOn(utils, 'getTimeoutError').mockReturnValue(timeoutErr)
const spy = vi.spyOn(utils, 'getTimeoutError').mockReturnValue(timeoutErr)
const req = new WebDriverRequest('GET', '/timeout', {}, true)
req.emit = jest.fn()
req.emit = vi.fn()
const reqOpts = {
protocol: 'https',
hostname: 'localhost',
@ -464,7 +468,7 @@ describe('webdriver request', () => {
expect(spy).toBeCalledTimes(1)
expect(spy).toBeCalledWith(expect.any(Error), expect.objectContaining({ method: 'GET' }))
expect((req.emit as jest.Mock).mock.calls).toHaveLength(3)
expect(vi.mocked(req.emit).mock.calls).toHaveLength(3)
expect(req.emit).toHaveBeenNthCalledWith(1, 'request', expect.anything())
expect(req.emit).toHaveBeenNthCalledWith(2, 'response', { error: timeoutErr })
expect(req.emit).toHaveBeenNthCalledWith(3, 'performance', expect.objectContaining({ success: false }))
@ -476,7 +480,7 @@ describe('webdriver request', () => {
it('should return proper response if retry passes', async () => {
const retryCnt = 7
const req = new WebDriverRequest('POST', '/timeout', {}, true)
const reqRetryCnt = jest.fn()
const reqRetryCnt = vi.fn()
req.on('retry', reqRetryCnt)
const result = await req.makeRequest({
protocol: 'https',
@ -496,7 +500,7 @@ describe('webdriver request', () => {
it('should retry on connection refused error', async () => {
const retryCnt = 7
const req = new WebDriverRequest('POST', '/connectionRefused', {}, true)
const reqRetryCnt = jest.fn()
const reqRetryCnt = vi.fn()
req.on('retry', reqRetryCnt)
const result = await req.makeRequest({
protocol: 'https',
@ -534,8 +538,8 @@ describe('webdriver request', () => {
// @ts-ignore
got.retryCnt = 0
got.mockClear()
warn.mockClear()
error.mockClear()
vi.mocked(got).mockClear()
vi.mocked(warn).mockClear()
vi.mocked(error).mockClear()
})
})

View file

@ -1,4 +1,5 @@
import { URL } from 'url'
import { URL } from 'node:url'
import { describe, it, expect, MockedFunction, vi } from 'vitest'
import { Capabilities, Options } from '@wdio/types'
import { transformCommandLogResult } from '@wdio/utils'
import {
@ -9,6 +10,9 @@ import {
} from '../src/utils'
import type { Client } from '../src/types'
vi.mock('@wdio/utils')
vi.mock('got')
describe('utils', () => {
it('isSuccessfulResponse', () => {
expect(isSuccessfulResponse(200, { value: { some: 'result' } })).toBe(true)
@ -176,25 +180,28 @@ describe('utils', () => {
describe('setupDirectConnect', () => {
class TestClient implements Client {
sessionId: string
capabilities: Capabilities.DesiredCapabilities | Capabilities.W3CCapabilities
requestedCapabilities: Capabilities.DesiredCapabilities | Capabilities.W3CCapabilities
options: Options.WebDriver
// @ts-expect-error
sessionId?: string
// @ts-expect-error
requestedCapabilities?: Capabilities.DesiredCapabilities | Capabilities.W3CCapabilities
constructor(capabilities, options) {
constructor(
public capabilities: Capabilities.DesiredCapabilities | Capabilities.W3CCapabilities,
public options: Options.WebDriver
) {
this.capabilities = capabilities
this.options = options
}
}
it('should do nothing if params contain no direct connect caps', function () {
const client = new TestClient({ platformName: 'baz' }, { hostname: 'bar' }) as Client
const client = new TestClient({ platformName: 'baz' }, { hostname: 'bar' } as any) as Client
setupDirectConnect(client)
expect(client.options.hostname).toEqual('bar')
})
it('should do nothing if params contain incomplete direct connect caps', function () {
const client = new TestClient({ platformName: 'baz', directConnectHost: 'baz' }, { hostname: 'bar' }) as Client
const client = new TestClient({ platformName: 'baz', directConnectHost: 'baz' }, { hostname: 'bar' } as any) as Client
setupDirectConnect(client)
expect(client.options.hostname).toEqual('bar')
})
@ -211,7 +218,7 @@ describe('utils', () => {
hostname: 'foo',
port: 1234,
path: ''
}) as Client
} as any) as Client
setupDirectConnect(client)
expect(client.options.protocol).toBe('https')
expect(client.options.hostname).toBe('bar')
@ -231,7 +238,7 @@ describe('utils', () => {
hostname: 'foo',
port: 1234,
path: ''
}) as Client
} as any) as Client
setupDirectConnect(client)
expect(client.options.protocol).toBe('https')
expect(client.options.hostname).toBe('bar')
@ -327,7 +334,7 @@ describe('utils', () => {
.toBe('mockBrowser')
})
it('should handle sessionRequest error', async () => {
it.only('should handle sessionRequest error', async () => {
let error = await startWebDriverSession({
logLevel: 'warn',
capabilities: {}
@ -409,7 +416,7 @@ describe('utils', () => {
})
it('command args with base64 script', async () => {
(transformCommandLogResult as jest.Mock).mockReturnValueOnce('"<Script[base64]>"')
(transformCommandLogResult as MockedFunction<any>).mockReturnValueOnce('"<Script[base64]>"')
const err = new Error('Timeout')
const cmdArgs = { script: Buffer.from('script').toString('base64') }
@ -435,7 +442,7 @@ describe('utils', () => {
})
it('command args with base64 screenshot', async () => {
(transformCommandLogResult as jest.Mock).mockReturnValueOnce('"<Screenshot[base64]>"')
(transformCommandLogResult as MockedFunction<any>).mockReturnValueOnce('"<Screenshot[base64]>"')
const err = new Error('Timeout')
const cmdArgs = { file: Buffer.from('screen').toString('base64') }

View file

@ -1,9 +0,0 @@
const mock = {}
mock.on = jest.fn().mockReturnValue(mock)
mock.append = jest.fn().mockReturnValue(mock)
mock.finalize = jest.fn().mockReturnValue(mock)
export default (...args) => {
mock.args = args
return mock
}

View file

@ -1,6 +0,0 @@
import type * as fsType from 'fs'
const fs = jest.genMockFromModule<typeof fsType>('fs')
fs.writeFileSync = jest.fn()
fs.existsSync = jest.fn(() => true)
module.exports = fs

View file

@ -1 +0,0 @@
export default jest.fn().mockReturnValue(Promise.resolve(9222))

View file

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