feat: introduce defineConfig function to create a typed configuration object (#14350)

This commit is contained in:
Erwin Heitzman 2025-04-12 15:05:57 +02:00 committed by GitHub
parent 5839f52f0f
commit 61c5243243
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
49 changed files with 133 additions and 148 deletions

View file

@ -1,13 +1,10 @@
import { vi } from 'vitest'
import type { Options } from '../../packages/wdio-types'
import { DEFAULT_CONFIGS as DEFAULT_CONFIGS_IMPORT } from '../../packages/wdio-config/src/constants.js'
import {
isCloudCapability as isCloudCapabilityMock,
validateConfig as validateConfigMock
} from '../../packages/wdio-config/src/utils.js'
export const DEFAULT_CONFIGS = DEFAULT_CONFIGS_IMPORT as () => Options.Testrunner
export { DEFAULT_CONFIGS } from '../../packages/wdio-config/src/constants.js'
export const isCloudCapability = vi.fn().mockImplementation(isCloudCapabilityMock)
export const validateConfig = vi.fn().mockImplementation((defaults, config) => {
const returnVal = validateConfigMock(defaults, config)

View file

@ -4,7 +4,7 @@ This directory demonstrates a simple setup for a wdio test suite with page objec
The goal behind this pattern is to abstract any page information away from the actual tests. Ideally you should store all selectors or specific instructions that are unique for a certain page in a page controller, so that you still can run your test after you've completely redesigned your page and fixed all selectors in the page object.
The examples works without any 3rd party dependencies for assertions. These can be added if desired to make the test even more readable. The code is written using [JavaScript classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes). In order to be able to run the code make sure you run a Node.JS version that supports it or integrate [Babel](https://babeljs.io/) as compiler.
The examples works without any 3rd party dependencies for assertions. These can be added if desired to make the test even more readable. The code is written using [JavaScript classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes). In order to be able to run the code make sure you run a Node.JS version that supports it.
To run the test, change into this directory:

View file

@ -4,7 +4,7 @@ import libCoverage, { type CoverageMap, type CoverageMapData } from 'istanbul-li
import logger from '@wdio/logger'
import type { WebSocketClient } from 'vite'
import type { WorkerInstance } from '@wdio/local-runner'
import { MESSAGE_TYPES, type Options, type Workers } from '@wdio/types'
import { MESSAGE_TYPES, type Workers } from '@wdio/types'
import type { SessionStartedMessage, SessionEndedMessage, WorkerResponseMessage } from '@wdio/runner'
import { SESSIONS } from './constants.js'
@ -22,7 +22,7 @@ interface WorkerMessage {
export class ServerWorkerCommunicator {
#mapStore = libSourceMap.createSourceMapStore()
#config: Options.Testrunner
#config: WebdriverIO.Config
#msgId = 0
/**
@ -37,7 +37,7 @@ export class ServerWorkerCommunicator {
public coverageMaps: CoverageMap[] = []
constructor (config: Options.Testrunner) {
constructor (config: WebdriverIO.Config) {
this.#config = config
}

View file

@ -11,7 +11,6 @@ import libReport from 'istanbul-lib-report'
import reports from 'istanbul-reports'
import type { RunArgs, WorkerInstance } from '@wdio/local-runner'
import type { Options } from '@wdio/types'
import type { MaybeMocked, MaybeMockedDeep, MaybePartiallyMocked, MaybePartiallyMockedDeep } from '@vitest/spy'
import type { InlineConfig } from 'vite'
@ -27,7 +26,7 @@ const log = logger('@wdio/browser-runner')
export default class BrowserRunner extends LocalRunner {
#options: BrowserRunnerOptionsImport
#config: Options.Testrunner
#config: WebdriverIO.Config
#servers: Set<ViteServer> = new Set()
#coverageOptions: CoverageOptions
#reportsDirectory: string
@ -36,7 +35,7 @@ export default class BrowserRunner extends LocalRunner {
constructor(
private options: BrowserRunnerOptionsImport,
protected _config: Options.Testrunner
protected _config: WebdriverIO.Config,
) {
super(options as never, _config)

View file

@ -1,5 +1,5 @@
import type { ConfigEnv, InlineConfig } from 'vite'
import type { Workers, Options } from '@wdio/types'
import type { Workers } from '@wdio/types'
import type { MochaOpts } from '@wdio/mocha-framework'
import type { IstanbulPluginOptions } from 'vite-plugin-istanbul'
@ -132,7 +132,7 @@ export interface RunArgs extends Workers.WorkerRunPayload {
export interface Environment {
args: MochaOpts
config: Options.Testrunner
config: WebdriverIO.Config
capabilities: WebdriverIO.Capabilities
sessionId: string
injectGlobals: boolean

View file

@ -2,7 +2,7 @@ import util from 'node:util'
import { deepmerge } from 'deepmerge-ts'
import logger from '@wdio/logger'
import type { Capabilities, Options } from '@wdio/types'
import type { Capabilities } from '@wdio/types'
import type { CoverageSummary } from 'istanbul-lib-coverage'
import { COVERAGE_FACTORS, GLOBAL_TRESHOLD_REPORTING, FILE_TRESHOLD_REPORTING } from './constants.js'
@ -57,7 +57,7 @@ export function makeHeadless (options: BrowserRunnerOptions, caps: WebdriverIO.C
/**
* Open with devtools open when in watch mode
*/
export function adjustWindowInWatchMode (config: Options.Testrunner, caps: WebdriverIO.Capabilities): WebdriverIO.Capabilities {
export function adjustWindowInWatchMode (config: WebdriverIO.Config, caps: WebdriverIO.Capabilities): WebdriverIO.Capabilities {
if (!config.watch) {
return caps
}

View file

@ -1,11 +1,10 @@
import type { Options } from '@wdio/types'
import type { InlineConfig } from 'vite'
import { isNuxtFramework, optimizeForNuxt } from './nuxt.js'
import { isUsingTailwindCSS, optimizeForTailwindCSS } from './tailwindcss.js'
import { isUsingStencilJS, optimizeForStencil } from './stencil.js'
export default async function updateViteConfig (options: WebdriverIO.BrowserRunnerOptions, config: Options.Testrunner) {
export default async function updateViteConfig (options: WebdriverIO.BrowserRunnerOptions, config: WebdriverIO.Config) {
const optimizations: InlineConfig = {}
const rootDir = options.rootDir || config.rootDir || process.cwd()

View file

@ -2,7 +2,6 @@ import url from 'node:url'
import path from 'node:path'
import logger from '@wdio/logger'
import { resolve } from 'import-meta-resolve'
import type { Options } from '@wdio/types'
import type { InlineConfig } from 'vite'
import { hasFileByExtensions, hasDir } from '../utils.js'
@ -23,7 +22,7 @@ export async function isNuxtFramework (rootDir: string) {
).filter(Boolean).length > 0
}
export async function optimizeForNuxt (options: WebdriverIO.BrowserRunnerOptions, config: Options.Testrunner): Promise<InlineConfig> {
export async function optimizeForNuxt (options: WebdriverIO.BrowserRunnerOptions, config: WebdriverIO.Config): Promise<InlineConfig> {
const Unimport = (await import('unimport/unplugin')).default
const { scanDirExports, scanExports } = await import('unimport')
const { loadNuxtConfig } = await import('@nuxt/kit')

View file

@ -1,7 +1,5 @@
import path from 'node:path'
import type { Options } from '@wdio/types'
import { getManualMocks } from './utils.js'
import { DEFAULT_MOCK_DIRECTORY, DEFAULT_AUTOMOCK } from '../constants.js'
import type { MockRequestEvent } from './types.js'
@ -17,7 +15,7 @@ export class MockHandler {
manualMocks: string[] = []
constructor (options: WebdriverIO.BrowserRunnerOptions, config: Options.Testrunner) {
constructor (options: WebdriverIO.BrowserRunnerOptions, config: WebdriverIO.Config) {
this.#automock = typeof options.automock === 'boolean' ? options.automock : DEFAULT_AUTOMOCK
this.#automockDir = path.resolve(config.rootDir!, options.automockDir || DEFAULT_MOCK_DIRECTORY)
this.#manualMocksList = getManualMocks(this.#automockDir)

View file

@ -7,7 +7,6 @@ import istanbulPlugin from 'vite-plugin-istanbul'
import { deepmerge } from 'deepmerge-ts'
import { createServer } from 'vite'
import type { ViteDevServer, InlineConfig, ConfigEnv } from 'vite'
import type { Options } from '@wdio/types'
import { testrunner } from './plugins/testrunner.js'
import { mockHoisting } from './plugins/mockHoisting.js'
@ -28,7 +27,7 @@ const DEFAULT_CONFIG_ENV: ConfigEnv = {
*/
export class ViteServer extends EventEmitter {
#options: WebdriverIO.BrowserRunnerOptions
#config: Options.Testrunner
#config: WebdriverIO.Config
#viteConfig: Partial<InlineConfig>
#server?: ViteDevServer
#mockHandler: MockHandler
@ -38,7 +37,7 @@ export class ViteServer extends EventEmitter {
return this.#viteConfig
}
constructor (options: WebdriverIO.BrowserRunnerOptions, config: Options.Testrunner, optimizations: InlineConfig) {
constructor (options: WebdriverIO.BrowserRunnerOptions, config: WebdriverIO.Config, optimizations: InlineConfig) {
super()
this.#options = options
this.#config = config

View file

@ -3,7 +3,7 @@ import chalk, { supportsColor } from 'chalk'
import logger from '@wdio/logger'
import { SnapshotManager } from '@vitest/snapshot/manager'
import type { SnapshotResult } from '@vitest/snapshot'
import type { Options, Workers } from '@wdio/types'
import type { Workers } from '@wdio/types'
import { HookError } from './utils.js'
import { getRunnerName } from './utils.js'
@ -58,7 +58,7 @@ export default class WDIOCLInterface extends EventEmitter {
}
constructor(
private _config: Options.Testrunner,
private _config: WebdriverIO.Config,
public totalWorkerCnt: number,
private _isWatchMode = false
) {

View file

@ -6,7 +6,7 @@ import { validateConfig } from '@wdio/config'
import { ConfigParser } from '@wdio/config/node'
import { initializePlugin, initializeLauncherService, sleep, enableFileLogging } from '@wdio/utils'
import { setupDriver, setupBrowser } from '@wdio/utils/node'
import type { Options, Capabilities, Services } from '@wdio/types'
import type { Capabilities, Services } from '@wdio/types'
import CLInterface from './interface.js'
import { runLauncherHook, runOnCompleteHook, runServiceHook, nodeVersion, type HookError } from './utils.js'
@ -215,7 +215,7 @@ class Launcher {
* available running hooks in this order
*/
async #runOnCompleteHook (
config: Required<Options.Testrunner>,
config: Required<WebdriverIO.Config>,
caps: Capabilities.TestrunnerCapabilities,
exitCode: number
): Promise<number> {
@ -232,7 +232,7 @@ class Launcher {
/**
* run without triggering onPrepare/onComplete hooks
*/
private _runMode(config: Required<Options.Testrunner>, caps?: Capabilities.TestrunnerCapabilities): Promise<number> {
private _runMode(config: Required<WebdriverIO.Config>, caps?: Capabilities.TestrunnerCapabilities): Promise<number> {
/**
* fail if
*/

View file

@ -17,7 +17,7 @@ import { resolve } from 'import-meta-resolve'
import { SevereServiceError } from 'webdriverio'
import { ConfigParser } from '@wdio/config/node'
import { CAPABILITY_KEYS } from '@wdio/protocols'
import type { Capabilities, Options, Services } from '@wdio/types'
import type { Capabilities, Services } from '@wdio/types'
import { installPackages, getInstallCommand } from './install.js'
import {
@ -129,7 +129,7 @@ export async function runLauncherHook(hook: Function | Function[], ...args: unkn
*/
export async function runOnCompleteHook(
onCompleteHook: Function | Function[],
config: Options.Testrunner,
config: WebdriverIO.Config,
capabilities: Capabilities.TestrunnerCapabilities,
exitCode: number,
results: OnCompleteResult
@ -337,23 +337,6 @@ export async function getCapabilities(arg: ReplCommandArguments) {
return { capabilities: { browserName: arg.option } }
}
/**
* Checks if certain directory has babel configuration files
* @param rootDir directory where this function checks for Babel signs
* @returns true, if a babel config was found, otherwise false
*/
export function hasBabelConfig(rootDir: string) {
return Promise.all([
fs.access(path.join(rootDir, 'babel.js')),
fs.access(path.join(rootDir, 'babel.cjs')),
fs.access(path.join(rootDir, 'babel.mjs')),
fs.access(path.join(rootDir, '.babelrc'))
]).then(
(results) => results.filter(Boolean).length > 1,
() => false
)
}
/**
* detect if project has a compiler file
*/
@ -364,8 +347,8 @@ export async function detectCompiler(answers: Questionnair) {
}
const root = await getProjectRoot(answers)
const rootTSConfigExist = await fs.access(path.resolve(root, 'tsconfig.json')).then(() => true, () => false)
return (await hasBabelConfig(root) || rootTSConfigExist) ? true : false
const hasRootTSConfig = await fs.access(path.resolve(root, 'tsconfig.json')).then(() => true, () => false)
return hasRootTSConfig
}
/**

View file

@ -41,7 +41,7 @@ import {
} from '../src/utils.js'
import { parseAnswers } from '../src/commands/config.js'
import { installPackages } from '../src/install.js'
import { hasBabelConfig } from '../src/utils.js'
import type { Questionnair } from '../src/types.js'
vi.mock('ejs')
vi.mock('inquirer')
@ -91,7 +91,7 @@ vi.mock('../src/install', () => ({
beforeEach(() => {
global.console.log = vi.fn()
vi.mocked(readPackageUp).mockReturnValue({
vi.mocked(readPackageUp).mockResolvedValue({
path: '/foo/package.json',
packageJson: {
name: 'cool-test-module',
@ -198,7 +198,7 @@ test('runOnCompleteHook handles array of functions', () => {
const hookSuccess = vi.fn()
const secondHook = vi.fn()
runOnCompleteHook([hookSuccess, secondHook], { capabilities: {} }, {}, 0, {} as any)
runOnCompleteHook([hookSuccess, secondHook], { capabilities: [] }, {}, 0, {} as any)
expect(hookSuccess).toBeCalledTimes(1)
expect(secondHook).toBeCalledTimes(1)
})
@ -207,14 +207,14 @@ test('runOnCompleteHook handles async functions', async () => {
const hookSuccess = () => new Promise(resolve => setTimeout(resolve, 31))
const start = Date.now()
await runOnCompleteHook([hookSuccess], { capabilities: {} }, {}, 0, {} as any)
await runOnCompleteHook([hookSuccess], { capabilities: [] }, {}, 0, {} as any)
expect(Date.now() - start).toBeGreaterThanOrEqual(30)
})
test('runOnCompleteHook handles a single function', () => {
const hookSuccess = vi.fn()
runOnCompleteHook(hookSuccess, { capabilities: {} }, {}, 0, {} as any)
runOnCompleteHook(hookSuccess, { capabilities: [] }, {}, 0, {} as any)
expect(hookSuccess).toBeCalledTimes(1)
})
@ -222,7 +222,7 @@ test('runOnCompleteHook with no failure returns 0', async () => {
const hookSuccess = vi.fn()
const hookFailing = vi.fn()
const result = await runOnCompleteHook([hookSuccess, hookFailing], { capabilities: {} }, {}, 0, {} as any)
const result = await runOnCompleteHook([hookSuccess, hookFailing], { capabilities: [] }, {}, 0, {} as any)
expect(result).not.toContain(1)
expect(hookSuccess).toBeCalledTimes(1)
@ -233,7 +233,7 @@ test('runOnCompleteHook with failure returns 1', async () => {
const hookSuccess = vi.fn()
const hookFailing = vi.fn().mockImplementation(() => { throw new Error('buhh') })
const result = await runOnCompleteHook([hookSuccess, hookFailing], { capabilities: {} }, {}, 0, {} as any)
const result = await runOnCompleteHook([hookSuccess, hookFailing], { capabilities: [] }, {}, 0, {} as any)
expect(result).toContain(1)
expect(hookSuccess).toBeCalledTimes(1)
@ -244,7 +244,7 @@ test('runOnCompleteHook fails with SevereServiceError', async () => {
const hookSuccess = vi.fn()
const hookFailing = vi.fn().mockImplementation(() => { throw new SevereServiceError('buhh') })
const result = await runOnCompleteHook([hookSuccess, hookFailing], { capabilities: {} }, {}, 0, {} as any)
const result = await runOnCompleteHook([hookSuccess, hookFailing], { capabilities: [] }, {}, 0, {} as any)
.catch(() => 'some error')
expect(result).toBe('some error')
@ -264,9 +264,9 @@ test('getRunnerName', () => {
// @ts-ignore test invalid parameter
expect(getRunnerName({ foo: {} })).toBe('undefined')
// @ts-ignore test invalid parameter
expect(getRunnerName({ foo: { capabilities: {} }, bar: {} })).toBe('undefined')
expect(getRunnerName({ foo: { capabilities: [] }, bar: {} })).toBe('undefined')
// @ts-ignore test invalid parameter
expect(getRunnerName({ foo: { capabilities: {} } })).toBe('MultiRemote')
expect(getRunnerName({ foo: { capabilities: [] } })).toBe('MultiRemote')
})
describe('findInConfig', () => {
@ -424,7 +424,7 @@ describe('getCapabilities', () => {
browserName: 'chrome',
'goog:chromeOptions': { 'args': ['window-size=8000,1200'] }
}
])
] as WebdriverIO.Capabilities)
expect(await getCapabilities({ option: '/path/to/config.js', capabilities: 2 } as any))
.toMatchSnapshot()
expect(autoCompileMock).toBeCalledTimes(1)
@ -783,16 +783,9 @@ test('getProjectRoot', async () => {
} as any)).toBe('/bar/foo')
})
test('hasBabelConfig', async () => {
vi.mocked(fs.access).mockResolvedValue({} as any)
expect(await hasBabelConfig('/foo')).toBe(true)
vi.mocked(fs.access).mockRejectedValue(new Error('not found'))
expect(await hasBabelConfig('/foo')).toBe(false)
})
test('detectCompiler', async () => {
vi.mocked(readPackageUp).mockRestore()
const answers = { createPackageJSON: true }
const answers = { createPackageJSON: true } as Questionnair
expect(await detectCompiler(answers)).toBe(false)
})

View file

@ -1,12 +1,13 @@
import type { Options, Services } from '@wdio/types'
import type { Services } from '@wdio/types'
const DEFAULT_TIMEOUT = 10000
/* istanbul ignore next */
export const DEFAULT_CONFIGS: () => Options.Testrunner = () => ({
export const DEFAULT_CONFIGS: () => WebdriverIO.Config = () => ({
specs: [],
suites: {},
exclude: [],
capabilities: [],
outputDir: undefined,
logLevel: 'info' as const,
logLevels: {},

View file

@ -1,13 +1,14 @@
/* istanbul ignore file */
import { DEFAULT_CONFIGS } from './constants.js'
import { validateConfig, isCloudCapability } from './utils.js'
import { defineConfig, validateConfig, isCloudCapability } from './utils.js'
export {
/**
* configuration helpers
*/
validateConfig,
defineConfig,
isCloudCapability,
/**

View file

@ -416,7 +416,7 @@ export default class ConfigParser {
if (!this.#isInitialised) {
throw new Error('ConfigParser was not initialized, call "await config.initialize()" first!')
}
return this._config as Required<Options.Testrunner>
return this._config as Required<WebdriverIO.Config>
}
/**

View file

@ -1,4 +1,5 @@
import type { Options } from '@wdio/types'
import { DEFAULT_CONFIGS } from './constants.js'
export const validObjectOrArray = (object: object): object is object | Array<unknown> => (Array.isArray(object) && object.length > 0) ||
(typeof object === 'object' && Object.keys(object).length > 0)
@ -31,6 +32,14 @@ export function isCloudCapability(caps: WebdriverIO.Capabilities) {
return Boolean(caps && (caps['bstack:options'] || caps['sauce:options'] || caps['tb:options']))
}
/**
* Creates a configuration object while providing types for both TypeScript and Javascript
*/
export const defineConfig = (options?: Partial<WebdriverIO.Config> | WebdriverIO.Config): WebdriverIO.Config => ({
...DEFAULT_CONFIGS(),
...options,
})
/**
* validates configurations based on default values
* @param {Object} defaults object describing all allowed properties

View file

@ -1,6 +1,6 @@
import type { Options } from '@wdio/types'
export const config: Partial<Options.Testrunner> = {
export const config: Partial<WebdriverIO.Config> = {
hostname: '127.0.0.1',
port: 4444
}

View file

@ -12,7 +12,7 @@ import { sync as globSync } from 'glob'
import logger from '@wdio/logger'
import { executeHooksWithArgs, testFnWrapper } from '@wdio/utils'
import type { Capabilities, Options, Frameworks } from '@wdio/types'
import type { Capabilities, Frameworks } from '@wdio/types'
import {
setDefaultTimeout,
@ -65,7 +65,7 @@ export class CucumberAdapter {
constructor(
private _cid: string,
private _config: Options.Testrunner,
private _config: WebdriverIO.Config,
private _specs: string[],
private _capabilities: Capabilities.ResolvedTestrunnerCapabilities,
private _reporter: EventEmitter,
@ -138,7 +138,7 @@ export class CucumberAdapter {
}
readFiles(
filePaths: Options.Testrunner['specs'] = []
filePaths: WebdriverIO.Config['specs'] = []
): (string | string[])[] {
return filePaths.map((filePath) => {
return Array.isArray(filePath)
@ -150,7 +150,7 @@ export class CucumberAdapter {
}
getGherkinDocuments(
files: Options.Testrunner['specs'] = []
files: WebdriverIO.Config['specs'] = []
): (GherkinDocument | GherkinDocument[])[] {
return this.readFiles(files).map((specContent, idx) => {
const docs: GherkinDocument[] = [specContent].flat(1).map(
@ -379,7 +379,7 @@ export class CucumberAdapter {
* @param {object} config config
*/
addWdioHooks(
config: Options.Testrunner,
config: WebdriverIO.Config,
supportCodeLibraryBuilder: typeof Cucumber.supportCodeLibraryBuilder
) {
const params: { uri?: string; feature?: Feature } = {}
@ -440,7 +440,7 @@ export class CucumberAdapter {
* wraps step definition code with sync/async runner with a retry option
* @param {object} config
*/
wrapSteps (config: Options.Testrunner) {
wrapSteps (config: WebdriverIO.Config) {
const wrapStep = this.wrapStep
const cid = this._cid
@ -494,7 +494,7 @@ export class CucumberAdapter {
wrapStep(
code: Function,
isStep: boolean,
config: Options.Testrunner,
config: WebdriverIO.Config,
cid: string,
options: StepDefinitionOptions,
getHookParams: Function,

View file

@ -6,7 +6,7 @@ import logger from '@wdio/logger'
import { wrapGlobalTestMethod, executeHooksWithArgs } from '@wdio/utils'
import { expect as expectImport, matchers, getConfig } from 'expect-webdriverio'
import { _setGlobal } from '@wdio/globals'
import type { Options, Services, Capabilities } from '@wdio/types'
import type { Services, Capabilities } from '@wdio/types'
import JasmineReporter from './reporter.js'
import { jestResultToJasmine } from './utils.js'
@ -38,7 +38,7 @@ type HooksArray = {
[K in keyof Required<Services.HookFunctions>]: Required<Services.HookFunctions>[K][]
}
interface WebdriverIOJasmineConfig extends Omit<Options.Testrunner, keyof HooksArray>, HooksArray {
interface WebdriverIOJasmineConfig extends Omit<WebdriverIO.Config, keyof HooksArray>, HooksArray {
jasmineOpts: Omit<jasmineNodeOpts, 'cleanStack'>
}

View file

@ -1,6 +1,6 @@
import logger from '@wdio/logger'
import { WritableStreamBuffer } from 'stream-buffers'
import type { Options, Workers } from '@wdio/types'
import type { Workers } from '@wdio/types'
import WorkerInstance from './worker.js'
import { SHUTDOWN_TIMEOUT, BUFFER_OPTIONS } from './constants.js'
@ -22,7 +22,7 @@ export default class LocalRunner {
constructor (
private _options: never,
protected _config: Options.Testrunner
protected _config: WebdriverIO.Config
) {}
/**

View file

@ -4,7 +4,7 @@ import child from 'node:child_process'
import { EventEmitter } from 'node:events'
import type { ChildProcess } from 'node:child_process'
import type { WritableStreamBuffer } from 'stream-buffers'
import type { Options, Workers } from '@wdio/types'
import type { Workers } from '@wdio/types'
import type { ReplConfig } from '@wdio/repl'
import logger from '@wdio/logger'
@ -30,7 +30,7 @@ stdErrStream.pipe(process.stderr)
*/
export default class WorkerInstance extends EventEmitter implements Workers.Worker {
cid: string
config: Options.Testrunner
config: WebdriverIO.Config
configFile: string
// requestedCapabilities
caps: WebdriverIO.Capabilities
@ -67,7 +67,7 @@ export default class WorkerInstance extends EventEmitter implements Workers.Work
* @param {object} execArgv execution arguments for the test run
*/
constructor(
config: Options.Testrunner,
config: WebdriverIO.Config,
{ cid, configFile, caps, specs, execArgv, retries }: Workers.WorkerRunPayload,
stdout: WritableStreamBuffer,
stderr: WritableStreamBuffer

View file

@ -7,7 +7,7 @@ import { handleRequires } from 'mocha/lib/cli/run-helpers.js'
import logger from '@wdio/logger'
import { executeHooksWithArgs } from '@wdio/utils'
import type { Services, Options } from '@wdio/types'
import type { Services } from '@wdio/types'
import { formatMessage, setupEnv } from './common.js'
import { EVENTS, NOOP } from './constants.js'
@ -19,7 +19,7 @@ const FILE_PROTOCOL = 'file://'
type EventTypes = 'hook' | 'test' | 'suite'
type EventTypeProps = '_hookCnt' | '_testCnt' | '_suiteCnt'
interface ParsedConfiguration extends Required<Options.Testrunner> {
interface ParsedConfiguration extends Required<WebdriverIO.Config> {
rootDir: string
mochaOpts: MochaOptsImport
}

View file

@ -6,7 +6,7 @@ import { browser } from '@wdio/globals'
import { executeHooksWithArgs } from '@wdio/utils'
import { matchers } from 'expect-webdriverio'
import { ELEMENT_KEY } from 'webdriver'
import { type Workers, type Options, type Services, MESSAGE_TYPES } from '@wdio/types'
import { type Workers, type Services, MESSAGE_TYPES } from '@wdio/types'
import { transformExpectArgs } from './utils.js'
import type BaseReporter from './reporter.js'
@ -56,7 +56,7 @@ export default class BrowserFramework implements Omit<TestFramework, 'init'> {
constructor (
private _cid: string,
private _config: Options.Testrunner & { sessionId?: string },
private _config: WebdriverIO.Config & { sessionId?: string },
private _specs: string[],
private _reporter: BaseReporter
) {
@ -527,7 +527,7 @@ export default class BrowserFramework implements Omit<TestFramework, 'init'> {
}
}
static init (cid: string, config: Options.Testrunner, specs: string[], _: unknown, reporter: BaseReporter) {
static init (cid: string, config: WebdriverIO.Config, specs: string[], _: unknown, reporter: BaseReporter) {
const framework = new BrowserFramework(cid, config, specs, reporter)
return framework
}

View file

@ -29,7 +29,7 @@ export default class Runner extends EventEmitter {
private _reporter?: BaseReporter
private _framework?: TestFramework
private _config?: Options.Testrunner
private _config?: WebdriverIO.Config
private _cid?: string
private _specs?: string[]
private _caps?: Capabilities.RequestedStandaloneCapabilities | Capabilities.RequestedMultiremoteCapabilities
@ -109,7 +109,7 @@ export default class Runner extends EventEmitter {
* run `beforeSession` command before framework and browser are initiated
*/
;(await initializeWorkerService(
this._config as Options.Testrunner,
this._config as WebdriverIO.Config,
this._caps as WebdriverIO.Capabilities,
args.ignoredWorkerServices
)).map(this._configParser.addService.bind(this._configParser))
@ -233,7 +233,7 @@ export default class Runner extends EventEmitter {
async #initFramework (
cid: string,
config: Options.Testrunner,
config: WebdriverIO.Config,
capabilities: Capabilities.RequestedStandaloneCapabilities | Capabilities.RequestedMultiremoteCapabilities,
reporter: BaseReporter,
specs: string[]
@ -267,7 +267,7 @@ export default class Runner extends EventEmitter {
* @return {Promise} resolves with browser object or null if session couldn't get established
*/
private async _initSession (
config: Options.Testrunner,
config: WebdriverIO.Config,
caps: Capabilities.RequestedStandaloneCapabilities | Capabilities.RequestedMultiremoteCapabilities
) {
const browser = await this._startSession(config, caps) as WebdriverIO.Browser
@ -309,7 +309,7 @@ export default class Runner extends EventEmitter {
* @return {Promise} resolves with browser object or null if session couldn't get established
*/
private async _startSession (
config: Options.Testrunner,
config: WebdriverIO.Config,
caps: Capabilities.RequestedStandaloneCapabilities | Capabilities.RequestedMultiremoteCapabilities
) {
try {

View file

@ -1,4 +1,4 @@
import type { Options, Capabilities, Services, Workers } from '@wdio/types'
import type { Capabilities, Services, Workers } from '@wdio/types'
import type BaseReporter from './reporter.js'
export type BeforeArgs = Parameters<Required<Services.HookFunctions>['before']>
@ -6,7 +6,7 @@ export type AfterArgs = Parameters<Required<Services.HookFunctions>['after']>
export type BeforeSessionArgs = Parameters<Required<Services.HookFunctions>['beforeSession']>
export type AfterSessionArgs = Parameters<Required<Services.HookFunctions>['afterSession']>
interface Args extends Partial<Options.Testrunner> {
interface Args extends Partial<WebdriverIO.Config> {
ignoredWorkerServices?: string[]
watch?: boolean
}
@ -23,7 +23,7 @@ export type RunParams = {
export interface TestFramework {
init: (
cid: string,
config: Options.Testrunner,
config: WebdriverIO.Config,
specs: string[],
capabilities: Capabilities.RequestedStandaloneCapabilities | Capabilities.RequestedMultiremoteCapabilities,
reporter: BaseReporter

View file

@ -53,7 +53,7 @@ export function sanitizeCaps (
* @return {Promise} resolves with browser object
*/
export async function initializeInstance (
config: ConfigWithSessionId | Options.Testrunner,
config: ConfigWithSessionId | WebdriverIO.Config,
capabilities: Capabilities.RequestedStandaloneCapabilities | Capabilities.RequestedMultiremoteCapabilities,
isMultiremote?: boolean
): Promise<WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser> {

View file

@ -1,6 +1,5 @@
import path from 'node:path'
import { describe, expect, it, vi, test, afterEach } from 'vitest'
import type { Options } from '@wdio/types'
import BaseReporter from '../src/reporter.js'
@ -32,7 +31,7 @@ describe('BaseReporter', () => {
'dot',
['dot', { foo: 'bar' }]
]
} as Options.Testrunner, '0-0', capability)
} as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
expect(reporter['_reporters']).toHaveLength(2)
@ -41,8 +40,8 @@ describe('BaseReporter', () => {
it('should make "dot" reporter default', async () => {
const reporter = new BaseReporter({
outputDir: '/foo/bar',
reporters: []
} as Options.Testrunner, '0-0', capability)
reporters: [],
} as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
expect(reporter['_reporters']).toHaveLength(1)
@ -56,7 +55,7 @@ describe('BaseReporter', () => {
'dot',
['dot', { foo: 'bar' }]
]
} as Options.Testrunner, '0-0', capability)
} as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
expect(reporter.getLogFile('foobar'))
@ -71,7 +70,7 @@ describe('BaseReporter', () => {
['dot', { foo: 'bar', logFile: '/foobar.log' }]
],
capabilities: [capability]
} as Options.Testrunner, '0-0', capability)
} as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
// @ts-expect-error
@ -92,7 +91,7 @@ describe('BaseReporter', () => {
}]
],
capabilities: [capability]
} as Options.Testrunner, '0-0', capability)
} as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
expect(reporter.getLogFile('dot'))
.toMatch(/(\\|\/)foo(\\|\/)bar(\\|\/)baz(\\|\/)wdio-0-0-dot-reporter.log/)
@ -116,7 +115,7 @@ describe('BaseReporter', () => {
}
}]
]
} as Options.Testrunner, '0-0', capability)
} as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
expect(reporter.getLogFile('dot'))
.toMatch(/(\\|\/)foo(\\|\/)bar(\\|\/)wdio-results-0-0-foo.log/)
@ -133,7 +132,7 @@ describe('BaseReporter', () => {
outputFileFormat: 'foo'
}]
]
} as Options.Testrunner, '0-0', capability)
} as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
}).rejects.toThrow('outputFileFormat must be a function')
})
@ -144,7 +143,7 @@ describe('BaseReporter', () => {
'dot',
['dot', { foo: 'bar' }]
]
} as Options.Testrunner, '0-0', capability)
} as WebdriverIO.Config, '0-0', capability)
expect(reporter.getLogFile('foobar')).toBe(undefined)
})
@ -156,7 +155,7 @@ describe('BaseReporter', () => {
'dot',
['dot', { foo: 'bar' }]
]
} as Options.Testrunner, '0-0', capability)
} as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
const payload: any = { foo: [1, 2, 3] }
@ -175,7 +174,7 @@ describe('BaseReporter', () => {
'dot',
['dot', { foo: 'bar' }]
]
} as Options.Testrunner, '0-0', capability)
} as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
const payload: any = { foo: [1, 2, 3] }
@ -195,7 +194,7 @@ describe('BaseReporter', () => {
'dot',
['dot', { foo: 'bar' }]
]
} as Options.Testrunner, '0-0', capability)
} as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
const error = new Error('foobar')
@ -214,7 +213,7 @@ describe('BaseReporter', () => {
const workingReporter = ['dot', { foo: 'bar' }]
const reporter = new BaseReporter({
outputDir: '/foo/bar',
reporters: [faultyReporter, workingReporter] } as Options.Testrunner, '0-0', capability)
reporters: [faultyReporter, workingReporter] } as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
const faultyReporterInstance = reporter['_reporters'][0]
@ -250,7 +249,7 @@ describe('BaseReporter', () => {
outputDir: '/foo/bar',
reporters: [CustomReporter] as any,
capabilities: [capability]
} as Options.Testrunner, '0-0', capability)
} as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
expect(reporter['_reporters']).toHaveLength(1)
// @ts-ignore
@ -264,7 +263,7 @@ describe('BaseReporter', () => {
outputDir: '/foo/baz/bar'
}]] as any,
capabilities: [capability]
} as Options.Testrunner, '0-0', capability)
} as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
expect(reporter.getLogFile('CustomReporter')).toMatch(/(\\|\/)foo(\\|\/)baz(\\|\/)bar(\\|\/)wdio-0-0-CustomReporter-reporter.log/)
@ -277,7 +276,7 @@ describe('BaseReporter', () => {
outputDir: '/foo/bar',
reporters: [{ foo: 'bar' } as any],
capabilities: [capability]
} as Options.Testrunner, '0-0', capability)
} as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
} catch (err: any) {
expect(err.message).toBe('Invalid reporters config')
@ -292,7 +291,7 @@ describe('BaseReporter', () => {
outputDir: '/foo/bar',
reporters: [CustomReporter, CustomReporter] as any,
capabilities: [capability]
} as Options.Testrunner, '0-0', capability)
} as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
// @ts-ignore test reporter param
@ -312,7 +311,7 @@ describe('BaseReporter', () => {
reporterSyncInterval: 10,
reporterSyncTimeout: 100,
capabilities: [capability]
} as Options.Testrunner, '0-0', capability)
} as WebdriverIO.Config, '0-0', capability)
await reporter.initReporters()
// @ts-ignore test reporter param

View file

@ -167,6 +167,7 @@ export interface WebdriverIO extends WebDriver, Pick<Hooks, 'onReload' | 'before
/**
* Default interval for all `waitFor*` commands to check if an expected state (e.g.,
* visibility) has been changed.
* @default 500
*/
waitforInterval?: number
}
@ -304,19 +305,27 @@ export interface Testrunner extends Hooks, WebdriverIO, WebdriverIO.HookFunction
* @default []
*/
cucumberFeaturesWithLineNumbers?: string[]
// flags
/**
* flags
* Toggle watch mode on/off
*/
watch?: boolean
/**
* Shard tests and execute only the selected shard. Specify in the one-based form like `{ total: 5, current: 2 }`.
*/
shard?: ShardOptions
// framework options
/**
* framework options
* Mocha specific options
*/
mochaOpts?: WebdriverIO.MochaOpts
/**
* Jasmine specific options
*/
jasmineOpts?: WebdriverIO.JasmineOpts
/**
* Cucumber specific options
*/
cucumberOpts?: WebdriverIO.CucumberOpts
/**
* TSX custom TSConfig path

View file

@ -1,4 +1,4 @@
import type { Services, Options, Capabilities } from '@wdio/types'
import type { Services, Capabilities } from '@wdio/types'
import logger from '@wdio/logger'
import initializePlugin from './initializePlugin.js'
@ -92,7 +92,7 @@ function sanitizeServiceArray (service: Services.ServiceEntry): ServiceWithOptio
* required in the worker
*/
export async function initializeLauncherService (
config: Omit<Options.Testrunner, 'capabilities' | keyof Services.HookFunctions>,
config: Omit<WebdriverIO.Config, 'capabilities' | keyof Services.HookFunctions>,
caps: Capabilities.TestrunnerCapabilities
): Promise<{
ignoredWorkerServices: string[];
@ -159,7 +159,7 @@ export async function initializeLauncherService (
* @return {Object[]} list if worker initiated worker services
*/
export async function initializeWorkerService (
config: Options.Testrunner,
config: WebdriverIO.Config,
caps: WebdriverIO.Capabilities,
ignoredWorkerServices: string[] = []
): Promise<Services.ServiceInstance[]> {

View file

@ -1,6 +1,6 @@
import nock from 'nock'
import { v4 as uuidv4 } from 'uuid'
import type { Services, Options } from '@wdio/types'
import type { Services } from '@wdio/types'
import WebDriverMock from './WebDriverMock.js'
@ -38,7 +38,7 @@ export default class WebdriverMockService implements Services.ServiceInstance {
this._mock.command.getLogTypes().reply(200, { value: [] })
}
beforeSession(config: Options.Testrunner): void {
beforeSession(config: WebdriverIO.Config): void {
config.hostname = 'localhost'
config.port = 4444
}

View file

@ -1,6 +1,5 @@
import path from 'node:path'
import assert from 'node:assert'
import type { Options } from '@wdio/types'
describe('Mocha smoke test', () => {
const testJs = path.join('tests', 'mocha', 'test.ts')
@ -30,7 +29,7 @@ describe('Mocha smoke test', () => {
})
it('has a testrunner config object', () => {
const opts = browser.options as Options.Testrunner
const opts = browser.options as WebdriverIO.Config
expect(Array.isArray(opts.services)).toBe(true)
expect(opts).toHaveProperty('mochaOpts')
expect(opts).toHaveProperty('jasmineOpts')

View file

@ -89,7 +89,7 @@ export default class CustomWorkerService implements Services.ServiceInstance {
constructor (
private _options: MyServiceOptions,
private _capabilities: Capabilities.RemoteCapability,
private _config: Options.Testrunner
private _config: WebdriverIO.Config,
) {
// ...
}

View file

@ -8,7 +8,7 @@ You can use WebdriverIO with your existing Selenium Grid instance. To connect yo
Here is a code snippet from sample wdio.conf.ts.
```ts title=wdio.conf.ts
export const config: Options.Testrunner = {
export const config: WebdriverIO.Config = {
// ...
protocol: 'https',
hostname: 'yourseleniumgridhost.yourdomain.com',
@ -22,7 +22,7 @@ You need to provide the appropriate values for the protocol, hostname, port, and
If you are running Selenium Grid on the same machine as your test scripts, here are some typical options:
```ts title=wdio.conf.ts
export const config: Options.Testrunner = {
export const config: WebdriverIO.Config = {
// ...
protocol: 'http',
hostname: 'localhost',

View file

@ -89,7 +89,7 @@ export default class CustomWorkerService implements Services.ServiceInstance {
constructor (
private _options: MyServiceOptions,
private _capabilities: Capabilities.RemoteCapability,
private _config: Options.Testrunner
private _config: WebdriverIO.Config,
) {
// ...
}

View file

@ -89,7 +89,7 @@ export default class CustomWorkerService implements Services.ServiceInstance {
constructor (
private _options: MyServiceOptions,
private _capabilities: Capabilities.RemoteCapability,
private _config: Options.Testrunner
private _config: WebdriverIO.Config,
) {
// ...
}

View file

@ -89,7 +89,7 @@ export default class CustomWorkerService implements Services.ServiceInstance {
constructor (
private _options: MyServiceOptions,
private _capabilities: Capabilities.RemoteCapability,
private _config: Options.Testrunner
private _config: WebdriverIO.Config,
) {
// ...
}

View file

@ -89,7 +89,7 @@ export default class CustomWorkerService implements Services.ServiceInstance {
constructor (
private _options: MyServiceOptions,
private _capabilities: Capabilities.RemoteCapability,
private _config: Options.Testrunner
private _config: WebdriverIO.Config,
) {
// ...
}

View file

@ -89,7 +89,7 @@ export default class CustomWorkerService implements Services.ServiceInstance {
constructor (
private _options: MyServiceOptions,
private _capabilities: Capabilities.RemoteCapability,
private _config: Options.Testrunner
private _config: WebdriverIO.Config,
) {
// ...
}

View file

@ -89,7 +89,7 @@ export default class CustomWorkerService implements Services.ServiceInstance {
constructor (
private _options: MyServiceOptions,
private _capabilities: Capabilities.RemoteCapability,
private _config: Options.Testrunner
private _config: WebdriverIO.Config,
) {
// ...
}

View file

@ -89,7 +89,7 @@ export default class CustomWorkerService implements Services.ServiceInstance {
constructor (
private _options: MyServiceOptions,
private _capabilities: Capabilities.RemoteCapability,
private _config: Options.Testrunner
private _config: WebdriverIO.Config,
) {
// ...
}

View file

@ -89,7 +89,7 @@ export default class CustomWorkerService implements Services.ServiceInstance {
constructor (
private _options: MyServiceOptions,
private _capabilities: Capabilities.RemoteCapability,
private _config: Options.Testrunner
private _config: WebdriverIO.Config,
) {
// ...
}

View file

@ -89,7 +89,7 @@ export default class CustomWorkerService implements Services.ServiceInstance {
constructor (
private _options: MyServiceOptions,
private _capabilities: Capabilities.RemoteCapability,
private _config: Options.Testrunner
private _config: WebdriverIO.Config,
) {
// ...
}

View file

@ -89,7 +89,7 @@ export default class CustomWorkerService implements Services.ServiceInstance {
constructor (
private _options: MyServiceOptions,
private _capabilities: Capabilities.RemoteCapability,
private _config: Options.Testrunner
private _config: WebdriverIO.Config,
) {
// ...
}

View file

@ -89,7 +89,7 @@ export default class CustomWorkerService implements Services.ServiceInstance {
constructor (
private _options: MyServiceOptions,
private _capabilities: Capabilities.RemoteCapability,
private _config: Options.Testrunner
private _config: WebdriverIO.Config,
) {
// ...
}

View file

@ -89,7 +89,7 @@ export default class CustomWorkerService implements Services.ServiceInstance {
constructor (
private _options: MyServiceOptions,
private _capabilities: Capabilities.RemoteCapability,
private _config: Options.Testrunner
private _config: WebdriverIO.Config,
) {
// ...
}

View file

@ -89,7 +89,7 @@ export default class CustomWorkerService implements Services.ServiceInstance {
constructor (
private _options: MyServiceOptions,
private _capabilities: Capabilities.RemoteCapability,
private _config: Options.Testrunner
private _config: WebdriverIO.Config,
) {
// ...
}

View file

@ -89,7 +89,7 @@ export default class CustomWorkerService implements Services.ServiceInstance {
constructor (
private _options: MyServiceOptions,
private _capabilities: Capabilities.RemoteCapability,
private _config: Options.Testrunner
private _config: WebdriverIO.Config,
) {
// ...
}