rewrite @wdio/cli into ESM

This commit is contained in:
Christian Bromann 2022-05-31 10:24:40 +00:00
parent 389b5131a1
commit 3c541d3892
43 changed files with 794 additions and 742 deletions

View file

@ -24,7 +24,10 @@ class DotReporter {
}
}
class RunnerMock {}
class RunnerMock {
shutdown = vi.fn()
initialise = vi.fn()
}
class FoobarServiceMock {
beforeSuite () {}
afterCommand () {}
@ -66,7 +69,7 @@ const pluginMocks = {
}
export const initialisePlugin = vi.fn().mockImplementation(
(name: keyof typeof frameworkMocks, type: keyof typeof pluginMocks) => (
async (name: keyof typeof frameworkMocks, type: keyof typeof pluginMocks) => (
{ default: (pluginMocks[type] as any)[name] }
)
)

View file

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

6
__mocks__/chokidar.ts Normal file
View file

@ -0,0 +1,6 @@
import { vi } from 'vitest'
const chokidar: any = {}
chokidar.watch = vi.fn().mockReturnValue(chokidar)
chokidar.on =vi.fn().mockReturnValue(chokidar)
export default chokidar

4
__mocks__/ejs.ts Normal file
View file

@ -0,0 +1,4 @@
import { vi } from 'vitest'
export default {
renderFile: vi.fn().mockImplementation((...args: any[]) => args.pop()())
}

View file

@ -1,5 +1,6 @@
import { vi } from 'vitest'
export default {
prompt: jest.fn().mockReturnValue(Promise.resolve({
prompt: vi.fn().mockReturnValue(Promise.resolve({
runner: '@wdio/local-runner--$local',
framework: '@wdio/mocha-framework$--$mocha',
reporters: ['@wdio/spec-reporter$--$spec'],

5
__mocks__/log-update.ts Normal file
View file

@ -0,0 +1,5 @@
import { vi } from 'vitest'
const logUpdateMock: any = vi.fn()
logUpdateMock.clear = vi.fn()
export default logUpdateMock

View file

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

14
__mocks__/yargs/yargs.ts Normal file
View file

@ -0,0 +1,14 @@
import { vi } from 'vitest'
const yargs: any = {}
yargs.commandDir = vi.fn(() => yargs)
yargs.example = vi.fn(() => yargs)
yargs.argv = { _: ['wdio.conf.js'] }
yargs.epilogue = vi.fn().mockReturnValue(yargs)
yargs.options = vi.fn(() => yargs)
yargs.updateStrings = vi.fn(() => yargs)
yargs.parse = vi.fn().mockReturnValue(yargs.argv)
yargs.env = vi.fn().mockReturnValue(yargs)
yargs.help = vi.fn().mockReturnValue(yargs)
export default vi.fn().mockReturnValue(yargs)
export { yargs }

View file

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

View file

@ -5,12 +5,11 @@
"author": "Christian Bromann <mail@bromann.dev>",
"homepage": "https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-cli",
"license": "MIT",
"main": "./build/index",
"bin": {
"wdio": "./bin/wdio.js"
},
"engines": {
"node": "^16.13 || >=18"
"node": "^16.13 || >=18"
},
"scripts": {
"copy": "copyfiles -u 1 -V \"src/templates/**/*\" ./build/"
@ -28,6 +27,20 @@
"bugs": {
"url": "https://github.com/webdriverio/webdriverio/issues"
},
"main": "./build/index.cjs.js",
"type": "module",
"module": "./build/index.js",
"exports": {
".": [
{
"import": "./build/index.js",
"require": "./build/index.cjs.js"
},
"./build/index.cjs.js"
]
},
"types": "./build/index.d.ts",
"typeScriptVersion": "3.8.3",
"dependencies": {
"@types/ejs": "^3.0.5",
"@types/fs-extra": "^9.0.4",
@ -61,5 +74,7 @@
"publishConfig": {
"access": "public"
},
"types": "./build/index.d.ts"
"devDependencies": {
"@types/yargs": "^17.0.10"
}
}

View file

@ -3,22 +3,21 @@ import util from 'node:util'
import fs from 'fs-extra'
import inquirer from 'inquirer'
import yarnInstall from 'yarn-install'
import type yargs from 'yargs'
import {
CONFIG_HELPER_INTRO, CLI_EPILOGUE, COMPILER_OPTIONS,
TS_COMPILER_INSTRUCTIONS, SUPPORTED_PACKAGES,
CONFIG_HELPER_SUCCESS_MESSAGE,
DEPENDENCIES_INSTALLATION_MESSAGE
} from '../constants'
DEPENDENCIES_INSTALLATION_MESSAGE,
pkg
} from '../constants.js'
import {
addServiceDeps, convertPackageHashToObject, renderConfigurationFile,
hasFile, generateTestFiles, getAnswers, getPathForFileGeneration,
hasPackage
} from '../utils'
import { ConfigCommandArguments, ParsedAnswers } from '../types'
import yargs from 'yargs'
const pkg = require('../../package.json')
} from '../utils.js'
import type { ConfigCommandArguments, ParsedAnswers } from '../types'
export const command = 'config'
export const desc = 'Initialize WebdriverIO and setup configuration in your current project.'
@ -45,6 +44,8 @@ export const builder = (yargs: yargs.Argv) => {
}
const runConfig = async function (useYarn: boolean, yes: boolean, exit = false) {
console.info('1')
console.log(CONFIG_HELPER_INTRO)
const answers = await getAnswers(yes)
const frameworkPackage = convertPackageHashToObject(answers.framework)
@ -66,6 +67,7 @@ const runConfig = async function (useYarn: boolean, yes: boolean, exit = false)
*/
const parsedPaths = getPathForFileGeneration(answers)
console.info('2')
const parsedAnswers: ParsedAnswers = {
...answers,

View file

@ -2,17 +2,17 @@
import path from 'node:path'
import fs from 'fs-extra'
import yarnInstall from 'yarn-install'
import type yargs from 'yargs'
import {
replaceConfig,
findInConfig,
addServiceDeps,
convertPackageHashToObject
} from '../utils'
import { missingConfigurationPrompt } from './config'
import { InstallCommandArguments, SupportedPackage } from '../types'
import { SUPPORTED_PACKAGES, CLI_EPILOGUE } from '../constants'
import yargs from 'yargs'
} from '../utils.js'
import { missingConfigurationPrompt } from './config.js'
import { SUPPORTED_PACKAGES, CLI_EPILOGUE } from '../constants.js'
import type { InstallCommandArguments, SupportedPackage } from '../types'
const supportedInstallations = {
plugin: SUPPORTED_PACKAGES.plugin.map(({ value }) => convertPackageHashToObject(value)),

View file

@ -1,10 +1,11 @@
import yargs from 'yargs'
import pickBy from 'lodash.pickby'
import { remote } from 'webdriverio'
import { cmdArgs as runCmdArgs } from './run'
import { getCapabilities } from '../utils'
import { ReplCommandArguments } from '../types'
import { CLI_EPILOGUE } from '../constants'
import yargs from 'yargs'
import { cmdArgs as runCmdArgs } from './run.js'
import { getCapabilities } from '../utils.js'
import { CLI_EPILOGUE } from '../constants.js'
import type { ReplCommandArguments } from '../types'
const IGNORED_ARGS = [
'bail', 'framework', 'reporters', 'suite', 'spec', 'exclude',

View file

@ -1,14 +1,13 @@
import path from 'node:path'
import fs from 'fs-extra'
import { missingConfigurationPrompt } from './config'
import { RunCommandArguments } from '../types'
import Launcher from '../launcher'
import Watcher from '../watcher'
import { CLI_EPILOGUE } from '../constants'
import yargs from 'yargs'
import Launcher from '../launcher.js'
import Watcher from '../watcher.js'
import { missingConfigurationPrompt } from './config.js'
import { CLI_EPILOGUE } from '../constants.js'
import type { RunCommandArguments } from '../types'
export const command = 'run <configPath>'
export const desc = 'Run your WDIO configuration file to initialize your tests. (default)'
@ -129,14 +128,14 @@ export function launch (wdioConfPath: string, params: Partial<RunCommandArgument
return launcher.run()
.then((...args) => {
/* istanbul ignore if */
if (!process.env.JEST_WORKER_ID) {
if (!process.env.VITEST_WORKER_ID) {
process.exit(...args)
}
})
.catch(err => {
console.error(err)
/* istanbul ignore if */
if (!process.env.JEST_WORKER_ID) {
if (!process.env.VITEST_WORKER_ID) {
process.exit(1)
}
})

View file

@ -1,7 +1,10 @@
import { validateServiceAnswers, hasFile, getDefaultFiles } from './utils'
import { Questionnair } from './types'
import { createRequire } from 'node:module'
const pkg = require('../package.json')
import { validateServiceAnswers, hasFile, getDefaultFiles } from './utils.js'
import type { Questionnair } from './types'
const require = createRequire(import.meta.url)
export const pkg = require('../package.json')
export const CLI_EPILOGUE = `Documentation: https://webdriver.io\n@wdio/cli (v${pkg.version})`

View file

@ -4,10 +4,10 @@ import path from 'node:path'
import yargs from 'yargs/yargs'
import { hideBin } from 'yargs/helpers'
import Launcher from './launcher'
import { handler, cmdArgs } from './commands/run'
import { CLI_EPILOGUE } from './constants'
import { RunCommandArguments } from './types'
import Launcher from './launcher.js'
import { handler, cmdArgs } from './commands/run.js'
import { CLI_EPILOGUE } from './constants.js'
import type { RunCommandArguments } from './types'
const DEFAULT_CONFIG_FILENAME = 'wdio.conf.js'
const DESCRIPTION = [
@ -82,4 +82,4 @@ export const run = async () => {
}
export default Launcher
export * from './types'
export * from './types.js'

View file

@ -1,9 +1,9 @@
import chalk from 'chalk'
import { EventEmitter } from 'node:events'
import chalk from 'chalk'
import logger from '@wdio/logger'
import type { Options, Capabilities, Workers } from '@wdio/types'
import { getRunnerName, HookError } from './utils'
import { getRunnerName, HookError } from './utils.js'
const log = logger('@wdio/cli')

View file

@ -7,9 +7,9 @@ import { ConfigParser } from '@wdio/config'
import { initialisePlugin, initialiseLauncherService, sleep } from '@wdio/utils'
import type { Options, Capabilities, Services } from '@wdio/types'
import CLInterface from './interface'
import { RunCommandArguments } from './types'
import { runLauncherHook, runOnCompleteHook, runServiceHook, HookError } from './utils'
import CLInterface from './interface.js'
import { runLauncherHook, runOnCompleteHook, runServiceHook, HookError } from './utils.js'
import type { RunCommandArguments } from './types'
const log = logger('@wdio/cli:launcher')

View file

@ -1,5 +1,5 @@
import { Options, Reporters } from '@wdio/types'
import { BACKEND_CHOICES, REGION_OPTION, COMPILER_OPTION_ANSWERS } from './constants'
import type { Options, Reporters } from '@wdio/types'
import type { BACKEND_CHOICES, REGION_OPTION, COMPILER_OPTION_ANSWERS } from './constants'
type ValueOf<T> = T[keyof T]

View file

@ -1,3 +1,9 @@
import { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { createRequire } from 'node:module'
import { execSync } from 'node:child_process'
import { promisify } from 'node:util'
import fs from 'fs-extra'
import ejs from 'ejs'
import path from 'node:path'
@ -6,16 +12,16 @@ import pickBy from 'lodash.pickby'
import logger from '@wdio/logger'
import readDir from 'recursive-readdir'
import { SevereServiceError } from 'webdriverio'
import { execSync } from 'node:child_process'
import { promisify } from 'node:util'
import { ConfigParser } from '@wdio/config'
import { CAPABILITY_KEYS } from '@wdio/protocols'
import type { Options, Capabilities, Services } from '@wdio/types'
import { ReplCommandArguments, Questionnair, SupportedPackage, OnCompleteResult, ParsedAnswers } from './types'
import { EXCLUSIVE_SERVICES, ANDROID_CONFIG, IOS_CONFIG, QUESTIONNAIRE } from './constants'
import { EXCLUSIVE_SERVICES, ANDROID_CONFIG, IOS_CONFIG, QUESTIONNAIRE } from './constants.js'
import type { ReplCommandArguments, Questionnair, SupportedPackage, OnCompleteResult, ParsedAnswers } from './types'
const require = createRequire(import.meta.url)
const log = logger('@wdio/cli:utils')
const __dirname = dirname(fileURLToPath(import.meta.url))
const TEMPLATE_ROOT_DIR = path.join(__dirname, 'templates', 'exampleFiles')
const renderFile = promisify(ejs.renderFile) as (path: string, data: Record<string, any>) => Promise<string>

View file

@ -3,10 +3,10 @@ import logger from '@wdio/logger'
import pickBy from 'lodash.pickby'
import flattenDeep from 'lodash.flattendeep'
import union from 'lodash.union'
import Launcher from './launcher'
import type { Capabilities, Workers } from '@wdio/types'
import { RunCommandArguments, ValueKeyIteratee } from './types.js'
import Launcher from './launcher.js'
import type { RunCommandArguments, ValueKeyIteratee } from './types'
const log = logger('@wdio/cli:watch')

View file

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

View file

@ -1 +0,0 @@
export default jest.fn()

View file

@ -1,5 +0,0 @@
const chokidar = {}
chokidar.watch = jest.fn().mockReturnValue(chokidar)
chokidar.on =jest.fn().mockReturnValue(chokidar)
export default chokidar

View file

@ -1,3 +0,0 @@
export default {
renderFile: jest.fn().mockImplementation((...args) => args.pop()())
}

View file

@ -1,4 +0,0 @@
const logUpdateMock = jest.fn()
logUpdateMock.clear = jest.fn()
export default logUpdateMock

View file

@ -1 +0,0 @@
export default jest.fn()

View file

@ -1,13 +0,0 @@
const yargs: any = {}
yargs.commandDir = jest.fn(() => yargs)
yargs.example = jest.fn(() => yargs)
yargs.argv = { _: ['wdio.conf.js'] }
yargs.epilogue = jest.fn().mockReturnValue(yargs)
yargs.options = jest.fn(() => yargs)
yargs.updateStrings = jest.fn(() => yargs)
yargs.parse = jest.fn().mockReturnValue(yargs.argv)
yargs.env = jest.fn().mockReturnValue(yargs)
yargs.help = jest.fn().mockReturnValue(yargs)
export default jest.fn().mockReturnValue(yargs)
export { yargs }

View file

@ -1 +0,0 @@
export default jest.fn().mockReturnValue({ status: 0 })

View file

@ -1,22 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Vitest Snapshot v1
exports[`getCapabilities should get capability from wdio.conf.js 1`] = `
Object {
"capabilities": Object {
"acceptInsecureCerts": true,
"browserName": "chrome",
"goog:chromeOptions": Object {
"args": Array [
"window-size=8000,1200",
],
},
},
}
`;
exports[`getCapabilities should return driver with capabilities for android 1`] = `
Object {
"capabilities": Object {
exports[`getCapabilities > should return driver with capabilities for android 1`] = `
{
"capabilities": {
"app": "foo.apk",
"automationName": "UiAutomator2",
"deviceName": "Test",
@ -27,9 +13,9 @@ Object {
}
`;
exports[`getCapabilities should return driver with capabilities for android 2`] = `
Object {
"capabilities": Object {
exports[`getCapabilities > should return driver with capabilities for android 2`] = `
{
"capabilities": {
"automationName": "UiAutomator2",
"browserName": "Chrome",
"deviceName": "Test",
@ -40,17 +26,17 @@ Object {
}
`;
exports[`getCapabilities should return driver with capabilities for desktop 1`] = `
Object {
"capabilities": Object {
exports[`getCapabilities > should return driver with capabilities for desktop 1`] = `
{
"capabilities": {
"browserName": "chrome",
},
}
`;
exports[`getCapabilities should return driver with capabilities for ios 1`] = `
Object {
"capabilities": Object {
exports[`getCapabilities > should return driver with capabilities for ios 1`] = `
{
"capabilities": {
"app": "foo.app",
"automationName": "XCUITest",
"deviceName": "fooName",
@ -61,9 +47,9 @@ Object {
}
`;
exports[`getCapabilities should return driver with capabilities for ios 2`] = `
Object {
"capabilities": Object {
exports[`getCapabilities > should return driver with capabilities for ios 2`] = `
{
"capabilities": {
"automationName": "XCUITest",
"browserName": "Safari",
"deviceName": "iPhone Simulator",
@ -74,10 +60,10 @@ Object {
}
`;
exports[`getCapabilities should through capability not found 1`] = `"No capability found in given config file with the provided capability indexed/named property: 5. Please check the capability in your wdio config file."`;
exports[`getCapabilities > should through capability not found 1`] = `"No capability found in given config file with the provided capability indexed/named property: 5. Please check the capability in your wdio config file."`;
exports[`getCapabilities should throw capability not provided 1`] = `"Please provide index/named property of capability to use from the capabilities array/object in wdio config file"`;
exports[`getCapabilities > should throw capability not provided 1`] = `"Please provide index/named property of capability to use from the capabilities array/object in wdio config file"`;
exports[`getCapabilities should throw config not found error 1`] = `"Config File not found: ./test.js"`;
exports[`getCapabilities > should throw config not found error 1`] = `"Config File not found: ./test.js"`;
exports[`getCapabilities should throw config not found error 2`] = `"Could not parse ./test.js, failed with error : ups"`;
exports[`getCapabilities > should throw config not found error 2`] = `"Could not parse ./test.js, failed with error : ups"`;

View file

@ -1,150 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Vitest Snapshot v1
exports[`install compliant NPM tag packages it should install tagged version if cli is tagged with beta 1`] = `
Array [
Array [
exports[`install compliant NPM tag packages > it should install tagged version if cli is tagged with beta 1`] = `
[
[
"
=========================
WDIO Configuration Helper
=========================
",
],
Array [
"
Installing wdio packages:
-",
"@wdio/local-runner@beta
- @wdio/mocha-framework@beta
- @wdio/crossbrowsertesting-service@beta
- wdio-lambdatest-service
- ts-node
- typescript",
],
Array [
"
Packages installed successfully, creating configuration file...",
],
Array [
"To have TypeScript support please add the following packages to your \\"types\\" list:
{
\\"compilerOptions\\": {
\\"types\\": [\\"node\\", \\"webdriverio/async\\", \\"@wdio/mocha-framework\\", \\"expect-webdriverio\\", \\"@wdio/crossbrowsertesting-service\\"]
}
}
For for information on TypeScript integration check out: https://webdriver.io/docs/typescript
",
],
Array [
"
Configuration file was created successfully!
To run your tests, execute:
$ npx wdio run test/wdio.conf.ts
",
],
]
`;
exports[`install compliant NPM tag packages it should install tagged version if cli is tagged with latest 1`] = `
Array [
Array [
"
=========================
WDIO Configuration Helper
=========================
",
],
Array [
"
Installing wdio packages:
-",
"@wdio/local-runner@latest
- @wdio/mocha-framework@latest
- @wdio/crossbrowsertesting-service@latest
- wdio-lambdatest-service
- ts-node
- typescript",
],
Array [
"
Packages installed successfully, creating configuration file...",
],
Array [
"To have TypeScript support please add the following packages to your \\"types\\" list:
{
\\"compilerOptions\\": {
\\"types\\": [\\"node\\", \\"webdriverio/async\\", \\"@wdio/mocha-framework\\", \\"expect-webdriverio\\", \\"@wdio/crossbrowsertesting-service\\"]
}
}
For for information on TypeScript integration check out: https://webdriver.io/docs/typescript
",
],
Array [
"
Configuration file was created successfully!
To run your tests, execute:
$ npx wdio run test/wdio.conf.ts
",
],
]
`;
exports[`install compliant NPM tag packages it should install tagged version if cli is tagged with next 1`] = `
Array [
Array [
"
=========================
WDIO Configuration Helper
=========================
",
],
Array [
"
Installing wdio packages:
-",
"@wdio/local-runner@next
- @wdio/mocha-framework@next
- @wdio/crossbrowsertesting-service@next
- wdio-lambdatest-service
- ts-node
- typescript",
],
Array [
"
Packages installed successfully, creating configuration file...",
],
Array [
"To have TypeScript support please add the following packages to your \\"types\\" list:
{
\\"compilerOptions\\": {
\\"types\\": [\\"node\\", \\"webdriverio/async\\", \\"@wdio/mocha-framework\\", \\"expect-webdriverio\\", \\"@wdio/crossbrowsertesting-service\\"]
}
}
For for information on TypeScript integration check out: https://webdriver.io/docs/typescript
",
],
Array [
"
Configuration file was created successfully!
To run your tests, execute:
$ npx wdio run test/wdio.conf.ts
",
],
]
`;
exports[`install compliant NPM tag packages it should not install tagged version if cli is tagged with a specific version 1`] = `
Array [
Array [
"
=========================
WDIO Configuration Helper
=========================
",
],
Array [
[
"
Installing wdio packages:
-",
@ -155,11 +20,11 @@ Installing wdio packages:
- ts-node
- typescript",
],
Array [
[
"
Packages installed successfully, creating configuration file...",
],
Array [
[
"To have TypeScript support please add the following packages to your \\"types\\" list:
{
\\"compilerOptions\\": {
@ -170,7 +35,142 @@ Packages installed successfully, creating configuration file...",
For for information on TypeScript integration check out: https://webdriver.io/docs/typescript
",
],
Array [
[
"
Configuration file was created successfully!
To run your tests, execute:
$ npx wdio run test/wdio.conf.ts
",
],
]
`;
exports[`install compliant NPM tag packages > it should install tagged version if cli is tagged with latest 1`] = `
[
[
"
=========================
WDIO Configuration Helper
=========================
",
],
[
"
Installing wdio packages:
-",
"@wdio/local-runner
- @wdio/mocha-framework
- @wdio/crossbrowsertesting-service
- wdio-lambdatest-service
- ts-node
- typescript",
],
[
"
Packages installed successfully, creating configuration file...",
],
[
"To have TypeScript support please add the following packages to your \\"types\\" list:
{
\\"compilerOptions\\": {
\\"types\\": [\\"node\\", \\"webdriverio/async\\", \\"@wdio/mocha-framework\\", \\"expect-webdriverio\\", \\"@wdio/crossbrowsertesting-service\\"]
}
}
For for information on TypeScript integration check out: https://webdriver.io/docs/typescript
",
],
[
"
Configuration file was created successfully!
To run your tests, execute:
$ npx wdio run test/wdio.conf.ts
",
],
]
`;
exports[`install compliant NPM tag packages > it should install tagged version if cli is tagged with next 1`] = `
[
[
"
=========================
WDIO Configuration Helper
=========================
",
],
[
"
Installing wdio packages:
-",
"@wdio/local-runner
- @wdio/mocha-framework
- @wdio/crossbrowsertesting-service
- wdio-lambdatest-service
- ts-node
- typescript",
],
[
"
Packages installed successfully, creating configuration file...",
],
[
"To have TypeScript support please add the following packages to your \\"types\\" list:
{
\\"compilerOptions\\": {
\\"types\\": [\\"node\\", \\"webdriverio/async\\", \\"@wdio/mocha-framework\\", \\"expect-webdriverio\\", \\"@wdio/crossbrowsertesting-service\\"]
}
}
For for information on TypeScript integration check out: https://webdriver.io/docs/typescript
",
],
[
"
Configuration file was created successfully!
To run your tests, execute:
$ npx wdio run test/wdio.conf.ts
",
],
]
`;
exports[`install compliant NPM tag packages > it should not install tagged version if cli is tagged with a specific version 1`] = `
[
[
"
=========================
WDIO Configuration Helper
=========================
",
],
[
"
Installing wdio packages:
-",
"@wdio/local-runner
- @wdio/mocha-framework
- @wdio/crossbrowsertesting-service
- wdio-lambdatest-service
- ts-node
- typescript",
],
[
"
Packages installed successfully, creating configuration file...",
],
[
"To have TypeScript support please add the following packages to your \\"types\\" list:
{
\\"compilerOptions\\": {
\\"types\\": [\\"node\\", \\"webdriverio/async\\", \\"@wdio/mocha-framework\\", \\"expect-webdriverio\\", \\"@wdio/crossbrowsertesting-service\\"]
}
}
For for information on TypeScript integration check out: https://webdriver.io/docs/typescript
",
],
[
"
Configuration file was created successfully!
To run your tests, execute:
@ -181,15 +181,15 @@ $ npx wdio run test/wdio.conf.ts
`;
exports[`prints TypeScript setup message 1`] = `
Array [
Array [
[
[
"
=========================
WDIO Configuration Helper
=========================
",
],
Array [
[
"
Installing wdio packages:
-",
@ -200,11 +200,11 @@ Installing wdio packages:
- ts-node
- typescript",
],
Array [
[
"
Packages installed successfully, creating configuration file...",
],
Array [
[
"To have TypeScript support please add the following packages to your \\"types\\" list:
{
\\"compilerOptions\\": {
@ -215,7 +215,7 @@ Packages installed successfully, creating configuration file...",
For for information on TypeScript integration check out: https://webdriver.io/docs/typescript
",
],
Array [
[
"
Configuration file was created successfully!
To run your tests, execute:
@ -226,15 +226,15 @@ $ npx wdio run test/wdio.conf.ts
`;
exports[`prints TypeScript setup message with ts-node installed 1`] = `
Array [
Array [
[
[
"
=========================
WDIO Configuration Helper
=========================
",
],
Array [
[
"
Installing wdio packages:
-",
@ -245,11 +245,11 @@ Installing wdio packages:
- ts-node
- typescript",
],
Array [
[
"
Packages installed successfully, creating configuration file...",
],
Array [
[
"To have TypeScript support please add the following packages to your \\"types\\" list:
{
\\"compilerOptions\\": {
@ -260,7 +260,7 @@ Packages installed successfully, creating configuration file...",
For for information on TypeScript integration check out: https://webdriver.io/docs/typescript
",
],
Array [
[
"
Configuration file was created successfully!
To run your tests, execute:
@ -271,15 +271,15 @@ $ npx wdio run test/wdio.conf.ts
`;
exports[`should create config file 1`] = `
Object {
"installedPackages": Array [
{
"installedPackages": [
"@wdio/local-runner",
"@wdio/mocha-framework",
"@wdio/spec-reporter",
"wdio-wait-for",
"@wdio/sauce-service",
],
"parsedAnswers": Object {
"parsedAnswers": {
"_async": "async ",
"_await": "await ",
"framework": "mocha",
@ -287,22 +287,22 @@ Object {
"isUsingBabel": false,
"isUsingTypeScript": false,
"npmInstall": true,
"packagesToInstall": Array [
"packagesToInstall": [
"@wdio/local-runner",
"@wdio/mocha-framework",
"@wdio/spec-reporter",
"wdio-wait-for",
"@wdio/sauce-service",
],
"plugins": Array [
"plugins": [
"wait-for",
],
"relativePath": "",
"reporters": Array [
"reporters": [
"spec",
],
"runner": "local",
"services": Array [
"services": [
"sauce",
],
"tsConfigFilePath": "test/tsconfig.json",
@ -312,15 +312,15 @@ Object {
`;
exports[`should not install @babel/register if existing 1`] = `
Array [
Array [
[
[
"
=========================
WDIO Configuration Helper
=========================
",
],
Array [
[
"
Installing wdio packages:
-",
@ -332,11 +332,11 @@ Installing wdio packages:
- @babel/core
- @babel/preset-env",
],
Array [
[
"
Packages installed successfully, creating configuration file...",
],
Array [
[
"
Configuration file was created successfully!
To run your tests, execute:
@ -346,57 +346,18 @@ $ npx wdio run wdio.conf.js
]
`;
exports[`should not install npm packages when npmInstall is false 1`] = `
[MockFunction] {
"calls": Array [
Array [
"
=========================
WDIO Configuration Helper
=========================
",
],
Array [
"
To install dependencies, execute:
npm i --save-dev @wdio/local-runner @wdio/mocha-framework @wdio/spec-reporter wdio-wait-for @wdio/sauce-service
",
],
Array [
"
Configuration file was created successfully!
To run your tests, execute:
$ npx wdio run wdio.conf.js
",
],
],
"results": Array [
Object {
"type": "return",
"value": undefined,
},
Object {
"type": "return",
"value": undefined,
},
Object {
"type": "return",
"value": undefined,
},
],
}
`;
exports[`should not install npm packages when npmInstall is false 1`] = `[Function]`;
exports[`should setup Babel if not existing 1`] = `
Array [
Array [
[
[
"
=========================
WDIO Configuration Helper
=========================
",
],
Array [
[
"
Installing wdio packages:
-",
@ -408,11 +369,11 @@ Installing wdio packages:
- @babel/core
- @babel/preset-env",
],
Array [
[
"
Packages installed successfully, creating configuration file...",
],
Array [
[
"
Configuration file was created successfully!
To run your tests, execute:

View file

@ -1,3 +1,4 @@
import { vi, describe, it, test, expect, afterEach, beforeEach } from 'vitest'
import path from 'node:path'
// @ts-expect-error mock
import { yargs } from 'yargs/yargs'
@ -7,34 +8,54 @@ import inquirer from 'inquirer'
import pkg from '../../package.json'
import { handler, builder, missingConfigurationPrompt } from '../../src/commands/config'
import { addServiceDeps, convertPackageHashToObject, renderConfigurationFile, generateTestFiles, getPathForFileGeneration } from '../../src/utils'
import {
getAnswers, addServiceDeps, convertPackageHashToObject, renderConfigurationFile,
generateTestFiles, getPathForFileGeneration
} from '../../src/utils'
jest.mock('../../src/utils', () => ({
addServiceDeps: jest.fn(),
convertPackageHashToObject: jest.fn().mockImplementation(jest.requireActual('../../src/utils').convertPackageHashToObject),
renderConfigurationFile: jest.fn(),
hasFile: jest.fn().mockReturnValue(false),
hasPackage: jest.fn().mockReturnValue(false),
getAnswers: jest.fn().mockImplementation(jest.requireActual('../../src/utils').getAnswers),
generateTestFiles: jest.fn(),
getPathForFileGeneration: jest.fn().mockImplementation(jest.requireActual('../../src/utils').getPathForFileGeneration),
vi.mock('yargs/yargs')
vi.mock('yarn-install')
vi.mock('inquirer')
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))
const utils: any = await vi.importActual('../../src/utils')
vi.mocked(convertPackageHashToObject).mockImplementation(utils.convertPackageHashToObject)
vi.mocked(getPathForFileGeneration).mockImplementation(utils.getPathForFileGeneration)
vi.mocked(getAnswers).mockImplementation(utils.getAnswers)
vi.mock('../../src/utils', async () => {
return {
addServiceDeps: vi.fn(),
convertPackageHashToObject: vi.fn(),
renderConfigurationFile: vi.fn(),
hasFile: vi.fn().mockReturnValue(false),
hasPackage: vi.fn().mockReturnValue(false),
getAnswers: vi.fn(),
generateTestFiles: vi.fn(),
getPathForFileGeneration: vi.fn()
}
})
vi.mock('fs', () => ({
default: {
writeFile: vi.fn().mockResolvedValue(''),
existsSync: vi.fn()
}
}))
jest.mock('fs')
jest.mock('../../package.json', () => {
const pkg = jest.requireActual('../../package.json')
vi.mock('../../package.json', async () => {
const pkg = await vi.importActual('../../package.json') as any
pkg.setFetchSpec = (fetchSpec: string) => {
pkg._requested = { fetchSpec }
}
pkg.clearFetchSpec = () => {
delete pkg._requested
}
return pkg
return { default: pkg }
})
const errorLogSpy = jest.spyOn(console, 'error')
const consoleLogSpy = jest.spyOn(console, 'log')
const errorLogSpy = vi.spyOn(console, 'error')
const consoleLogSpy = vi.spyOn(console, 'log')
const args = {
framework: '@wdio/mocha-framework$--$mocha',
@ -52,8 +73,8 @@ const args = {
}
beforeEach(() => {
(yarnInstall as any as jest.Mock).mockClear()
;(yarnInstall as any as jest.Mock).mockReturnValue({ status: 0 })
vi.mocked(yarnInstall).mockClear()
vi.mocked(yarnInstall).mockReturnValue({ status: 0 } as any)
errorLogSpy.mockClear()
consoleLogSpy.mockClear()
@ -65,16 +86,14 @@ afterEach(() => {
})
test('should create config file', async () => {
(inquirer.prompt as any as jest.Mock).mockReturnValue(Promise.resolve(args))
// @ts-expect-error
fs.promises = { writeFile: jest.fn()
.mockReturnValue(Promise.resolve('')) }
vi.mocked(inquirer.prompt).mockResolvedValue(args)
const result = await handler({} as any)
// @ts-expect-error
delete result.parsedAnswers.destPageObjectRootPath
// @ts-expect-error
delete result.parsedAnswers.destSpecRootPath
const fileName = `${path.basename(path.dirname(result.parsedAnswers.tsConfigFilePath))}/${path.basename(result.parsedAnswers.tsConfigFilePath)}`
result.parsedAnswers.tsConfigFilePath = fileName
const fileName = `${path.basename(path.dirname(result.parsedAnswers!.tsConfigFilePath))}/${path.basename(result.parsedAnswers!.tsConfigFilePath)}`
result.parsedAnswers!.tsConfigFilePath = fileName
expect(result).toMatchSnapshot()
expect(addServiceDeps).toBeCalledTimes(1)
expect(convertPackageHashToObject).toBeCalledTimes(5)
@ -97,7 +116,7 @@ test('it should properly build command', () => {
})
test('should throw error if creating config file fails', async () => {
(renderConfigurationFile as jest.Mock).mockReturnValueOnce(Promise.reject(new Error('boom!')))
vi.mocked(renderConfigurationFile).mockReturnValueOnce(Promise.reject(new Error('boom!')))
const err = await handler({} as any).catch((err) => err)
expect(err.message).toContain('Error: boom!')
})
@ -129,10 +148,10 @@ describe('install compliant NPM tag packages', () => {
}
test('it should install tagged version if cli is tagged with beta', async () => {
setFetchSpec('beta');
(inquirer.prompt as any as jest.Mock).mockReturnValue(Promise.resolve(args))
setFetchSpec('beta')
vi.mocked(inquirer.prompt).mockResolvedValue(args)
// @ts-expect-error
fs.promises = { writeFile: jest.fn()
fs.promises = { writeFile: vi.fn()
.mockReturnValue(Promise.resolve('')) }
await handler({} as any)
@ -140,21 +159,21 @@ describe('install compliant NPM tag packages', () => {
})
test('it should install tagged version if cli is tagged with next', async () => {
setFetchSpec('next');
(inquirer.prompt as any as jest.Mock).mockReturnValue(Promise.resolve(args))
// @ts-expect-error
fs.promises = { writeFile: jest.fn()
.mockReturnValue(Promise.resolve('')) }
setFetchSpec('next')
vi.mocked(inquirer.prompt).mockResolvedValue(args)
fs.promises = {
writeFile: vi.fn().mockReturnValue(Promise.resolve(''))
} as any
await handler({} as any)
expect(consoleLogSpy.mock.calls).toMatchSnapshot()
})
test('it should install tagged version if cli is tagged with latest', async () => {
setFetchSpec('latest');
(inquirer.prompt as any as jest.Mock).mockReturnValue(Promise.resolve(args))
setFetchSpec('latest')
vi.mocked(inquirer.prompt).mockResolvedValue(args)
// @ts-expect-error
fs.promises = { writeFile: jest.fn()
fs.promises = { writeFile: vi.fn()
.mockReturnValue(Promise.resolve('')) }
await handler({} as any)
@ -162,10 +181,10 @@ describe('install compliant NPM tag packages', () => {
})
test('it should not install tagged version if cli is tagged with a specific version', async () => {
setFetchSpec('7.0.8');
(inquirer.prompt as any as jest.Mock).mockReturnValue(Promise.resolve(args))
setFetchSpec('7.0.8')
vi.mocked(inquirer.prompt).mockResolvedValue(args)
// @ts-expect-error
fs.promises = { writeFile: jest.fn()
fs.promises = { writeFile: vi.fn()
.mockReturnValue(Promise.resolve('')) }
await handler({} as any)
@ -179,7 +198,7 @@ describe('install compliant NPM tag packages', () => {
})
test('prints TypeScript setup message', async () => {
(inquirer.prompt as any as jest.Mock).mockReturnValue(Promise.resolve({
vi.mocked(inquirer.prompt).mockResolvedValue({
framework: '@wdio/mocha-framework$--$mocha',
reporters: [],
plugins: [],
@ -190,14 +209,14 @@ test('prints TypeScript setup message', async () => {
generateTestFiles: false,
isUsingCompiler: 'TypeScript (https://www.typescriptlang.org/)',
npmInstall: true
}))
})
await handler({} as any)
expect(consoleLogSpy.mock.calls).toMatchSnapshot()
})
test('prints TypeScript setup message with ts-node installed', async () => {
process.env.WDIO_TEST_THROW_RESOLVE = '1'
;(inquirer.prompt as any as jest.Mock).mockReturnValue(Promise.resolve({
vi.mocked(inquirer.prompt).mockResolvedValue({
framework: '@wdio/mocha-framework$--$mocha',
reporters: [],
plugins: [],
@ -208,7 +227,7 @@ test('prints TypeScript setup message with ts-node installed', async () => {
generateTestFiles: false,
isUsingCompiler: 'TypeScript (https://www.typescriptlang.org/)',
npmInstall: true
}))
})
const config = {
compilerOptions: {
@ -228,7 +247,7 @@ test('prints TypeScript setup message with ts-node installed', async () => {
JSON.stringify(config, null, 4))
// @ts-expect-error
fs.promises = { writeFile: jest.fn()
fs.promises = { writeFile: vi.fn()
.mockReturnValue(Promise.resolve('')) }
await handler({} as any)
expect(consoleLogSpy.mock.calls).toMatchSnapshot()
@ -236,7 +255,7 @@ test('prints TypeScript setup message with ts-node installed', async () => {
test('should setup Babel if not existing', async () => {
process.env.WDIO_TEST_THROW_RESOLVE = '1'
;(inquirer.prompt as any as jest.Mock).mockReturnValue(Promise.resolve({
vi.mocked(inquirer.prompt).mockResolvedValue({
framework: '@wdio/mocha-framework$--$mocha',
reporters: [],
plugins: [],
@ -247,9 +266,9 @@ test('should setup Babel if not existing', async () => {
generateTestFiles: false,
isUsingCompiler: 'Babel (https://babeljs.io/)',
npmInstall: true
}))
})
// @ts-expect-error
fs.promises = { writeFile: jest.fn()
fs.promises = { writeFile: vi.fn()
.mockReturnValue(Promise.resolve('')) }
await handler({} as any)
expect(consoleLogSpy.mock.calls).toMatchSnapshot()
@ -257,7 +276,7 @@ test('should setup Babel if not existing', async () => {
test('should not install @babel/register if existing', async () => {
delete process.env.WDIO_TEST_THROW_RESOLVE
;(inquirer.prompt as any as jest.Mock).mockReturnValue(Promise.resolve({
vi.mocked(inquirer.prompt).mockResolvedValue({
framework: '@wdio/mocha-framework$--$mocha',
reporters: [],
plugins: [],
@ -268,14 +287,14 @@ test('should not install @babel/register if existing', async () => {
generateTestFiles: false,
isUsingCompiler: 'Babel (https://babeljs.io/)',
npmInstall: true
}))
})
await handler({} as any)
expect(consoleLogSpy.mock.calls).toMatchSnapshot()
})
test('should not install npm packages when npmInstall is false', async () => {
const ans = { ...args, npmInstall: false };
(inquirer.prompt as any as jest.Mock).mockReturnValue(Promise.resolve(ans))
const ans = { ...args, npmInstall: false }
vi.mocked(inquirer.prompt).mockResolvedValue(ans)
await handler({} as any)
expect(consoleLogSpy).toMatchSnapshot()
expect(yarnInstall).not.toHaveBeenCalled()
@ -283,25 +302,25 @@ test('should not install npm packages when npmInstall is false', async () => {
describe('missingConfigurationPromp', () => {
it('should prompt user', async () => {
(inquirer.prompt as any as jest.Mock).mockImplementation(() => ({ config: true }))
await missingConfigurationPrompt('run', 'foobar', false, jest.fn())
expect((inquirer.prompt as any as jest.Mock)).toHaveBeenCalled()
vi.mocked(inquirer.prompt).mockImplementation(() => ({ config: true }) as any)
await missingConfigurationPrompt('run', 'foobar', false, vi.fn())
expect(vi.mocked(inquirer.prompt)).toHaveBeenCalled()
})
it('should call function to initalize configuration helper', async () => {
const runConfig = jest.fn()
const runConfig = vi.fn()
await missingConfigurationPrompt('test', 'foobar', false, runConfig)
expect(runConfig).toHaveBeenCalledWith(false, false, true)
})
it('should pass "yarn" flag to runConfig', async () => {
const runConfig = jest.fn()
const runConfig = vi.fn()
await missingConfigurationPrompt('test', 'test message', true, runConfig)
expect(runConfig).toHaveBeenCalledWith(true, false, true)
})
it('should throw if error occurs', async () => {
const runConfig = jest.fn().mockImplementation(Promise.reject)
const runConfig = vi.fn().mockImplementation(Promise.reject)
try {
await missingConfigurationPrompt('test', 'foobar', false, runConfig)
@ -311,6 +330,6 @@ describe('missingConfigurationPromp', () => {
})
afterEach(() => {
(inquirer.prompt as any as jest.Mock).mockClear()
vi.mocked(inquirer.prompt).mockClear()
})
})

View file

@ -1,3 +1,5 @@
import path from 'node:path'
import { vi, describe, it, expect, afterEach, beforeEach } from 'vitest'
// @ts-expect-error mock
import { yargs } from 'yargs/yargs'
import fs from 'fs-extra'
@ -6,20 +8,20 @@ import * as configCmd from '../../src/commands/config'
import * as utils from '../../src/utils'
import yarnInstall from 'yarn-install'
jest.mock('yarn-install')
jest.mock('fs-extra')
vi.mock('yargs/yargs')
vi.mock('yarn-install')
vi.mock('fs-extra')
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))
let findInConfigMock: jest.SpyInstance
const findInConfigMock = vi.spyOn(utils, 'findInConfig')
describe('Command: install', () => {
beforeEach(() => {
jest.spyOn(console, 'log')
jest.spyOn(process, 'exit').mockImplementation((code?: number): never => code as never)
jest.spyOn(configCmd, 'missingConfigurationPrompt').mockImplementation(() => Promise.resolve() as any)
jest.spyOn(utils, 'addServiceDeps')
jest.spyOn(utils, 'replaceConfig').mockReturnValueOnce({ foo: 123 } as any)
findInConfigMock = jest.spyOn(utils, 'findInConfig')
vi.spyOn(console, 'log')
vi.spyOn(process, 'exit').mockImplementation((code?: number): never => code as never)
vi.spyOn(configCmd, 'missingConfigurationPrompt').mockImplementation(() => Promise.resolve() as any)
vi.spyOn(utils, 'addServiceDeps')
vi.spyOn(utils, 'replaceConfig').mockReturnValueOnce({ foo: 123 } as any)
})
it('it should properly build command', () => {
@ -45,8 +47,8 @@ describe('Command: install', () => {
})
it('should prompt missing configuration', async () => {
jest.spyOn(configCmd, 'missingConfigurationPrompt').mockImplementation(() => Promise.reject())
;(fs.existsSync as jest.Mock).mockReturnValue(false)
vi.spyOn(configCmd, 'missingConfigurationPrompt').mockImplementation(() => Promise.reject())
vi.mocked(fs.existsSync).mockReturnValue(false)
await installCmd.handler({ type: 'service', name: 'chromedriver', config: './wdio.conf.js' } as any)
@ -56,7 +58,7 @@ You can create one by running 'wdio config'`, undefined)
it('should verify if configuration already has desired installation', async () => {
findInConfigMock.mockReturnValue(['chromedriver'])
;(fs.existsSync as jest.Mock).mockReturnValue(true)
vi.mocked(fs.existsSync).mockReturnValue(true)
await installCmd.handler({ type: 'service', name: 'chromedriver', config: './wdio.conf.js' } as any)
@ -65,9 +67,9 @@ You can create one by running 'wdio config'`, undefined)
it('should correctly install packages', async () => {
findInConfigMock.mockReturnValue([''])
;(fs.existsSync as jest.Mock).mockReturnValue(true)
;(fs.readFileSync as jest.Mock).mockReturnValue('module.config = {}')
;(yarnInstall as any as jest.Mock).mockImplementation(() => ({ status: 0 }))
vi.mocked(fs.existsSync).mockReturnValue(true)
vi.mocked(fs.readFileSync).mockReturnValue('module.config = {}')
vi.mocked(yarnInstall).mockImplementation(() => ({ status: 0 }) as any)
await installCmd.handler({ type: 'service', name: 'chromedriver', config: './wdio.conf.js' } as any)
@ -81,10 +83,10 @@ You can create one by running 'wdio config'`, undefined)
it('should fail if config could not be updated', async () => {
findInConfigMock.mockReturnValue([''])
;(fs.readFileSync as jest.Mock).mockReturnValue('module.config = {}')
;(yarnInstall as any as jest.Mock).mockImplementation(() => ({ status: 0 }))
;(utils.replaceConfig as jest.Mock).mockRestore()
jest.spyOn(utils, 'replaceConfig').mockReturnValue('')
vi.mocked(fs.readFileSync).mockReturnValue('module.config = {}')
vi.mocked(yarnInstall).mockImplementation(() => ({ status: 0 }) as any)
vi.mocked(utils.replaceConfig).mockRestore()
vi.spyOn(utils, 'replaceConfig').mockReturnValue('')
const err = await installCmd.handler({ type: 'service', name: 'chromedriver', config: './wdio.conf.js' } as any)
.catch((err: Error) => err) as Error
@ -94,9 +96,9 @@ You can create one by running 'wdio config'`, undefined)
it('allows for custom config location', async () => {
findInConfigMock.mockReturnValue([''])
;(fs.existsSync as jest.Mock).mockReturnValue(true)
;(fs.readFileSync as jest.Mock).mockReturnValue('module.config = {}')
;(yarnInstall as any as jest.Mock).mockImplementation(() => ({ status: 0 }))
vi.mocked(fs.existsSync).mockReturnValue(true)
vi.mocked(fs.readFileSync).mockReturnValue('module.config = {}')
vi.mocked(yarnInstall).mockImplementation(() => ({ status: 0 }) as any)
await installCmd.handler({ type: 'service', name: 'chromedriver', config: './path/to/wdio.conf.js' } as any)
@ -110,9 +112,9 @@ You can create one by running 'wdio config'`, undefined)
it('should exit if there is an error while installing', async () => {
findInConfigMock.mockReturnValue([''])
;(fs.existsSync as jest.Mock).mockReturnValue(true)
;(yarnInstall as any as jest.Mock).mockImplementation(() => ({ status: 1, stderr: 'test error' }))
jest.spyOn(console, 'error')
vi.mocked(fs.existsSync).mockReturnValue(true)
vi.mocked(yarnInstall).mockImplementation(() => ({ status: 1, stderr: 'test error' }))
vi.spyOn(console, 'error')
await installCmd.handler({ type: 'service', name: 'chromedriver', config: './wdio.conf.js' } as any)
@ -121,15 +123,15 @@ You can create one by running 'wdio config'`, undefined)
})
afterEach(() => {
(console.log as jest.Mock).mockClear()
;(process.exit as any as jest.Mock).mockClear()
;(fs.readFileSync as jest.Mock).mockClear()
;(fs.existsSync as jest.Mock).mockClear()
;(fs.writeFileSync as jest.Mock).mockClear()
vi.mocked(console.log).mockClear()
vi.mocked(process.exit).mockClear()
vi.mocked(fs.readFileSync).mockClear()
vi.mocked(fs.existsSync).mockClear()
vi.mocked(fs.writeFileSync).mockClear()
;(utils.findInConfig as jest.Mock).mockClear()
;(utils.addServiceDeps as jest.Mock).mockClear()
;(utils.replaceConfig as jest.Mock).mockClear()
;(configCmd.missingConfigurationPrompt as jest.Mock).mockClear()
vi.mocked(utils.findInConfig).mockClear()
vi.mocked(utils.addServiceDeps).mockClear()
vi.mocked(utils.replaceConfig).mockClear()
vi.mocked(configCmd.missingConfigurationPrompt).mockClear()
})
})

View file

@ -1,21 +1,27 @@
import path from 'node:path'
import { vi, describe, it, expect, afterEach, beforeEach } from 'vitest'
// @ts-expect-error mock
import { yargs } from 'yargs/yargs'
import { remote } from 'webdriverio'
import { handler, builder } from '../../src/commands/repl'
jest.mock('@wdio/utils', () => {
vi.mock('@wdio/utils', () => {
let syncSupport = false
return {
setSyncSupport: (val: boolean) => (syncSupport = val),
get hasWdioSyncSupport () {
return syncSupport
default: {
setSyncSupport: (val: boolean) => (syncSupport = val),
get hasWdioSyncSupport () {
return syncSupport
}
}
}
})
jest.mock('repl')
vi.mock('repl')
vi.mock('yargs/yargs')
vi.mock('webdriverio', () => import(path.join(process.cwd(), '__mocks__', 'webdriverio')))
describe('repl commandDir', () => {
it('should call debug command', async () => {
@ -44,7 +50,7 @@ describe('repl commandDir', () => {
describe('Command: repl', () => {
beforeEach(() => {
(remote as jest.Mock).mockClear()
vi.mocked(remote).mockClear()
})
it('should attach global variables', async () => {
@ -52,6 +58,7 @@ describe('Command: repl', () => {
expect(global.$).not.toBeUndefined()
expect(global.$$).not.toBeUndefined()
// @ts-expect-error
expect(global.browser).not.toBeUndefined()
})

View file

@ -1,54 +1,59 @@
import { vi, describe, it, expect, afterEach, beforeEach } from 'vitest'
// @ts-expect-error mock
import { yargs } from 'yargs/yargs'
import fs from 'fs-extra'
import * as runCmd from '../../src/commands/run'
import * as configCmd from '../../src/commands/config'
jest.mock('./../../src/launcher', () => class {
run() {
return {
then: jest.fn().mockReturnValue({
catch: jest.fn().mockReturnValue('launcher-mock')
})
vi.mock('yargs/yargs')
vi.mock('fs-extra')
vi.mock('./../../src/launcher', () => ({
default: class {
run() {
return {
then: vi.fn().mockReturnValue({
catch: vi.fn().mockReturnValue('launcher-mock')
})
}
}
}
})
jest.mock('./../../src/watcher', () => class {
watch() {
return 'watching-test'
}))
vi.mock('./../../src/watcher', () => ({
default: class {
watch() {
return 'watching-test'
}
}
})
jest.mock('fs-extra')
}))
describe('Command: run', () => {
const setEncodingMock = jest.fn()
const onMock = jest.fn((s, c) => c())
const setEncodingMock = vi.fn()
const onMock = vi.fn((s, c) => c())
beforeEach(() => {
(fs.existsSync as jest.Mock).mockImplementation(() => true)
;(fs.existsSync as jest.Mock).mockClear()
jest.spyOn(configCmd, 'missingConfigurationPrompt').mockImplementation((): Promise<never> => {
vi.mocked(fs.existsSync).mockImplementation(() => true)
vi.mocked(fs.existsSync).mockClear()
vi.spyOn(configCmd, 'missingConfigurationPrompt').mockImplementation((): Promise<never> => {
return undefined as never
})
jest.spyOn(console, 'error')
jest.spyOn(process, 'openStdin').mockImplementation(
vi.spyOn(console, 'error')
vi.spyOn(process, 'openStdin').mockImplementation(
() => ({ setEncoding: setEncodingMock, on: onMock }) as any)
})
it('should call missingConfigurationPrompt if no config found', async () => {
(fs.existsSync as jest.Mock).mockImplementation(() => false)
vi.mocked(fs.existsSync).mockImplementation(() => false)
await runCmd.handler({} as any)
expect(configCmd.missingConfigurationPrompt).toHaveBeenCalledTimes(1)
expect((configCmd.missingConfigurationPrompt as jest.Mock).mock.calls[0][1])
expect(vi.mocked(configCmd.missingConfigurationPrompt).mock.calls[0][1])
.toContain('No WebdriverIO configuration found in "')
;(fs.existsSync as jest.Mock).mockClear()
vi.mocked(fs.existsSync).mockClear()
})
it('should use local conf if nothing defined', async () => {
(fs.existsSync as jest.Mock).mockImplementation(() => true)
vi.mocked(fs.existsSync).mockImplementation(() => true)
await runCmd.handler({ argv: {} } as any)
expect(fs.existsSync).toBeCalledTimes(2)
})
@ -90,9 +95,9 @@ describe('Command: run', () => {
})
afterEach(() => {
(process.openStdin as jest.Mock).mockReset()
;(console.error as any as jest.Mock).mockReset()
;(fs.existsSync as jest.Mock).mockClear()
;(configCmd.missingConfigurationPrompt as jest.Mock).mockClear()
vi.mocked(process.openStdin).mockReset()
vi.mocked(console.error).mockReset()
vi.mocked(fs.existsSync).mockClear()
vi.mocked(configCmd.missingConfigurationPrompt).mockClear()
})
})

View file

@ -1,3 +1,4 @@
import { test, expect } from 'vitest'
import { getAnswers } from '../src/utils'
test('runConfig with yes param', async () => {

View file

@ -1,36 +1,38 @@
import { join, resolve } from 'node:path'
import { vi, describe, it, expect, afterEach, beforeEach } from 'vitest'
// @ts-expect-error mock
import { yargs as yargsMock } from 'yargs/yargs'
import { run } from '../src/index'
import { handler } from '../src/commands/run'
jest.mock('./../src/commands/run', () => ({
...jest.requireActual('./../src/commands/run') as object,
handler: jest.fn().mockReturnValue(Promise.resolve('success'))
vi.mock('yargs/yargs')
vi.mock('./../src/commands/run', async () => ({
...(await vi.importActual('./../src/commands/run')) as object,
handler: vi.fn().mockReturnValue(Promise.resolve('success'))
}))
const consoleError = console.error
describe('index', () => {
beforeEach(() => {
(handler as jest.Mock).mockClear()
;(yargsMock.parse as jest.Mock).mockClear()
console.error = jest.fn()
vi.mocked(handler).mockClear()
vi.mocked(yargsMock.parse).mockClear()
console.error = vi.fn()
})
it('should call config if no known command is used', async () => {
await run()
expect((handler as jest.Mock).mock.calls[0][0]).toEqual({
expect(vi.mocked(handler).mock.calls[0][0]).toEqual({
configPath: join(`${process.cwd()}`, 'wdio.conf.js'),
_: ['wdio.conf.js']
})
})
it('should set default config filename if not set', async () => {
(yargsMock.parse as jest.Mock).mockReturnValue({ _: [], spec: ['/foo/bar'] }) as any
vi.mocked(yargsMock.parse).mockReturnValue({ _: [], spec: ['/foo/bar'] }) as any
await run()
expect((handler as jest.Mock).mock.calls[0][0]).toEqual({
expect(vi.mocked(handler).mock.calls[0][0]).toEqual({
configPath: join(`${process.cwd()}`, 'wdio.conf.js'),
spec: ['/foo/bar'],
_: []
@ -39,15 +41,15 @@ describe('index', () => {
it('should work properly with absolute paths', async () => {
const expectedPath = resolve('/some/absolute/path/here/wdio.conf.js')
;(yargsMock.parse as jest.Mock).mockReturnValue({ ...yargsMock.argv, _: [expectedPath] }) as any
vi.mocked(yargsMock.parse).mockReturnValue({ ...yargsMock.argv, _: [expectedPath] }) as any
await run().catch()
expect(handler).toHaveBeenCalledTimes(1)
expect((handler as jest.Mock).mock.calls[0][0]).toEqual({
expect(vi.mocked(handler).mock.calls[0][0]).toEqual({
configPath: expectedPath,
_: [expectedPath]
})
;(yargsMock.epilogue as jest.Mock).mockClear()
vi.mocked(yargsMock.epilogue).mockClear()
})
/**
@ -55,19 +57,19 @@ describe('index', () => {
* for some reason the `cb` variable is not the callback passed in
*/
it.skip('should gracefully fail', async () => {
(yargsMock.parse as jest.Mock).mockImplementation((str, cb) => {
vi.mocked(yargsMock.parse).mockImplementation((str: never, cb: Function) => {
cb(null, null, 'test')
return yargsMock.argv
})
;(handler as jest.Mock).mockRejectedValue(new Error('ups'))
jest.spyOn(console, 'error')
vi.mocked(handler).mockRejectedValue(new Error('ups'))
vi.spyOn(console, 'error')
await run()
expect(console.error).toHaveBeenCalled()
})
it('should do nothing if command was called', async () => {
(yargsMock.parse as jest.Mock).mockReturnValue({ ...yargsMock.argv, _: ['run'] }) as any
vi.mocked(yargsMock.parse).mockReturnValue({ ...yargsMock.argv, _: ['run'] }) as any
expect(typeof (await run())).toBe('undefined')
})

View file

@ -1,3 +1,5 @@
import path from 'node:path'
import { vi, describe, it, expect, afterEach, beforeEach } from 'vitest'
import WDIOCLInterface from '../src/interface'
import { HookError } from '../src/utils'
import chalk from 'chalk'
@ -8,13 +10,16 @@ const EMPTY_INTERFACE_MESSAGE_OBJECT = {
debugger: {}
}
vi.mock('chalk')
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))
describe('cli interface', () => {
let wdioClInterface: WDIOCLInterface
beforeEach(() => {
global.console.log = jest.fn()
global.console.log = vi.fn()
wdioClInterface = new WDIOCLInterface(config as any, 5)
wdioClInterface.log = jest.fn().mockImplementation((...args) => args)
wdioClInterface.log = vi.fn().mockImplementation((...args: any[]) => args)
})
it('should add jobs', () => {
@ -99,7 +104,7 @@ describe('cli interface', () => {
})
it('should print test error', () => {
wdioClInterface.onTestError = jest.fn()
wdioClInterface.onTestError = vi.fn()
wdioClInterface.onMessage({
origin: 'reporter',
name: 'printFailureMessage',
@ -110,7 +115,7 @@ describe('cli interface', () => {
})
it('should trigger job:start event on testFrameworkInit', () => {
wdioClInterface.emit = jest.fn()
wdioClInterface.emit = vi.fn()
wdioClInterface.onMessage({
name: 'testFrameworkInit',
content: 'content'
@ -120,7 +125,7 @@ describe('cli interface', () => {
it('should print reporter messages in watch mode', () => {
wdioClInterface['_isWatchMode'] = true
wdioClInterface.printReporters = jest.fn()
wdioClInterface.printReporters = vi.fn()
wdioClInterface.onMessage({
origin: 'reporter',
@ -136,7 +141,7 @@ describe('cli interface', () => {
})
it('should not store any other messages', () => {
wdioClInterface.printReporters = jest.fn()
wdioClInterface.printReporters = vi.fn()
expect(wdioClInterface.onMessage({
cid: '0-0',
@ -201,7 +206,7 @@ describe('cli interface', () => {
describe('setup', () => {
it('called within constructor', () => {
wdioClInterface.onStart = jest.fn()
wdioClInterface.onStart = vi.fn()
expect(wdioClInterface.result).toEqual({
finished: 0,
passed: 0,
@ -212,7 +217,7 @@ describe('cli interface', () => {
})
it('called explicitly', () => {
wdioClInterface.onStart = jest.fn()
wdioClInterface.onStart = vi.fn()
wdioClInterface['_messages'] = {
reporter: {},
debugger: {}
@ -315,22 +320,23 @@ describe('cli interface', () => {
scenarios.forEach(scenario => {
it(scenario.method, () => {
wdioClInterface.onJobComplete = jest.fn()
wdioClInterface.onJobComplete = vi.fn()
wdioClInterface['_jobs'].set(scenario.cid, scenario.job)
// @ts-expect-error
wdioClInterface[scenario.method](scenario.cid, scenario.job, scenario.retries)
expect(wdioClInterface.onJobComplete).toBeCalledWith(scenario.cid, scenario.job, scenario.retries, scenario.message)
})
})
it('onSpecSkip', () => {
wdioClInterface.onJobComplete = jest.fn()
wdioClInterface.onJobComplete = vi.fn()
wdioClInterface['_jobs'].set('cid', job)
wdioClInterface.onSpecSkip(cid, job)
expect(wdioClInterface.onJobComplete).toBeCalledWith(cid, job, 0, 'SKIPPED', expect.any(Function))
})
it('onSpecRetry with delay', () => {
wdioClInterface.onJobComplete = jest.fn()
wdioClInterface.onJobComplete = vi.fn()
wdioClInterface['_specFileRetriesDelay'] = 2
wdioClInterface['_jobs'].set('cid', job)
wdioClInterface.onSpecRetry(cid, job, 3)
@ -345,10 +351,12 @@ describe('cli interface', () => {
specs: ['bar'],
hasTests: true
})
// @ts-expect-error
expect(wdioClInterface.sigintTrigger()[0]).toContain('Ending WebDriver sessions gracefully')
})
it('should print message without jobs', () => {
// @ts-expect-error
expect(wdioClInterface.sigintTrigger()[0]).toContain('Ended WebDriver sessions gracefully')
})
@ -369,15 +377,15 @@ describe('cli interface', () => {
wdioClInterface.printReporters()
expect(wdioClInterface['_messages'].reporter).toEqual({})
expect(wdioClInterface.log).toBeCalledTimes(2)
expect((wdioClInterface.log as jest.Mock).mock.calls[0][1]).toContain('"foo" Reporter:')
expect((wdioClInterface.log as jest.Mock).mock.calls[1][0]).toContain('bar')
expect(vi.mocked(wdioClInterface.log).mock.calls[0][1]).toContain('"foo" Reporter:')
expect(vi.mocked(wdioClInterface.log).mock.calls[1][0]).toContain('bar')
})
})
describe('finalise', () => {
it('finalise should print reporters and summary', () => {
wdioClInterface.printReporters = jest.fn()
wdioClInterface.printSummary = jest.fn()
wdioClInterface.printReporters = vi.fn()
wdioClInterface.printSummary = vi.fn()
wdioClInterface.finalise()
expect(wdioClInterface.printReporters).toBeCalledTimes(1)
expect(wdioClInterface.printSummary).toBeCalledTimes(1)
@ -385,8 +393,8 @@ describe('cli interface', () => {
it('finalise should do nothing in watch mode', () => {
wdioClInterface['_isWatchMode'] = true
wdioClInterface.printReporters = jest.fn()
wdioClInterface.printSummary = jest.fn()
wdioClInterface.printReporters = vi.fn()
wdioClInterface.printSummary = vi.fn()
wdioClInterface.finalise()
expect(wdioClInterface.printReporters).toBeCalledTimes(0)
expect(wdioClInterface.printSummary).toBeCalledTimes(0)
@ -423,7 +431,7 @@ describe('cli interface', () => {
})
})
test('logHookError', () => {
it('logHookError', () => {
const err = new HookError('foobar', 'somewhere')
expect(wdioClInterface.logHookError(err)[0])
.toContain('red SevereServiceError in "somewhere"')
@ -492,6 +500,6 @@ describe('cli interface', () => {
afterEach(() => {
wdioClInterface['_specFileRetriesDelay'] = 0
;(global.console.log as jest.Mock).mockRestore()
vi.mocked(global.console.log).mockRestore()
})
})

View file

@ -1,3 +1,5 @@
import path from 'node:path'
import { vi, describe, it, expect, afterEach, beforeEach } from 'vitest'
import Launcher from '../src/launcher'
import logger from '@wdio/logger'
import { sleep } from '@wdio/utils'
@ -5,20 +7,25 @@ import fs from 'fs-extra'
const caps: WebDriver.DesiredCapabilities = { maxInstances: 1, browserName: 'chrome' }
jest.mock('fs-extra')
jest.mock('../src/interface', () => class {
emit = jest.fn()
on = jest.fn()
sigintTrigger = jest.fn()
onMessage = jest.fn()
})
vi.mock('fs-extra')
vi.mock('@wdio/utils', () => import(path.join(process.cwd(), '__mocks__', '@wdio/utils')))
vi.mock('@wdio/config', () => import(path.join(process.cwd(), '__mocks__', '@wdio/config')))
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))
vi.mock('../src/interface', () => ({
default: class {
emit = vi.fn()
on = vi.fn()
sigintTrigger = vi.fn()
onMessage = vi.fn()
}
}))
describe('launcher', () => {
const emitSpy = jest.spyOn(process, 'emit')
const emitSpy = vi.spyOn(process, 'emit')
let launcher: Launcher
beforeEach(() => {
global.console.log = jest.fn()
global.console.log = vi.fn()
emitSpy.mockClear()
launcher = new Launcher('./')
})
@ -50,7 +57,7 @@ describe('launcher', () => {
describe('capabilities', () => {
it('should NOT fail when capabilities are passed', async () => {
launcher.runSpecs = jest.fn().mockReturnValue(1)
launcher.runSpecs = vi.fn().mockReturnValue(1)
const exitCode = await launcher.runMode({ specs: ['./'] } as any, [caps])
expect(launcher.runSpecs).toBeCalled()
expect(exitCode).toEqual(0)
@ -58,15 +65,15 @@ describe('launcher', () => {
})
it('should fail if no specs were found', async () => {
launcher.runSpecs = jest.fn()
launcher.configParser.getSpecs = jest.fn().mockReturnValue([])
launcher.runSpecs = vi.fn()
launcher.configParser.getSpecs = vi.fn().mockReturnValue([])
const exitCode = await launcher.runMode({ specs: ['./'] } as any, [caps])
expect(launcher.runSpecs).toBeCalledTimes(0)
expect(exitCode).toBe(1)
})
it('should fail when no capabilities are passed', async () => {
launcher.runSpecs = jest.fn().mockReturnValue(1)
launcher.runSpecs = vi.fn().mockReturnValue(1)
// @ts-ignore test invalid parameter
const exitCode = await launcher.runMode({ specs: ['./'] as any })
expect(exitCode).toEqual(1)
@ -74,14 +81,14 @@ describe('launcher', () => {
})
it('should fail when no capabilities are set', async () => {
launcher.runSpecs = jest.fn().mockReturnValue(1)
const exitCode = await launcher.runMode({ specs: ['./'] } as any, undefined)
launcher.runSpecs = vi.fn().mockReturnValue(1)
const exitCode = await launcher.runMode({ specs: ['./'] } as any, undefined as any)
expect(exitCode).toEqual(1)
expect(logger('').error).toBeCalledWith('Missing capabilities, exiting with failure')
})
it('should start instance in multiremote', () => {
launcher.runSpecs = jest.fn()
launcher.runSpecs = vi.fn()
launcher.isMultiremote = true
launcher.runMode(
{ specs: ['./'], specFileRetries: 2 } as any,
@ -96,7 +103,7 @@ describe('launcher', () => {
})
it('should start instance with grouped specs', () => {
launcher.runSpecs = jest.fn()
launcher.runSpecs = vi.fn()
launcher.isMultiremote = false
launcher.runMode(
{ specs: [['/a.js', '/b.js']], specFileRetries: 2 } as any,
@ -111,7 +118,7 @@ describe('launcher', () => {
})
it('should start instance in multiremote with grouped specs', () => {
launcher.runSpecs = jest.fn()
launcher.runSpecs = vi.fn()
launcher.isMultiremote = true
launcher.runMode(
{ specs: [['/a.js', '/b.js']], specFileRetries: 2 } as any,
@ -126,7 +133,7 @@ describe('launcher', () => {
})
it('should ignore specFileRetries in watch mode', () => {
launcher.runSpecs = jest.fn()
launcher.runSpecs = vi.fn()
launcher['_isWatchMode'] = true
launcher.runMode({ specs: ['./'], specFileRetries: 2 } as any, [caps, caps])
@ -138,7 +145,7 @@ describe('launcher', () => {
})
it('should apply maxInstancesPerCapability if maxInstances is not passed', () => {
launcher.runSpecs = jest.fn()
launcher.runSpecs = vi.fn()
launcher.runMode(
{ specs: ['./'], specFileRetries: 3, maxInstancesPerCapability: 4 } as any,
[{ browserName: 'chrome' }]
@ -154,14 +161,14 @@ describe('launcher', () => {
describe('hasTriggeredExitRoutine', () => {
it('should return false if there are specs left of running when hasTriggeredExitRoutine is false', () => {
launcher.getNumberOfRunningInstances = jest.fn().mockReturnValue(1)
launcher.getNumberOfRunningInstances = vi.fn().mockReturnValue(1)
launcher['_hasTriggeredExitRoutine'] = false
const returnValue = launcher.runSpecs()
expect(returnValue).toEqual(false)
})
it('should return true when hasTriggeredExitRoutine is true', () => {
launcher.getNumberOfRunningInstances = jest.fn().mockReturnValue(1)
launcher.getNumberOfRunningInstances = vi.fn().mockReturnValue(1)
launcher['_hasTriggeredExitRoutine'] = true
const returnValue = launcher.runSpecs()
expect(returnValue).toEqual(true)
@ -169,18 +176,18 @@ describe('launcher', () => {
})
describe('endHandler', () => {
const config = { onWorkerEnd: jest.fn() }
const config = { onWorkerEnd: vi.fn() }
beforeEach(() => {
launcher['_launcher'] = []
launcher.configParser.getConfig = jest.fn().mockReturnValue(config)
launcher.configParser.getConfig = vi.fn().mockReturnValue(config)
})
it('should emit and resolve failed status', async () => {
launcher.getNumberOfRunningInstances = jest.fn().mockReturnValue(1)
launcher.runSpecs = jest.fn().mockReturnValue(1)
launcher.getNumberOfRunningInstances = vi.fn().mockReturnValue(1)
launcher.runSpecs = vi.fn().mockReturnValue(1)
launcher['_schedule'] = [{ cid: 1 } as any, { cid: 2 }]
launcher['_resolve'] = jest.fn()
launcher['_resolve'] = vi.fn()
await launcher.endHandler({ cid: '0-1', exitCode: 1, specs: [], retries: 0 } as any)
expect(launcher.interface.emit).toBeCalledWith('job:end', { cid: '0-1', passed: false, retries: 0 })
expect(launcher['_resolve']).toBeCalledWith(1)
@ -188,43 +195,43 @@ describe('launcher', () => {
})
it('should emit and resolve passed status', async () => {
launcher.getNumberOfRunningInstances = jest.fn().mockReturnValue(1)
launcher.runSpecs = jest.fn().mockReturnValue(1)
launcher.getNumberOfRunningInstances = vi.fn().mockReturnValue(1)
launcher.runSpecs = vi.fn().mockReturnValue(1)
launcher['_schedule'] = [{ cid: 1 } as any, { cid: 2 }]
launcher['_resolve'] = jest.fn()
launcher['_resolve'] = vi.fn()
await launcher.endHandler({ cid: '0-1', exitCode: 0 } as any)
expect(launcher.interface.emit).toBeCalledWith('job:end', { cid: '0-1', passed: true })
expect(launcher['_resolve']).toBeCalledWith(0)
})
it('should do nothing if not all specs are run', async () => {
launcher.getNumberOfRunningInstances = jest.fn().mockReturnValue(1)
launcher.runSpecs = jest.fn().mockReturnValue(0)
launcher.getNumberOfRunningInstances = vi.fn().mockReturnValue(1)
launcher.runSpecs = vi.fn().mockReturnValue(0)
launcher['_schedule'] = [{ cid: 1 } as any, { cid: 2 }]
launcher['_resolve'] = jest.fn()
launcher['_resolve'] = vi.fn()
await launcher.endHandler({ cid: '0-1', exitCode: 0 } as any)
expect(launcher.interface.emit).toBeCalledWith('job:end', { cid: '0-1', passed: true })
expect(launcher['_resolve']).toBeCalledTimes(0)
})
it('should do nothing if watch mode is still running', async () => {
launcher.getNumberOfRunningInstances = jest.fn().mockReturnValue(1)
launcher.getNumberOfRunningInstances = vi.fn().mockReturnValue(1)
launcher['_isWatchMode'] = true
launcher.runSpecs = jest.fn().mockReturnValue(1)
launcher.runSpecs = vi.fn().mockReturnValue(1)
launcher['_schedule'] = [{ cid: 1 } as any, { cid: 2 }]
launcher['_resolve'] = jest.fn()
launcher['_resolve'] = vi.fn()
await launcher.endHandler({ cid: '0-1', exitCode: 1 } as any)
expect(launcher.interface.emit).toBeCalledWith('job:end', { cid: '0-1', passed: false })
expect(launcher['_resolve']).toBeCalledTimes(0)
})
it('should resolve and not emit on watch mode stop', async () => {
launcher.getNumberOfRunningInstances = jest.fn().mockReturnValue(1)
launcher.getNumberOfRunningInstances = vi.fn().mockReturnValue(1)
launcher['_isWatchMode'] = true
launcher['_hasTriggeredExitRoutine'] = true
launcher.runSpecs = jest.fn().mockReturnValue(1)
launcher.runSpecs = vi.fn().mockReturnValue(1)
launcher['_schedule'] = [{ cid: 1 } as any, { cid: 2 }]
launcher['_resolve'] = jest.fn()
launcher['_resolve'] = vi.fn()
await launcher.endHandler({ cid: '0-1', exitCode: 1 } as any)
expect(launcher.interface.emit).not.toBeCalled()
expect(launcher['_resolve']).toBeCalledWith(0)
@ -237,7 +244,7 @@ describe('launcher', () => {
})
it('should requeue retried specfiles at beginning of queue', async () => {
launcher.configParser.getConfig = jest.fn().mockReturnValue({ specFileRetriesDeferred: false, onWorkerEnd: jest.fn() })
launcher.configParser.getConfig = vi.fn().mockReturnValue({ specFileRetriesDeferred: false, onWorkerEnd: vi.fn() })
launcher['_schedule'] = [{ cid: 0, specs: [{ files: ['b.js'] }] }] as any
await launcher.endHandler({ cid: '0-5', exitCode: 1, retries: 1, specs: ['a.js'] })
expect(launcher['_schedule']).toMatchObject([{ cid: 0, specs: [{ rid: '0-5', files: ['a.js'], retries: 0 }, { files: ['b.js'] }] }])
@ -253,36 +260,36 @@ describe('launcher', () => {
describe('exitHandler', () => {
it('should do nothing if no callback is given', () => {
launcher['_hasTriggeredExitRoutine'] = false
launcher.runner = { shutdown: jest.fn()
launcher.runner = { shutdown: vi.fn()
.mockReturnValue(Promise.resolve()) } as any
launcher.exitHandler()
expect(launcher['_hasTriggeredExitRoutine']).toBe(false)
expect(launcher.interface.sigintTrigger).toBeCalledTimes(0)
expect(launcher.runner.shutdown).toBeCalledTimes(0)
expect(launcher.runner?.shutdown).toBeCalledTimes(0)
})
it('should do nothing if shutdown was called before', () => {
launcher['_hasTriggeredExitRoutine'] = true
launcher.runner = { shutdown: jest.fn().mockReturnValue(Promise.resolve()) } as any
launcher.runner = { shutdown: vi.fn().mockReturnValue(Promise.resolve()) } as any
expect(launcher.exitHandler(() => 'foo')).toBe('foo')
expect(launcher['_hasTriggeredExitRoutine']).toBe(true)
expect(launcher.interface.sigintTrigger).toBeCalledTimes(0)
expect(launcher.runner.shutdown).toBeCalledTimes(0)
expect(launcher.runner?.shutdown).toBeCalledTimes(0)
})
it('should shutdown', () => {
launcher['_hasTriggeredExitRoutine'] = false
launcher.runner = { shutdown: jest.fn().mockReturnValue(Promise.resolve()) } as any
launcher.runner = { shutdown: vi.fn().mockReturnValue(Promise.resolve()) } as any
launcher.exitHandler(jest.fn())
launcher.exitHandler(vi.fn())
expect(launcher['_hasTriggeredExitRoutine']).toBe(true)
expect(launcher.interface.sigintTrigger).toBeCalledTimes(1)
expect(launcher.runner.shutdown).toBeCalledTimes(1)
expect(launcher.runner?.shutdown).toBeCalledTimes(1)
})
})
@ -325,7 +332,7 @@ describe('launcher', () => {
]
// Mock the return value of getSpecs so we are not doing cross
// module testing
launcher.configParser = { getSpecs: jest.fn().mockReturnValue(
launcher.configParser = { getSpecs: vi.fn().mockReturnValue(
['/a.js', ['/b.js', '/c.js', '/d.js'], '/e.js']
) } as any
expect(launcher.formatSpecs(capabilities as any, specFileRetries)).toStrictEqual(expected)
@ -334,11 +341,11 @@ describe('launcher', () => {
describe('runSpecs', () => {
beforeEach(() => {
launcher.startInstance = jest.fn()
launcher.startInstance = vi.fn()
})
it('should not start running anything if exit routine is triggered', () => {
launcher.configParser = { getConfig: jest.fn().mockReturnValue({
launcher.configParser = { getConfig: vi.fn().mockReturnValue({
maxInstances: 100
}) } as any
launcher['_hasTriggeredExitRoutine'] = true
@ -347,7 +354,7 @@ describe('launcher', () => {
})
it('should run all specs', () => {
launcher.configParser = { getConfig: jest.fn().mockReturnValue({
launcher.configParser = { getConfig: vi.fn().mockReturnValue({
maxInstances: 100
}) } as any
launcher['_schedule'] = [{
@ -384,7 +391,7 @@ describe('launcher', () => {
})
it('should run arrayed specs in a single instance', () => {
launcher.configParser = { getConfig: jest.fn().mockReturnValue({
launcher.configParser = { getConfig: vi.fn().mockReturnValue({
maxInstances: 100
}) } as any
launcher['_schedule'] = [{
@ -422,7 +429,7 @@ describe('launcher', () => {
it('should not run anything if runner failed', () => {
launcher['_runnerFailed'] = 2
launcher.configParser = { getConfig: jest.fn().mockReturnValue({
launcher.configParser = { getConfig: vi.fn().mockReturnValue({
maxInstances: 100,
bail: 1
}) } as any
@ -454,7 +461,7 @@ describe('launcher', () => {
})
it('should run as much as maxInstances allows', () => {
launcher.configParser = { getConfig: jest.fn().mockReturnValue({
launcher.configParser = { getConfig: vi.fn().mockReturnValue({
maxInstances: 5
}) } as any
launcher['_schedule'] = [{
@ -485,7 +492,7 @@ describe('launcher', () => {
})
it('should not allow to schedule more runner if no instances are available', () => {
launcher.configParser = { getConfig: jest.fn().mockReturnValue({
launcher.configParser = { getConfig: vi.fn().mockReturnValue({
maxInstances: 100
}) } as any
launcher['_schedule'] = [{
@ -522,7 +529,7 @@ describe('launcher', () => {
})
it('should not run if all specs were executed', () => {
launcher.configParser = { getConfig: jest.fn().mockReturnValue({
launcher.configParser = { getConfig: vi.fn().mockReturnValue({
maxInstances: 100
}) } as any
launcher['_schedule'] = [{
@ -541,12 +548,17 @@ describe('launcher', () => {
describe('startInstance', () => {
beforeEach(() => {
(launcher.runner.run as jest.Mock) = jest.fn().mockReturnValue({ on: () => {} })
// launcher.runner?.run = vi.fn().mockReturnValue({ on: () => {} })
launcher['_launcher'] = []
launcher.runner = {
run: vi.fn().mockReturnValue({
on: vi.fn()
})
} as any
})
it('should start an instance', async () => {
const onWorkerStartMock = jest.fn()
const onWorkerStartMock = vi.fn()
const caps = {
browserName: 'chrome'
}
@ -564,7 +576,7 @@ describe('launcher', () => {
expect(sleep).not.toHaveBeenCalled()
expect(launcher['_runnerStarted']).toBe(1)
expect((launcher.runner.run as jest.Mock).mock.calls[0][0]).toHaveProperty('cid', '0-5')
expect(vi.mocked(launcher.runner?.run!).mock.calls[0][0]).toHaveProperty('cid', '0-5')
expect(launcher.getRunnerId(0)).toBe('0-0')
expect(onWorkerStartMock).toHaveBeenCalledWith(
@ -572,16 +584,16 @@ describe('launcher', () => {
caps,
['/foo.test.js'],
{ hostname: '127.0.0.2' },
['--no-wasm-code-gc']
[]
)
})
it('should wait before starting an instance on retry', async () => {
const onWorkerStartMock = jest.fn()
const onWorkerStartMock = vi.fn()
const caps = {
browserName: 'chrome'
}
launcher.configParser = { getConfig: jest.fn().mockReturnValue({
launcher.configParser = { getConfig: vi.fn().mockReturnValue({
onWorkerStart: onWorkerStartMock,
specFileRetries: 2,
specFileRetriesDelay: 0.01
@ -604,16 +616,16 @@ describe('launcher', () => {
caps,
['/foo.test.js'],
{ hostname: '127.0.0.3' },
['--no-wasm-code-gc']
[]
)
})
it('should not wait before starting an instance on the first run', async () => {
const onWorkerStartMock = jest.fn()
const onWorkerStartMock = vi.fn()
const caps = {
browserName: 'chrome'
}
launcher.configParser = { getConfig: jest.fn().mockReturnValue({
launcher.configParser = { getConfig: vi.fn().mockReturnValue({
onWorkerStart: onWorkerStartMock,
specFileRetries: 4,
specFileRetriesDelay: 0.01
@ -635,22 +647,18 @@ describe('launcher', () => {
caps,
['/foo.test.js'],
{ hostname: '127.0.0.4' },
['--no-wasm-code-gc']
[]
)
})
})
describe('config options', () => {
let ensureDirSyncSpy: any
beforeEach(() => {
ensureDirSyncSpy = jest.spyOn(fs, 'ensureDirSync')
})
it('should create directory when the config options have a outputDir option', () => {
expect(ensureDirSyncSpy).toHaveBeenCalled()
expect(ensureDirSyncSpy).toHaveBeenCalledWith('tempDir')
expect(vi.mocked(fs.ensureDirSync)).toHaveBeenCalled()
expect(vi.mocked(fs.ensureDirSync)).toHaveBeenCalledWith('tempDir')
})
afterEach(() => {
ensureDirSyncSpy.mockClear()
vi.mocked(fs.ensureDirSync).mockClear()
})
})
@ -658,33 +666,36 @@ describe('launcher', () => {
let config: WebdriverIO.Config = { capabilities: {} }
beforeEach(() => {
global.console.error = jest.fn()
global.console.error = vi.fn()
config = {
// ConfigParser.addFileConfig() will return onPrepare and onComplete as arrays of functions
onPrepare: [jest.fn()],
onComplete: [jest.fn()],
capabilities: {}
onPrepare: [vi.fn()],
onComplete: [vi.fn()],
capabilities: {},
runner: 'local'
}
launcher.configParser = {
getCapabilities: jest.fn().mockReturnValue(0),
getConfig: jest.fn().mockReturnValue(config),
autoCompile: jest.fn()
getCapabilities: vi.fn().mockReturnValue(0),
getConfig: vi.fn().mockReturnValue(config),
autoCompile: vi.fn()
} as any
launcher.runner = { initialise: jest.fn(), shutdown: jest.fn() } as any
launcher.runMode = jest.fn().mockImplementation((config, caps) => caps)
launcher.interface = { finalise: jest.fn() } as any
launcher.runner = { initialise: vi.fn(), shutdown: vi.fn() } as any
launcher.runMode = vi.fn().mockImplementation((config, caps) => caps)
launcher.interface = { finalise: vi.fn() } as any
})
it('exit code 0', async () => {
expect(await launcher.run()).toEqual(0)
expect(launcher.runner.shutdown).toBeCalled()
expect(launcher.runner!.shutdown).toBeCalled()
expect(launcher.configParser.getCapabilities).toBeCalledTimes(1)
expect(launcher.configParser.getConfig).toBeCalledTimes(1)
expect(launcher.runner.initialise).toBeCalledTimes(1)
expect(launcher.runner!.initialise).toBeCalledTimes(1)
// @ts-expect-error
expect(config.onPrepare[0]).toBeCalledTimes(1)
expect(launcher.runMode).toBeCalledTimes(1)
// @ts-expect-error
expect(config.onPrepare[0]).toBeCalledTimes(1)
expect(launcher.interface.finalise).toBeCalledTimes(1)
})
@ -692,7 +703,7 @@ describe('launcher', () => {
it('should not shutdown runner if was called before', async () => {
launcher['_hasTriggeredExitRoutine'] = true
expect(await launcher.run()).toEqual(0)
expect(launcher.runner.shutdown).not.toBeCalled()
expect(launcher.runner!.shutdown).not.toBeCalled()
})
it('onComplete error', async () => {
@ -700,10 +711,11 @@ describe('launcher', () => {
config.onComplete = [() => { throw new Error() }]
expect(await launcher.run()).toEqual(1)
expect(launcher.runner.shutdown).toBeCalled()
expect(launcher.runner!.shutdown).toBeCalled()
})
it('should shutdown runner on error', async () => {
// @ts-expect-error
delete logger.waitForBuffer
let error
@ -712,17 +724,17 @@ describe('launcher', () => {
} catch (err: any) {
error = err
}
expect(launcher.runner.shutdown).toBeCalled()
expect(launcher.runner!.shutdown).toBeCalled()
expect(error).toBeInstanceOf(Error)
})
afterEach(() => {
(global.console.error as jest.Mock).mockRestore()
vi.mocked(global.console.error).mockRestore()
})
})
afterEach(() => {
(global.console.log as jest.Mock).mockRestore()
;(sleep as jest.Mock).mockClear()
vi.mocked(global.console.log).mockRestore()
vi.mocked(sleep).mockClear()
})
})

View file

@ -1,40 +1,43 @@
import { vi, describe, it, expect, afterEach, beforeEach } from 'vitest'
import { launch, cmdArgs } from '../src/commands/run'
import Launcher from '../src/launcher'
jest.mock('../src/launcher', () => jest.fn().mockImplementation((conf, result) => ({
run: () => Number.isInteger(result) ? Promise.resolve(result) : Promise.reject(result)
})))
vi.mock('../src/launcher', () => ({
default: vi.fn().mockImplementation((conf, result) => ({
run: () => Number.isInteger(result) ? Promise.resolve(result) : Promise.reject(result)
}))
}))
describe('launch', () => {
beforeEach(() => {
jest.spyOn(console, 'error').mockImplementation(() => {})
vi.spyOn(console, 'error').mockImplementation(() => {})
})
it('should exit with code 0', async () => {
// @ts-ignore mock feature
await launch('configFile', 0)
expect(Launcher).toBeCalledWith('configFile', 0)
expect((Launcher as jest.Mock).mock.instances).toHaveLength(1)
expect(vi.mocked(Launcher).mock.instances).toHaveLength(1)
})
it('should exit with code 1', async () => {
// @ts-ignore mock feature
await launch('configFile', 1)
expect(Launcher).toBeCalledWith('configFile', 1)
expect((Launcher as jest.Mock).mock.instances).toHaveLength(1)
expect(vi.mocked(Launcher).mock.instances).toHaveLength(1)
})
it('should catch errors', async () => {
// @ts-ignore mock feature
await launch('configFile', 'foobar')
expect(Launcher).toBeCalledWith('configFile', 'foobar')
expect((Launcher as jest.Mock).mock.instances).toHaveLength(1)
expect(vi.mocked(Launcher).mock.instances).toHaveLength(1)
expect(console.error).toBeCalledWith('foobar')
})
afterEach(() => {
(Launcher as jest.Mock).mockClear()
;(console.error as jest.Mock).mockRestore()
vi.mocked(Launcher).mockClear()
vi.mocked(console.error).mockRestore()
})
})

View file

@ -1,12 +1,13 @@
import { vi, describe, it, expect, afterEach, beforeEach, test } from 'vitest'
import path from 'node:path'
import fs from 'fs-extra'
import ejs from 'ejs'
import readDirMock from 'recursive-readdir'
import childProcess from 'node:child_process'
import readDir from 'recursive-readdir'
// @ts-ignore mock feature
import { execSyncRes } from 'node:child_process'
import { SevereServiceError } from 'webdriverio'
import { ConfigParser } from '@wdio/config'
const readDir = readDirMock as jest.Mock
import {
runLauncherHook,
runOnCompleteHook,
@ -27,7 +28,10 @@ import {
} from '../src/utils'
import { COMPILER_OPTION_ANSWERS } from '../src/constants'
jest.mock('child_process', function () {
vi.mock('ejs')
vi.mock('recursive-readdir')
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))
vi.mock('child_process', function () {
const m = {
execSyncRes: 'APPIUM_MISSING',
execSync: function () { return m.execSyncRes }
@ -35,15 +39,17 @@ jest.mock('child_process', function () {
return m
})
jest.mock('../src/commands/config', () => ({
runConfig: jest.fn()
vi.mock('../src/commands/config', () => ({
runConfig: vi.fn()
}))
jest.mock('fs-extra', () => ({
existsSync: jest.fn(),
ensureDirSync: jest.fn(),
promises: {
writeFile: jest.fn().mockReturnValue(Promise.resolve())
vi.mock('fs-extra', () => ({
default: {
existsSync: vi.fn(),
ensureDirSync: vi.fn(),
promises: {
writeFile: vi.fn().mockReturnValue(Promise.resolve())
}
}
}))
@ -51,7 +57,7 @@ jest.mock('fs-extra', () => ({
* it is necessary here to create a new mock for the ConfigParser because it
* doesn't seem to be possible to spy on jest mock instances
*/
jest.mock('@wdio/config', () => ({
vi.mock('@wdio/config', () => ({
ConfigParser: class ConfigParserMock {
addConfigFile () {}
autoCompile () {}
@ -60,13 +66,13 @@ jest.mock('@wdio/config', () => ({
}))
beforeEach(() => {
global.console.log = jest.fn()
global.console.log = vi.fn()
})
describe('runServiceHook', () => {
const hookSuccess = jest.fn()
const slowSetupFn = jest.fn()
const asyncHookSuccess = jest.fn().mockImplementation(() => new Promise<void>(resolve => {
const hookSuccess = vi.fn()
const slowSetupFn = vi.fn()
const asyncHookSuccess = vi.fn().mockImplementation(() => new Promise<void>(resolve => {
setTimeout(() => {
slowSetupFn()
resolve()
@ -79,7 +85,7 @@ describe('runServiceHook', () => {
asyncHookSuccess.mockClear()
})
test('run sync and async hooks successfully', async () => {
it('run sync and async hooks successfully', async () => {
await runServiceHook([
{ onPrepare: hookSuccess },
{ onPrepare: asyncHookSuccess },
@ -92,7 +98,7 @@ describe('runServiceHook', () => {
})
it('executes all hooks and continues after a hook throws error', async () => {
const hookFailing = jest.fn().mockImplementation(() => { throw new Error('buhh') })
const hookFailing = vi.fn().mockImplementation(() => { throw new Error('buhh') })
await runServiceHook([
{ onPrepare: hookSuccess },
@ -109,7 +115,7 @@ describe('runServiceHook', () => {
})
it('executes all hooks and stops after a hook throws SevereServiceError', async () => {
const hookFailing = jest.fn().mockImplementation(() => { throw new SevereServiceError() })
const hookFailing = vi.fn().mockImplementation(() => { throw new SevereServiceError() })
try {
await runServiceHook([
@ -131,8 +137,8 @@ describe('runServiceHook', () => {
})
test('runLauncherHook handles array of functions', () => {
const hookSuccess = jest.fn()
const hookFailing = jest.fn().mockImplementation(() => { throw new Error('buhh') })
const hookSuccess = vi.fn()
const hookFailing = vi.fn().mockImplementation(() => { throw new Error('buhh') })
runLauncherHook([hookSuccess, hookFailing], 1, 2, 3, 4, 5, 6)
expect(hookSuccess).toBeCalledTimes(1)
@ -150,7 +156,7 @@ test('runLauncherHook handles async functions', async () => {
})
test('runLauncherHook handles a single function', () => {
const hookSuccess = jest.fn()
const hookSuccess = vi.fn()
runLauncherHook(hookSuccess, 1, 2, 3, 4, 5, 6)
expect(hookSuccess).toBeCalledTimes(1)
@ -158,8 +164,8 @@ test('runLauncherHook handles a single function', () => {
})
test('runOnCompleteHook handles array of functions', () => {
const hookSuccess = jest.fn()
const secondHook = jest.fn()
const hookSuccess = vi.fn()
const secondHook = vi.fn()
runOnCompleteHook([hookSuccess, secondHook], { capabilities: {} }, {}, 0, {} as any)
expect(hookSuccess).toBeCalledTimes(1)
@ -175,15 +181,15 @@ test('runOnCompleteHook handles async functions', async () => {
})
test('runOnCompleteHook handles a single function', () => {
const hookSuccess = jest.fn()
const hookSuccess = vi.fn()
runOnCompleteHook(hookSuccess, { capabilities: {} }, {}, 0, {} as any)
expect(hookSuccess).toBeCalledTimes(1)
})
test('runOnCompleteHook with no failure returns 0', async () => {
const hookSuccess = jest.fn()
const hookFailing = jest.fn()
const hookSuccess = vi.fn()
const hookFailing = vi.fn()
const result = await runOnCompleteHook([hookSuccess, hookFailing], { capabilities: {} }, {}, 0, {} as any)
@ -193,8 +199,8 @@ test('runOnCompleteHook with no failure returns 0', async () => {
})
test('runOnCompleteHook with failure returns 1', async () => {
const hookSuccess = jest.fn()
const hookFailing = jest.fn().mockImplementation(() => { throw new Error('buhh') })
const hookSuccess = vi.fn()
const hookFailing = vi.fn().mockImplementation(() => { throw new Error('buhh') })
const result = await runOnCompleteHook([hookSuccess, hookFailing], { capabilities: {} }, {}, 0, {} as any)
@ -204,8 +210,8 @@ test('runOnCompleteHook with failure returns 1', async () => {
})
test('runOnCompleteHook fails with SevereServiceError', async () => {
const hookSuccess = jest.fn()
const hookFailing = jest.fn().mockImplementation(() => { throw new SevereServiceError('buhh') })
const hookSuccess = vi.fn()
const hookFailing = vi.fn().mockImplementation(() => { throw new SevereServiceError('buhh') })
const result = await runOnCompleteHook([hookSuccess, hookFailing], { capabilities: {} }, {}, 0, {} as any)
.catch(() => 'some error')
@ -255,30 +261,31 @@ describe('findInConfig', () => {
describe('renderConfigurationFile', () => {
it('should write file', async () => {
// @ts-ignore mock feature
jest.spyOn(ejs, 'renderFile').mockImplementation((a, b, c) => c(null, true))
vi.mocked(ejs.renderFile).mockImplementation((a, b, c: any) => c(null, true))
await renderConfigurationFile({ foo: 'bar' } as any)
expect(ejs.renderFile).toHaveBeenCalled()
expect(fs.promises.writeFile).toHaveBeenCalled()
expect((fs.promises.writeFile as jest.Mock).mock.calls[0][0].endsWith('wdio.conf.js')).toBe(true)
expect((vi.mocked(fs.promises.writeFile).mock.calls[0][0] as string)
.endsWith('wdio.conf.js')).toBe(true)
})
it('should write TS file', async () => {
// @ts-ignore mock feature
jest.spyOn(ejs, 'renderFile').mockImplementation((a, b, c) => c(null, true))
vi.mocked(ejs.renderFile).mockImplementation((a, b, c) => c(null, true))
await renderConfigurationFile({ isUsingTypeScript: true } as any)
expect(ejs.renderFile).toHaveBeenCalled()
expect(fs.promises.writeFile).toHaveBeenCalled()
expect((fs.promises.writeFile as jest.Mock).mock.calls[0][0].endsWith('wdio.conf.ts')).toBe(true)
expect((vi.mocked(fs.promises.writeFile).mock.calls[0][0] as string)
.endsWith('wdio.conf.ts')).toBe(true)
})
it('should throw error', async () => {
// @ts-ignore mock feature
jest.spyOn(ejs, 'renderFile').mockImplementationOnce((a, b, c) => c('test error', null))
vi.mocked(ejs.renderFile).mockImplementationOnce((a, b, c) => c('test error', null))
try {
await renderConfigurationFile({ foo: 'bar' } as any)
@ -340,8 +347,9 @@ describe('addServiceDeps', () => {
})
it('should not add appium if globally installed', () => {
// @ts-ignore mock feature
childProcess.execSyncRes = '1.13.0'
// @ts-ignore
// eslint-disable-next-line no-import-assign, @typescript-eslint/no-unused-vars
execSyncRes = '1.13.0'
const packages: any = []
addServiceDeps([{ package: '@wdio/appium-service', short: 'appium' }], packages)
expect(packages).toEqual([])
@ -370,7 +378,7 @@ describe('addServiceDeps', () => {
})
afterEach(() => {
(global.console.log as jest.Mock).mockClear()
vi.mocked(global.console.log).mockClear()
})
})
@ -404,7 +412,8 @@ describe('getCapabilities', () => {
})
it('should return driver with capabilities for ios', () => {
expect(getCapabilities({ option: 'foo.app', deviceName: 'fooName', udid: 'num', platformVersion: 'fooNum' } as any)).toMatchSnapshot()
expect(getCapabilities({ option: 'foo.app', deviceName: 'fooName', udid: 'num', platformVersion: 'fooNum' } as any))
.toMatchSnapshot()
expect(getCapabilities({ option: 'ios' } as any)).toMatchSnapshot()
})
@ -413,7 +422,7 @@ describe('getCapabilities', () => {
})
it('should throw config not found error', () => {
const addConfigFileMock = jest.spyOn(ConfigParser.prototype, 'addConfigFile')
const addConfigFileMock = vi.spyOn(ConfigParser.prototype, 'addConfigFile')
addConfigFileMock.mockImplementationOnce(() => {
const error: any = new Error('ups')
error.code = 'MODULE_NOT_FOUND'
@ -433,15 +442,15 @@ describe('getCapabilities', () => {
it('should through capability not found', () => {
const cap = { browserName: 'chrome' }
const getCapabilitiesMock = jest.spyOn(ConfigParser.prototype, 'getCapabilities')
const getCapabilitiesMock = vi.spyOn(ConfigParser.prototype, 'getCapabilities')
getCapabilitiesMock.mockReturnValue([cap, cap, cap, cap, cap])
expect(() => getCapabilities({ option: '/path/to/config.js', capabilities: 5 } as any))
.toThrowErrorMatchingSnapshot()
})
it('should get capability from wdio.conf.js', () => {
const autoCompileMock = jest.spyOn(ConfigParser.prototype, 'autoCompile')
const getCapabilitiesMock = jest.spyOn(ConfigParser.prototype, 'getCapabilities')
const autoCompileMock = vi.spyOn(ConfigParser.prototype, 'autoCompile')
const getCapabilitiesMock = vi.spyOn(ConfigParser.prototype, 'getCapabilities')
getCapabilitiesMock.mockReturnValue([
{ browserName: 'chrome' },
{
@ -462,9 +471,9 @@ describe('getCapabilities', () => {
})
test('hasFile', () => {
(fs.existsSync as jest.Mock).mockReturnValue(true)
vi.mocked(fs.existsSync).mockReturnValue(true)
expect(hasFile('package.json')).toBe(true)
; (fs.existsSync as jest.Mock).mockReturnValue(false)
vi.mocked(fs.existsSync).mockReturnValue(false)
expect(hasFile('xyz')).toBe(false)
})
@ -475,10 +484,10 @@ test('hasPackage', () => {
describe('generateTestFiles', () => {
it('Mocha with page objects', async () => {
readDir.mockReturnValue(Promise.resolve([
vi.mocked(readDir).mockResolvedValue([
'/foo/bar/loo/page.js.ejs',
'/foo/bar/example.e2e.js'
]))
] as any)
const answers = {
framework: 'mocha',
usePageObjects: true,
@ -490,14 +499,14 @@ describe('generateTestFiles', () => {
await generateTestFiles(answers as any)
expect(readDir).toBeCalledTimes(2)
expect(readDir.mock.calls[0][0]).toContain('mocha')
expect(readDir.mock.calls[1][0]).toContain('pageobjects')
expect(vi.mocked(readDir).mock.calls[0][0]).toContain('mocha')
expect(vi.mocked(readDir).mock.calls[1][0]).toContain('pageobjects')
/**
* test readDir callback
*/
const readDirCb = readDir.mock.calls[0][1][0]
const stats = { isDirectory: jest.fn().mockReturnValue(false) }
const readDirCb = vi.mocked(readDir).mock.calls[0][1][0] as Function
const stats = { isDirectory: vi.fn().mockReturnValue(false) }
expect(readDirCb('/foo/bar.lala', stats)).toBe(true)
expect(readDirCb('/foo/bar.js.ejs', stats)).toBe(false)
expect(readDirCb('/foo/bar.feature', stats)).toBe(false)
@ -518,17 +527,17 @@ describe('generateTestFiles', () => {
expect.any(Function)
)
expect(fs.ensureDirSync).toBeCalledTimes(4)
expect((fs.promises.writeFile as jest.Mock).mock.calls[0][0].endsWith('/page/objects/model/page.js'))
expect((vi.mocked(fs.promises.writeFile).mock.calls[0][0] as string).endsWith('/page/objects/model/page.js'))
.toBe(true)
expect((fs.promises.writeFile as jest.Mock).mock.calls[1][0].endsWith('/example.e2e.js'))
expect((vi.mocked(fs.promises.writeFile).mock.calls[1][0] as string).endsWith('/example.e2e.js'))
.toBe(true)
})
it('jasmine with page objects', async () => {
readDir.mockReturnValue(Promise.resolve([
vi.mocked(readDir).mockResolvedValue([
'/foo/bar/loo/page.js.ejs',
'/foo/bar/example.e2e.js'
]))
] as any)
const answers = {
framework: 'jasmine',
usePageObjects: true,
@ -540,14 +549,14 @@ describe('generateTestFiles', () => {
await generateTestFiles(answers as any)
expect(readDir).toBeCalledTimes(2)
expect(readDir.mock.calls[0][0]).toContain('jasmine')
expect(readDir.mock.calls[1][0]).toContain('pageobjects')
expect(vi.mocked(readDir).mock.calls[0][0]).toContain('jasmine')
expect(vi.mocked(readDir).mock.calls[1][0]).toContain('pageobjects')
/**
* test readDir callback
*/
const readDirCb = readDir.mock.calls[0][1][0]
const stats = { isDirectory: jest.fn().mockReturnValue(false) }
const readDirCb = vi.mocked(readDir).mock.calls[0][1][0] as Function
const stats = { isDirectory: vi.fn().mockReturnValue(false) }
expect(readDirCb('/foo/bar.lala', stats)).toBe(true)
expect(readDirCb('/foo/bar.js.ejs', stats)).toBe(false)
expect(readDirCb('/foo/bar.feature', stats)).toBe(false)
@ -568,15 +577,16 @@ describe('generateTestFiles', () => {
expect.any(Function)
)
expect(fs.ensureDirSync).toBeCalledTimes(4)
expect((fs.promises.writeFile as jest.Mock).mock.calls[0][0].endsWith('/page/objects/model/page.js'))
expect((vi.mocked(fs.promises.writeFile).mock.calls[0][0] as string)
.endsWith('/page/objects/model/page.js'))
.toBe(true)
expect((fs.promises.writeFile as jest.Mock).mock.calls[1][0].endsWith('/example.e2e.js'))
expect((vi.mocked(fs.promises.writeFile).mock.calls[1][0] as string)
.endsWith('/example.e2e.js'))
.toBe(true)
})
it('Jasmine with page generation and no pageObjects', async () => {
readDir.mockReturnValue(Promise.resolve([
]))
vi.mocked(readDir).mockResolvedValue([] as any)
const answers = {
specs: './tests/e2e/**/*.js',
framework: 'jasmine',
@ -591,7 +601,7 @@ describe('generateTestFiles', () => {
})
it('Cucumber with page generation and no pageObjects', async () => {
readDir.mockReturnValue(Promise.resolve([]))
vi.mocked(readDir).mockResolvedValue([] as any)
const answers = {
specs: './tests/e2e/**/*.js',
framework: 'cucumber',
@ -606,10 +616,10 @@ describe('generateTestFiles', () => {
})
it('Cucumber without page objects', async () => {
readDir.mockReturnValue(Promise.resolve([
vi.mocked(readDir).mockResolvedValue([
'/foo/bar/loo/step_definition/example.step.js',
'/foo/bar/example.feature'
]))
] as any)
const answers = {
specs: './tests/e2e/*.js',
framework: 'cucumber',
@ -620,7 +630,7 @@ describe('generateTestFiles', () => {
await generateTestFiles(answers as any)
expect(readDir).toBeCalledTimes(1)
expect(readDir.mock.calls[0][0]).toContain('cucumber')
expect(vi.mocked(readDir).mock.calls[0][0]).toContain('cucumber')
expect(ejs.renderFile).toBeCalledTimes(2)
expect(ejs.renderFile).toBeCalledWith(
'/foo/bar/loo/step_definition/example.step.js',
@ -636,11 +646,11 @@ describe('generateTestFiles', () => {
})
it('Cucumber with page objects and TypeScript', async () => {
readDir.mockReturnValue(Promise.resolve([
vi.mocked(readDir).mockResolvedValue([
'/foo/bar/loo/page.js.ejs',
'/foo/bar/loo/step_definition/example.step.js',
'/foo/bar/example.feature'
]))
] as any)
const answers = {
framework: 'cucumber',
usePageObjects: true,
@ -652,7 +662,7 @@ describe('generateTestFiles', () => {
await generateTestFiles(answers as any)
expect(readDir).toBeCalledTimes(2)
expect(readDir.mock.calls[0][0]).toContain('cucumber')
expect(vi.mocked(readDir).mock.calls[0][0]).toContain('cucumber')
expect(ejs.renderFile).toBeCalledTimes(6)
expect(ejs.renderFile).toBeCalledWith(
'/foo/bar/loo/step_definition/example.step.js',
@ -665,9 +675,9 @@ describe('generateTestFiles', () => {
expect.any(Function)
)
expect(fs.ensureDirSync).toBeCalledTimes(6)
expect((fs.promises.writeFile as jest.Mock).mock.calls[0][0].endsWith('/some/page/objects/page.ts'))
expect((vi.mocked(fs.promises.writeFile).mock.calls[0][0] as string).endsWith('/some/page/objects/page.ts'))
.toBe(true)
expect((fs.promises.writeFile as jest.Mock).mock.calls[2][0].endsWith('/example.feature'))
expect((vi.mocked(fs.promises.writeFile).mock.calls[2][0] as string).endsWith('/example.feature'))
.toBe(true)
})
})
@ -751,9 +761,9 @@ test('getDefaultFiles', () => {
})
afterEach(() => {
(console.log as jest.Mock).mockRestore()
readDir.mockClear()
; (fs.promises.writeFile as jest.Mock).mockClear()
; (fs.ensureDirSync as jest.Mock).mockClear()
; (ejs.renderFile as jest.Mock).mockClear()
vi.mocked(console.log).mockRestore()
vi.mocked(readDir).mockClear()
vi.mocked(fs.promises.writeFile).mockClear()
vi.mocked(fs.ensureDirSync).mockClear()
vi.mocked(ejs.renderFile).mockClear()
})

View file

@ -1,3 +1,4 @@
import { vi, describe, it, expect, afterEach } from 'vitest'
import path from 'node:path'
import chokidar from 'chokidar'
import EventEmitter from 'node:events'
@ -6,8 +7,12 @@ import type { Workers } from '@wdio/types'
import { RunCommandArguments } from '../src/types'
import Watcher from '../src/watcher'
jest.mock('../src/launcher', () => {
const { ConfigParser } = require('@wdio/config')
vi.mock('chokidar')
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))
vi.mock('@wdio/config', () => import(path.join(process.cwd(), '__mocks__', '@wdio/config')))
vi.mock('@wdio/utils', () => import(path.join(process.cwd(), '__mocks__', '@wdio/utils')))
vi.mock('../src/launcher', async () => {
const { ConfigParser } = await import('@wdio/config')
interface LauncherMockRunCommandArguments extends Omit<RunCommandArguments, 'configPath'> {
isMultiremote?: boolean;
@ -28,12 +33,12 @@ jest.mock('../src/launcher', () => {
this.isMultiremote = args.isMultiremote || false
this.runner = {}
this.interface = {
emit: jest.fn(),
setup: jest.fn()
emit: vi.fn(),
setup: vi.fn()
}
}
}
return LauncherMock
return { default: LauncherMock }
})
interface WorkerMockRunPayload extends Partial<Workers.WorkerRunPayload> {
@ -49,7 +54,7 @@ class WorkerMock extends EventEmitter implements Workers.Worker {
capabilities: WebDriver.DesiredCapabilities
sessionId: string
isBusy: boolean
postMessage = jest.fn()
postMessage = vi.fn()
constructor ({ cid, specs, sessionId, isBusy = false }: WorkerMockRunPayload) {
super()
@ -59,7 +64,7 @@ class WorkerMock extends EventEmitter implements Workers.Worker {
this.capabilities = this.caps
this.sessionId = sessionId || `${Math.random()}`
this.isBusy = isBusy
this.on = jest.fn()
this.on = vi.fn()
}
}
@ -85,12 +90,12 @@ describe('watcher', () => {
const wdioConf = path.join(__dirname, '__fixtures__', 'wdio.conf')
const watcher = new Watcher(wdioConf, {})
watcher['_launcher'] = {
run: jest.fn(),
run: vi.fn(),
interface: {
finalise: jest.fn()
finalise: vi.fn()
},
configParser: {
getConfig: jest.fn().mockReturnValue({ filesToWatch: [] })
getConfig: vi.fn().mockReturnValue({ filesToWatch: [] })
},
runner: {
workerPool: {
@ -107,12 +112,12 @@ describe('watcher', () => {
const wdioConf = path.join(__dirname, '__fixtures__', 'wdio.conf')
const watcher = new Watcher(wdioConf, {})
watcher['_launcher'] = {
run: jest.fn(),
run: vi.fn(),
interface: {
finalise: jest.fn()
finalise: vi.fn()
},
configParser: {
getConfig: jest.fn().mockReturnValue({ filesToWatch: [] })
getConfig: vi.fn().mockReturnValue({ filesToWatch: [] })
},
runner: {
workerPool: {
@ -129,12 +134,12 @@ describe('watcher', () => {
const wdioConf = path.join(__dirname, '__fixtures__', 'wdio.conf')
const watcher = new Watcher(wdioConf, {})
watcher['_launcher'] = {
run: jest.fn(),
run: vi.fn(),
interface: {
finalise: jest.fn()
finalise: vi.fn()
},
configParser: {
getConfig: jest.fn().mockReturnValue({ filesToWatch: ['/foo/bar'] })
getConfig: vi.fn().mockReturnValue({ filesToWatch: ['/foo/bar'] })
},
runner: {
workerPool: {
@ -146,7 +151,7 @@ describe('watcher', () => {
expect(chokidar.watch).toHaveBeenCalledTimes(2)
const worker = watcher['_launcher'].runner.workerPool['0-0']
const worker = watcher['_launcher'].runner!.workerPool['0-0']
expect(worker.on).toBeCalledTimes(1)
const eventHandler = worker.on.mock.calls[0][1]
@ -163,12 +168,12 @@ describe('watcher', () => {
const wdioConf = path.join(__dirname, '__fixtures__', 'wdio.conf')
const watcher = new Watcher(wdioConf, {})
watcher['_launcher'] = {
run: jest.fn(),
run: vi.fn(),
interface: {
finalise: jest.fn()
finalise: vi.fn()
},
configParser: {
getConfig: jest.fn().mockReturnValue({ filesToWatch: ['/foo/bar'] })
getConfig: vi.fn().mockReturnValue({ filesToWatch: ['/foo/bar'] })
},
runner: {
workerPool: {
@ -176,17 +181,17 @@ describe('watcher', () => {
}
}
} as any
watcher.run = jest.fn()
watcher.run = vi.fn()
await watcher.watch()
// @ts-ignore mock feature
;(chokidar.on as jest.Mock).mock.calls[0][1]('/some/path.js')
vi.mocked(chokidar.on).mock.calls[0][1]('/some/path.js')
// @ts-ignore mock feature
;(chokidar.on as jest.Mock).mock.calls[1][1]('/some/other/path.js')
vi.mocked(chokidar.on).mock.calls[1][1]('/some/other/path.js')
// @ts-ignore mock feature
;(chokidar.on as jest.Mock).mock.calls[2][1]('/some/another/path.js')
vi.mocked(chokidar.on).mock.calls[2][1]('/some/another/path.js')
// @ts-ignore mock feature
;(chokidar.on as jest.Mock).mock.calls[3][1]('/some/another/path.js')
vi.mocked(chokidar.on).mock.calls[3][1]('/some/another/path.js')
expect(watcher.run).toHaveBeenNthCalledWith(1, { spec: '/some/path.js' })
expect(watcher.run).toHaveBeenNthCalledWith(2, { spec: '/some/other/path.js' })
expect(watcher.run).toHaveBeenNthCalledWith(3, {})
@ -201,7 +206,7 @@ describe('watcher', () => {
'0-1': new WorkerMock({ cid: '0-1', specs: ['/foo/bar2.js'], isBusy: true }),
'1-0': new WorkerMock({ cid: '1-0', specs: ['/bar/foo.js'] })
}
watcher['_launcher'].runner.workerPool = workerPool
watcher['_launcher'].runner!.workerPool = workerPool
expect(watcher.getWorkers(null, true)).toEqual(workerPool)
expect(watcher.getWorkers()).toEqual({
@ -216,14 +221,14 @@ describe('watcher', () => {
it('should run workers on existing session', () => {
const wdioConf = path.join(__dirname, '__fixtures__', 'wdio.conf')
const watcher = new Watcher(wdioConf, {})
watcher['_launcher'].runner.workerPool = {
watcher['_launcher'].runner!.workerPool = {
// @ts-ignore mock feature
'0-0': new WorkerMock({ cid: '0-0', specs: ['/foo/bar.js'] }),
'0-1': new WorkerMock({ cid: '0-1', specs: ['/foo/bar2.js'], isBusy: true }),
// @ts-ignore mock feature
'1-0': new WorkerMock({ cid: '1-0', specs: ['/bar/foo.js'] })
}
watcher['_launcher'].interface.emit = jest.fn()
watcher['_launcher'].interface.emit = vi.fn()
watcher.run({ spec: '/foo/bar.js' } as any)
expect(watcher['_launcher'].interface.emit).toHaveBeenCalledWith('job:start', {
cid: '0-0',
@ -231,7 +236,7 @@ describe('watcher', () => {
specs: ['/foo/bar.js']
})
const { postMessage, sessionId } = watcher['_launcher'].runner.workerPool['0-0']
const { postMessage, sessionId } = watcher['_launcher'].runner!.workerPool['0-0']
expect(postMessage).toHaveBeenCalledWith('run', { sessionId, spec: '/foo/bar.js' })
expect(watcher['_launcher'].interface.totalWorkerCnt).toBe(1)
})
@ -239,14 +244,14 @@ describe('watcher', () => {
it('should not clean if no watcher is running', () => {
const wdioConf = path.join(__dirname, '__fixtures__', 'wdio.conf')
const watcher = new Watcher(wdioConf, {})
watcher['_launcher'].runner.workerPool = {
watcher['_launcher'].runner!.workerPool = {
// @ts-ignore mock feature
'0-0': new WorkerMock({ cid: '0-0', specs: ['/foo/bar.js'] }),
'0-1': new WorkerMock({ cid: '0-1', specs: ['/foo/bar2.js'], isBusy: true }),
// @ts-ignore mock feature
'1-0': new WorkerMock({ cid: '1-0', specs: ['/bar/foo.js'] })
}
watcher['_launcher'].interface.emit = jest.fn()
watcher['_launcher'].interface.emit = vi.fn()
watcher.run({ spec: '/foo/bar2.js' } as any)
expect(watcher['_launcher'].interface.emit).toHaveBeenCalledTimes(0)
})
@ -255,8 +260,8 @@ describe('watcher', () => {
const wdioConf = path.join(__dirname, '__fixtures__', 'wdio.conf')
const watcher = new Watcher(wdioConf, {})
watcher['_launcher'].interface.totalWorkerCnt = 1
watcher.cleanUp = jest.fn()
watcher['_launcher'].runner.workerPool = {
watcher.cleanUp = vi.fn()
watcher['_launcher'].runner!.workerPool = {
// @ts-ignore mock feature
'0-0': new WorkerMock({ cid: '0-0', specs: ['/foo/bar.js'] }),
'0-1': new WorkerMock({ cid: '0-1', specs: ['/foo/bar2.js'], isBusy: true }),
@ -267,7 +272,7 @@ describe('watcher', () => {
expect(watcher['_launcher'].interface.totalWorkerCnt).toBe(2)
const worker00 = watcher['_launcher'].runner.workerPool['0-0']
const worker00 = watcher['_launcher'].runner!.workerPool['0-0']
expect(worker00.postMessage).toHaveBeenCalledWith(
'run',
{ sessionId: worker00.sessionId })
@ -276,7 +281,7 @@ describe('watcher', () => {
caps: { browserName: 'chrome' },
specs: ['/foo/bar.js'] })
const worker10 = watcher['_launcher'].runner.workerPool['0-0']
const worker10 = watcher['_launcher'].runner!.workerPool['0-0']
expect(worker10.postMessage).toHaveBeenCalledWith(
'run',
{ sessionId: worker10.sessionId })
@ -294,13 +299,13 @@ describe('watcher', () => {
const watcher = new Watcher(wdioConf, {})
watcher['_launcher'] = {
__args: { spec },
run: jest.fn(),
run: vi.fn(),
interface: {
emit: jest.fn(),
finalise: jest.fn()
emit: vi.fn(),
finalise: vi.fn()
},
configParser: {
getConfig: jest.fn().mockReturnValue({ filesToWatch })
getConfig: vi.fn().mockReturnValue({ filesToWatch })
},
runner: {
workerPool: {
@ -309,31 +314,31 @@ describe('watcher', () => {
}
}
} as any
const runSpy = jest.spyOn(watcher, 'run')
const runSpy = vi.spyOn(watcher, 'run')
const emitSpy = watcher['_launcher'].interface.emit
watcher.cleanUp = jest.fn()
watcher.cleanUp = vi.fn()
await watcher.watch()
// @ts-ignore mock feature
;(chokidar.on as jest.Mock).mock.calls[0][1](spec[0])
vi.mocked(chokidar.on).mock.calls[0][1](spec[0])
expect(runSpy).toHaveBeenNthCalledWith(1, { spec: spec[0] })
expect(emitSpy).toHaveBeenCalledTimes(1) // Only one Worker called
;(emitSpy as jest.Mock).mockClear()
vi.mocked(emitSpy).mockClear()
// @ts-ignore mock feature
;(chokidar.on as jest.Mock).mock.calls[1][1](someOtherExcludedPath)
vi.mocked(chokidar.on).mock.calls[1][1](someOtherExcludedPath)
expect(runSpy).toHaveBeenNthCalledWith(2, { spec: someOtherExcludedPath })
expect(emitSpy).not.toHaveBeenCalled() // No Workers called
;(emitSpy as jest.Mock).mockClear()
vi.mocked(emitSpy).mockClear()
// @ts-ignore mock feature
;(chokidar.on as jest.Mock).mock.calls[2][1](filesToWatch[0])
vi.mocked(chokidar.on).mock.calls[2][1](filesToWatch[0])
expect(runSpy).toHaveBeenNthCalledWith(3, {})
expect(emitSpy).toHaveBeenCalledTimes(2) // Both Workers called
;(emitSpy as jest.Mock).mockClear()
vi.mocked(emitSpy).mockClear()
// @ts-ignore mock feature
;(chokidar.on as jest.Mock).mock.calls[3][1](filesToWatch[0])
vi.mocked(chokidar.on).mock.calls[3][1](filesToWatch[0])
expect(runSpy).toHaveBeenNthCalledWith(4, {})
expect(emitSpy).toHaveBeenCalledTimes(2) // Both Workers called
})
@ -347,52 +352,52 @@ describe('watcher', () => {
// @ts-ignore
watcher['_launcher'] = {
__args: { spec },
run: jest.fn(),
run: vi.fn(),
interface: {
emit: jest.fn(),
finalise: jest.fn()
emit: vi.fn(),
finalise: vi.fn()
},
configParser: {
getConfig: jest.fn().mockReturnValue({ filesToWatch })
getConfig: vi.fn().mockReturnValue({ filesToWatch })
},
runner: {
workerPool: {
'0-0': new WorkerMock({ cid: '0-0', specs: [spec[0]] }),
'0-1': new WorkerMock({ cid: '0-1', specs: [spec[1]] })
'0-0': new WorkerMock({ cid: '0-0', specs: [spec[0] as any] }),
'0-1': new WorkerMock({ cid: '0-1', specs: [spec[1] as any] })
}
}
} as any
const runSpy = jest.spyOn(watcher, 'run')
const runSpy = vi.spyOn(watcher, 'run')
const emitSpy = watcher['_launcher'].interface.emit
watcher.cleanUp = jest.fn()
watcher.cleanUp = vi.fn()
await watcher.watch()
// @ts-ignore mock feature
;(chokidar.on as jest.Mock).mock.calls[0][1](spec[0])
vi.mocked(chokidar.on).mock.calls[0][1](spec[0])
expect(runSpy).toHaveBeenNthCalledWith(1, { spec: spec[0] })
expect(emitSpy).toHaveBeenCalledTimes(1) // Only one Worker called
;(emitSpy as jest.Mock).mockClear()
vi.mocked(emitSpy).mockClear()
// @ts-ignore mock feature
;(chokidar.on as jest.Mock).mock.calls[1][1](someOtherExcludedPath)
vi.mocked(chokidar.on).mock.calls[1][1](someOtherExcludedPath)
expect(runSpy).toHaveBeenNthCalledWith(2, { spec: someOtherExcludedPath })
expect(emitSpy).not.toHaveBeenCalled() // No Workers called
;(emitSpy as jest.Mock).mockClear()
vi.mocked(emitSpy).mockClear()
// @ts-ignore mock feature
;(chokidar.on as jest.Mock).mock.calls[2][1](filesToWatch[0])
vi.mocked(chokidar.on).mock.calls[2][1](filesToWatch[0])
expect(runSpy).toHaveBeenNthCalledWith(3, {})
expect(emitSpy).toHaveBeenCalledTimes(2) // Both Workers called
;(emitSpy as jest.Mock).mockClear()
vi.mocked(emitSpy).mockClear()
// @ts-ignore mock feature
;(chokidar.on as jest.Mock).mock.calls[3][1](filesToWatch[0])
vi.mocked(chokidar.on).mock.calls[3][1](filesToWatch[0])
expect(runSpy).toHaveBeenNthCalledWith(4, {})
expect(emitSpy).toHaveBeenCalledTimes(2) // Both Workers called
})
afterEach(() => {
(chokidar.watch as jest.Mock).mockClear()
vi.mocked(chokidar.watch).mockClear()
// @ts-ignore mock feature
chokidar.on.mockClear()
})

View file

@ -10,7 +10,6 @@ export default defineConfig({
'dist', '.idea', '.git', '.cache',
'**/node_modules/**',
'packages/eslint-plugin-wdio/**/*',
'packages/wdio-cli/**/*.test.ts',
'packages/webdriverio/**/*.test.ts',
'packages/wdio-jasmine-framework/**/*.test.ts'
],