breaking(build): migrate to Esbuild for bundling (#13338)

* breaking(build): migrate to Rollup for bundling

* migrate more packages

* progress

* delete unnecessary tsconfigs

* migrate to esbuild

* revert npmignore changes

* more tweaks

* update pnpm-lock

* more tweaks

* compile scripts within browser environment

* fix ts issue in webdriverio

* add infra/compiler to readme

* fix lock file

* remove virtual:wdio from lock file

* update docs

* fix tests

* fix component tests

* fix unit tests

* clean up

* remove original build script

* more cleanups

* more cleanups

* last cleanup
This commit is contained in:
Christian Bromann 2024-08-08 23:47:30 -07:00 committed by GitHub
parent 4e349a2d2c
commit 80779bb429
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
164 changed files with 2221 additions and 1792 deletions

View file

@ -5,6 +5,5 @@
/packages/**/coverage
/tests/typings
*.d.ts
!packages/**/src/cjs
packages/wdio-protocols/src/protocols/webdriverBidi.ts
packages/webdriverio/third_party/fake-timers.js

View file

@ -21,10 +21,6 @@ jobs:
env:
GITHUB_AUTH: ${{ secrets.GITHUB_TOKEN }}
- name: 🏗️ Generate Typings
run: pnpm run generate:typings
shell: bash
- name: ⬆️ Upload Build Artifacts
uses: ./.github/workflows/actions/upload-archive
with:

View file

@ -62,7 +62,6 @@ jobs:
- name: Release
run: |
pnpm run setup
pnpm run generate:typings
pnpm lerna publish ${{github.event.inputs.releaseType}} --exact --yes --dist-tag ${{github.event.inputs.distTag}}
pnpm run pushReleaseTag
env:

View file

@ -142,13 +142,9 @@ You can immediately start working on the code using [a pre-setup Gitpod environm
If you have compiled the code this command will remove them as well as all dependencies of the subpackages.
* Bootstraps sub-projects via ```pnpm run bootstrap```
* Compiles the project ```pnpm run compile:all```
Many packages depend on each other, in order to properly set up the dependency tree you need to run the [Lerna Bootstrap](https://github.com/lerna/lerna#bootstrap) command to create all necessary links. As this project also does some other house keeping tasks, it is recommended to use the package bootstrap command.
* Builds all subpackages via ```pnpm run build```
As the last step you need to build all sub-packages in order to resolve the internal dependencies. WebdriverIO uses [TypeScript](https://www.typescriptlang.org/) as a compiler.
As the last step you need to build all sub-packages in order to resolve the internal dependencies. WebdriverIO uses [`@wdio/compiler`](https://github.com/webdriverio/webdriverio/tree/main/infa/compiler) which is an internal package that uses Esbuild to compile the project.
* Run Tests to ensure that everything is set up correctly
@ -195,13 +191,7 @@ All type definitions are generated by the TypeScript compiler. There are some es
- the `@wdio/protocol` package defines all protocol commands, their function parameters and return types
- all other types should be defined in the package where they are used, here we tend to have general types defined in a `types.ts` file
You can find all files responsible for the generating the typings [here](https://github.com/webdriverio/webdriverio/tree/main/scripts/type-generation). You can trigger the process by calling:
```sh
npm run generate:typings
```
This will run the scripts in the directory shown above and generate the typings for all protocol commands. Whenever you change those [protocol commands](https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-protocols/src/protocols), make sure you re-generate the types with the command shown above.
The protocol types are generated as part of the `@wdio/compiler` build command and is part of the [`generate-types`](https://github.com/webdriverio/webdriverio/blob/main/infra/compiler/src/type-generation/index.ts#L27-L35) plugin.
### Test Changes

View file

@ -139,6 +139,12 @@ __Did you build a WebdriverIO service or reporter?__ That's awesome! Please add
- [@wdio/smoke-test-service](https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-smoke-test-service) - A WebdriverIO utility to smoke test services for internal testing purposes
- [@wdio/webdriver-mock-service](https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-webdriver-mock-service) - A WebdriverIO service to stub all endpoints for internal testing purposes
### Infrastructure Packages
These packages are not released to NPM and used to work on this codebase.
- [@wdio/compiler](https://github.com/webdriverio/webdriverio/tree/main/infa/compiler) - Esbuild script to compile the source code all of all packages
## :handshake: Project Governance
This project is maintained by [awesome people](/AUTHORS.md) following a common [set of rules](/GOVERNANCE.md) and treating each other with [respect and appreciation](/CODE_OF_CONDUCT.md).

View file

@ -41,3 +41,22 @@ exports[`snapshot testing > of objects 3`] = `
"foo": "bar",
}
`;
exports[`snapshot testing > of objects 5`] = `
{
"parsed": {
"alpha": 0,
"hex": "#000000",
"rgba": "rgba(0,0,0,0)",
"type": "color",
},
"property": "background-color",
"value": "rgba(0,0,0,0)",
}
`;
exports[`snapshot testing > of objects 7`] = `
{
"foo": "bar",
}
`;

View file

@ -76,6 +76,6 @@
"preact": "^10.19.3",
"react": "^18.2.0",
"svelte": "^4.2.9",
"vue": "^3.4.15"
"vue": "^3.4.37"
}
}

32
infra/compiler/README.md Normal file
View file

@ -0,0 +1,32 @@
# WebdriverIO Build Tool
This sub-package is being used to build WebdriverIO. It uses [Esbuild](https://esbuild.github.io) to bundle the packages.
## Usage
In order to use this package run:
```sh
pnpm -r --filter=@wdio/build run build
```
## Options
You can pass in the following options to customize the build command.
### `-p` / `--project`
With this argument you can specify which sub package in `<root>/packages` will be build. It accepts either the NPM package name or the directory name. If you omit this parameter the tool will try to build all packages. You can pass in one or multiple packages, e.g.
```sh
$ pnpm -r --filter=@wdio/build run build -p webdriverio -p @wdio/logger -p wdio-globals
```
### `--watch`
If you pass in this flag, the build task will run within a "watch" context and will continue to run and rebuild individual changes when changes are being made, e.g.
```sh
# watch changes in logger package
$ pnpm -r --filter=@wdio/build run build -p @wdio/logger --watch
```

View file

@ -0,0 +1,16 @@
{
"name": "@wdio/compiler",
"private": true,
"type": "module",
"scripts": {
"build": "tsx ./src/index.ts"
},
"dependencies": {
"esbuild": "^0.23.0",
"esbuild-plugin-copy": "^2.1.1",
"esbuild-plugin-d.ts": "^1.3.0",
"camelcase": "^8.0.0",
"tsx": "^4.17.0",
"type-fest": "^4.24.0"
}
}

227
infra/compiler/src/index.ts Normal file
View file

@ -0,0 +1,227 @@
import fs from 'node:fs/promises'
import path from 'node:path'
import url from 'node:url'
import { parseArgs } from 'node:util'
import { build, context, type BuildOptions, type Plugin } from 'esbuild'
import type { PackageJson } from 'type-fest'
import { getExternal } from './utils.js'
import { log, clear, generateDts, copyEJSTemplates, externalScripts } from './plugins.js'
import { generateTypes } from './type-generation/index.js'
const __dirname = path.dirname(url.fileURLToPath(import.meta.url))
const rootDir = path.resolve(__dirname, '..', '..', '..')
const args = process.argv.slice(2)
const options = {
project: {
type: 'string',
short: 'p',
multiple: true,
},
watch: {
type: 'boolean',
},
clear: {
type: 'boolean'
}
} as const
const { values } = parseArgs({ args, options })
/**
* parse through all packages and filter based on command parameters
*/
const projects = (await fs.readdir(
path.resolve(rootDir, 'packages')
)).filter((dir) => dir !== 'node_modules')
const packages = (
await Promise.all(
projects.map(async (project) => {
const pkg = await import(path.resolve(rootDir, 'packages', project, 'package.json'), { assert: { type: 'json' } })
return [project, pkg.default]
})
) as [string, PackageJson][]
).filter(([packageDir, pkg]) => (
!values.project ||
(pkg.name && values.project.includes(pkg.name)) ||
values.project.includes(packageDir)
))
/**
* plugins for the ESM build
*/
const esmPlugins: Record<string, Plugin[]> = {
'@wdio/protocols': [generateTypes()],
'@wdio/cli': [copyEJSTemplates()],
'webdriverio': [externalScripts()]
}
/**
* plugins for the cjs build
*/
const cjsPlugins: Record<string, Plugin[]> = {}
/**
* plugins for the browser build
*/
const browserPlugins: Record<string, Plugin[]> = {}
/**
* compose Esbuild configs
*/
const configs = packages.map(([packageDir, pkg]) => {
const packageBuilds: BuildOptions[] = []
const exports = (pkg.exports || {}) as PackageJson.ExportConditions
if (!pkg.name) {
throw new Error(`Package in ${packageDir} does not have a "name" field, which is required to build the package`)
}
/**
* in cases where we don't have an exports field but a main field
* we assume that the main field is the main entry point of the package
*/
if (!pkg.exports && pkg.main) {
exports['.'] = {
require: pkg.main
}
}
const exportedModules = Object.entries(exports).filter?.(([, exp]) => typeof exp === 'object' && !Array.isArray(exp)) as [string, PackageJson.ExportConditions][]
for (const [target, exp] of exportedModules) {
const absWorkingDir = path.resolve(rootDir, 'packages', packageDir)
const source = (exp.source as string | undefined) || './src/index.ts'
const baseConfig: BuildOptions = {
sourceRoot: absWorkingDir,
tsconfig: path.resolve(absWorkingDir, 'tsconfig.json'),
sourcemap: process.env.NODE_ENV !== 'production',
external: getExternal(pkg),
target: 'node18',
bundle: true,
absWorkingDir
}
if (typeof exp.import === 'string') {
const esmSource = (exp.importSource as string | undefined) || source
const esmBuild: BuildOptions = {
...baseConfig,
entryPoints: [path.resolve(absWorkingDir, esmSource)],
platform: 'node',
format: 'esm',
plugins: []
}
if (exp.import.endsWith('*')) {
esmBuild.outdir = path.resolve(absWorkingDir, path.dirname(exp.import))
} else {
esmBuild.outfile = path.resolve(absWorkingDir, exp.import)
}
esmBuild.plugins?.push(
log(esmBuild, pkg),
...(esmPlugins[pkg.name] || [])
)
/**
* if types field is a string, generate TypeScript declarations
*/
if (typeof exp.types === 'string' && target === '.') {
esmBuild.plugins?.push(generateDts(absWorkingDir))
}
if (values.clear) {
esmBuild.plugins?.push(clear(esmBuild))
}
packageBuilds.push(esmBuild)
}
if (typeof exp.require === 'string') {
const requireSource = (exp.requireSource as string | undefined) || source
const cjsBuild: BuildOptions = {
...baseConfig,
external: getExternal(pkg),
entryPoints: [path.resolve(absWorkingDir, requireSource)],
platform: 'node',
format: 'cjs',
plugins: [],
banner: {
'js': 'const __importMetaUrl = require(\'url\').pathToFileURL(__filename).href;'
},
define: {
'import.meta.url': '__importMetaUrl',
'import.meta.resolve': 'require.resolve'
}
}
if (exp.require.endsWith('*')) {
cjsBuild.outdir = path.resolve(absWorkingDir, path.dirname(exp.require))
} else {
cjsBuild.outfile = path.resolve(absWorkingDir, exp.require)
}
/**
* if we define an `index.cts` as require source it is suppose to be a small wrapper
* around the main source file that exports the main source file within the CJS context,
* hence we need to mark this export as external
*/
if (requireSource.endsWith('.cts')) {
cjsBuild.external?.push('./index.js')
}
cjsBuild.plugins?.push(
log(cjsBuild, pkg),
...(cjsPlugins[pkg.name] || [])
)
packageBuilds.push(cjsBuild)
}
if (typeof exp.browser === 'string') {
const browserSource = (exp.browserSource as string | undefined) || source
const browserBuild: BuildOptions = {
...baseConfig,
entryPoints: [path.resolve(absWorkingDir, browserSource)],
platform: 'browser',
format: 'esm',
target: ['es2021', 'chrome90', 'edge90', 'firefox90', 'safari12'],
plugins: [],
supported: {
'top-level-await': true //browsers can handle top-level-await features
}
}
if (exp.browser.endsWith('*')) {
browserBuild.outdir = path.resolve(absWorkingDir, path.dirname(exp.browser))
} else {
browserBuild.outfile = path.resolve(absWorkingDir, exp.browser)
}
browserBuild.plugins?.push(
log(browserBuild, pkg),
...(browserPlugins[pkg.name] || [])
)
packageBuilds.push(browserBuild)
}
}
return packageBuilds
}).flat()
if (configs.length === 0) {
throw new Error(`No packages found to build using params: ${JSON.stringify(values)}`)
}
/**
* build packages
*/
await Promise.all(configs.map(async (config) => {
if (values.watch) {
const ctx = await context(config)
return ctx.watch()
}
const result = await build(config)
if (result.errors.length > 0) {
console.error(result.errors)
throw new Error('Failed to build packages')
}
}))

View file

@ -0,0 +1,116 @@
import cp from 'node:child_process'
import url from 'node:url'
import path from 'node:path'
import { rimraf } from 'rimraf'
import { copy } from 'esbuild-plugin-copy'
import type { Plugin, BuildOptions } from 'esbuild'
import type { PackageJson } from 'type-fest'
const __dirname = path.dirname(url.fileURLToPath(import.meta.url))
/**
* little logger plugin for Esbuild
* @param {BuildOptions} options Esbuild options
* @param {PackageJson} pkg package.json of given project as object
* @returns
*/
export function log(options: BuildOptions, pkg: PackageJson): Plugin {
const srcFile = path.relative(options.absWorkingDir || process.cwd(), (options.entryPoints as string[])[0])
const outFile = path.relative(options.absWorkingDir || process.cwd(), options.outfile || options.outdir as string)
return {
name: 'LogPlugin',
setup(build) {
build.onStart(() => {
console.log(`🏗️ Building "${pkg.name}" for ${options.format}: ${srcFile} → ${outFile}`)
})
build.onEnd((result) => {
if (result.errors.length === 0) {
console.log(`✅ Success building "${pkg.name}" for ${options.format}: ${srcFile} → ${outFile}`)
}
})
}
}
}
/**
* clear previously generated build files
* @param {string} outfile directory that Esbuild usually compiles to
* @returns an Esbuild plugin
*/
export function clear(config: BuildOptions): Plugin {
const rimrafOptions = { maxRetries: 1 }
const outfile = config.outfile || config.outdir
if (!outfile) {
throw new Error('No outfile defined')
}
return {
name: 'ClearPlugin',
async setup() {
await Promise.all([
rimraf(path.dirname(outfile), rimrafOptions),
])
}
}
}
/**
* generate type definition files (d.ts) for working dir
* @param {string} absWorkingDir absolute path to the working directory
* @returns an Esbuild plugin
*/
export function generateDts(absWorkingDir: string): Plugin {
return {
name: 'TypeScriptDeclarationsPlugin',
setup(build) {
build.onEnd((result) => {
if (result.errors.length > 0) {
return
}
try {
cp.execSync('tsc --emitDeclarationOnly', {
cwd: absWorkingDir,
stdio: 'inherit'
})
} catch {
console.log('Failed to generate TypeScript declarations')
}
})
}
}
}
/**
* Plugin to copy EJS templates from the `@wdio/cli` package to build directory
* @returns {Plugin} an Esbuild plugin
*/
export function copyEJSTemplates () {
const cliPackage = path.resolve(__dirname, '..', '..', 'packages', 'wdio-cli')
return copy({
resolveFrom: cliPackage,
assets: [{
from: [path.resolve(cliPackage, 'src', 'templates', '**', '*.ejs')],
to: path.resolve(cliPackage, 'build', 'templates')
}]
})
}
/**
* Plugin to mark all WebdriverIO scripts in `packages/webdriverio/src/scripts` as external
*/
export function externalScripts(): Plugin {
const name = 'ExternalScripts'
return {
name,
setup(build) {
build.onResolve({ filter: /\/scripts\// }, (args) => {
return {
path: args.path.replace('../../', './'),
external: true,
pluginName: name
}
})
}
}
}

View file

@ -0,0 +1,130 @@
#!/usr/bin/env node
import fs from 'node:fs'
import url from 'node:url'
import path from 'node:path'
import camelCase from 'camelcase'
import { type Plugin } from 'esbuild'
import { paramTypeMap, returnTypeMap } from './constants.js'
import { PROTOCOLS } from '../../../../scripts/protocols.js'
const __dirname = path.dirname(url.fileURLToPath(import.meta.url))
const TYPINGS_PATH = path.join(__dirname, '..', '..', '..', '..', 'packages', 'wdio-protocols', 'src', 'commands')
const INDENTATION = ' '.repeat(4)
const EXAMPLE_INDENTATION = `${INDENTATION} * `
const DEPRECATED_INDENTATION = `\n${INDENTATION} * @deprecated`
const jsDocTemplate = `
${INDENTATION}/**
${INDENTATION} * {PROTOCOL} Protocol Command
${INDENTATION} *
${INDENTATION} * {DESCRIPTION}
${INDENTATION} * @ref {REF}
${INDENTATION} *{EXAMPLE}
${INDENTATION} */`
export function generateTypes (): Plugin {
return {
name: 'generate-types',
setup (build) {
build.onStart(() => generate())
}
}
}
function generate () {
/**
* create directory if not existing
*/
if (!fs.existsSync(TYPINGS_PATH)) {
fs.mkdirSync(TYPINGS_PATH)
}
for (const [protocolName, definition] of Object.entries(PROTOCOLS)) {
if (protocolName === 'webdriverBidi') {
continue
}
const interfaceName = protocolName.slice(0, 1).toUpperCase() + protocolName.slice(1)
const customTypes = new Set()
const lines = ['']
lines.push(`// ${protocolName} types`)
lines.push(`export default interface ${interfaceName}Commands {`)
for (const methods of Object.values(definition)) {
for (const description of Object.values(methods)) {
const { command, parameters = [], variables = [], returns, ref, deprecated, examples } = description
if (!ref) {
throw new Error(`missing ref for command ${command} in ${protocolName}`)
}
const vars = variables
// sessionId is handled by WebdriverIO for all protocol requests
.filter((v) => v.name !== 'sessionId')
// url params are always type of string
.map((v) => `${v.name}: string`)
const params = parameters.map((p, idx) => {
const hasCustomType = (
paramTypeMap[command as keyof typeof paramTypeMap] &&
paramTypeMap[command as keyof typeof paramTypeMap][idx] &&
paramTypeMap[command as keyof typeof paramTypeMap][idx].name === p.name
)
const paramType = hasCustomType
? paramTypeMap[command as keyof typeof paramTypeMap][idx].type
: p.type.toLowerCase()
if (hasCustomType && Boolean(paramTypeMap[command as keyof typeof paramTypeMap][idx].requiresImport)) {
customTypes.add(paramType)
}
return `${camelCase(p.name)}${p.required === false ? '?' : ''}: ${paramType}`
})
const varsAndParams = vars.concat(params)
let returnValue = returns ? returns.type.toLowerCase() : 'void'
returnValue = returnValue === '*' ? 'any' : returnValue
if (returnTypeMap[command as keyof typeof returnTypeMap]) {
returnValue = returnTypeMap[command as keyof typeof returnTypeMap]
customTypes.add(returnTypeMap[command as keyof typeof returnTypeMap].replace('[]', ''))
}
if (returnValue === 'object') {
returnValue = 'ProtocolCommandResponse'
customTypes.add(returnValue)
}
const jsDoc = jsDocTemplate
.replace('{PROTOCOL}', interfaceName)
.replace('{DESCRIPTION}', description.description || 'No description available, please see reference link.')
.replace('{EXAMPLE}', (
(examples || [])
.map((example) => (
`\n${EXAMPLE_INDENTATION}@example\n` +
`${EXAMPLE_INDENTATION}\`\`\`js\n` +
EXAMPLE_INDENTATION +
`${example.map((l, i) => (i === 0
? `${l}`
: `${EXAMPLE_INDENTATION}${l.replace(/(\/\*\*|\s\*\s|\s\*\/)/, '// ')}`.trimEnd())
).join('\n')}\n` +
`${EXAMPLE_INDENTATION}` + '```'
))
.join(`\n${EXAMPLE_INDENTATION}`.trim())
)
)
// Conditionally adds the '@deprecated' tag next to '{REF}' if 'deprecated' value is passed, otherwise leaves it unchanged.
.replace('{REF}', deprecated ? `{REF}${DEPRECATED_INDENTATION} ${deprecated}` : '{REF}')
.replace('{REF}', ref)
lines.push(jsDoc)
lines.push(`${INDENTATION}${command}(${varsAndParams.join(', ')}): Promise<${returnValue}>;`)
}
}
/**
* import missing protocol types
*/
if (customTypes.size) {
lines.unshift(`import type { ${[...customTypes].join(', ')} } from '../types.js'`)
}
lines.push('}')
fs.writeFileSync(path.join(TYPINGS_PATH, `${protocolName}.ts`), lines.join('\n'), 'utf8')
console.log(` 🧩 Generated typings file for ${protocolName}`)
}
}

View file

@ -0,0 +1,13 @@
import { builtinModules } from 'node:module'
import type { PackageJson } from 'type-fest'
export function getExternal(pkg: PackageJson) {
return [
'virtual:*',
...builtinModules,
...builtinModules.map((mod) => `node:${mod}`),
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.peerDependencies || {}),
...Object.keys(pkg.optionalDependencies || {}),
]
}

View file

@ -6,7 +6,7 @@
"scripts": {
"create": "tsx ./scripts/generateSubPackage.ts",
"backport": "tsx ./scripts/backport.ts",
"build": "run-s clean:build generate compile copy",
"build": "run-s clean:build generate compile:all",
"changelog": "tsx ./scripts/changelog.ts",
"ci": "run-s setup test test:e2e",
"clean": "run-p clean:*",
@ -18,11 +18,13 @@
"clean:cache": "rimraf --glob .eslintcache",
"clean:protocols": "rimraf --glob packages/wdio-protocols/src/commands",
"clean:cddl": "rimraf --glob scripts/bidi/cddl",
"compile": "tsx ./scripts/build.ts",
"copy": "cd packages/wdio-cli && pnpm copy && cd ../../",
"compile": "pnpm -r --filter=@wdio/compiler run build",
"compile:all": "run-s compile:all:*",
"compile:all:core": "pnpm -r --filter=@wdio/compiler run build -p @wdio/logger -p @wdio/types -p @wdio/globals -p @wdio/protocols -p @wdio/repl",
"compile:all:main": "pnpm -r --filter=@wdio/compiler run build -p @wdio/utils -p @wdio/reporter -p @wdio/config -p webdriver -p webdriverio",
"compile:all:all": "pnpm -r --filter=@wdio/compiler run build",
"generate": "run-s generate:*",
"generate:bidi": "tsx ./scripts/bidi/index.ts",
"generate:typings": "tsx ./scripts/type-generation/generate-all-typings.ts",
"link": "tsx ./scripts/link.ts",
"pushReleaseTag": "tsx ./scripts/pushTags.ts",
"setup": "run-s clean link build",
@ -53,7 +55,7 @@
"test:e2e:standalone": "vitest --config ./e2e/vitest.config.ts --run",
"test:e2e:webdriver": "node ./packages/wdio-cli/bin/wdio.js ./e2e/wdio/wdio.local.conf.ts",
"test:e2e:cloud": "tsx ./packages/wdio-cli/bin/wdio.js ./e2e/wdio/wdio.sauce.conf.ts",
"watch": "tsx ./scripts/build.ts --watch",
"dev": "pnpm -r --filter=@wdio/compiler run build --watch",
"watch:docs": "pnpm docs:generate && cd website && npm i && npm start",
"version": "pnpm changelog && git add CHANGELOG.md",
"postinstall": "run-s postinstall:*",

View file

@ -1,5 +0,0 @@
{
"name": "eslint-plugin-wdio-cjs",
"type": "commonjs",
"private": true
}

View file

@ -5,19 +5,17 @@
"author": "Christian Bromann <mail@bromann.dev>",
"homepage": "https://github.com/webdriverio/webdriverio/tree/main/packages/eslint-plugin-wdio",
"license": "MIT",
"main": "./cjs/index.js",
"main": "./build/index.cjs",
"module": "./build/index.js",
"types": "./build/index.d.ts",
"exports": {
"import": {
".": {
"types": "./build/index.d.ts",
"default": "./build/index.js"
},
"require": {
"types": "./build/index.d.ts",
"default": "./cjs/index.js"
"import": "./build/index.js",
"require": "./build/index.cjs"
}
},
"type": "module",
"typeScriptVersion": "3.8.3",
"engines": {
"node": ">=18"

View file

@ -44,7 +44,7 @@ const flatConfig = {
},
}
export = {
export default {
...index,
configs: {
'flat/recommended': flatConfig,

View file

@ -1,10 +0,0 @@
{
"extends": "./tsconfig.prod.json",
"compilerOptions": {
"module": "CommonJS",
"moduleResolution": "Node",
"outDir": "./cjs",
"declaration": false,
"declarationMap": false
}
}

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -1,5 +0,0 @@
{
"name": "@wdio/allure-reporter-cjs",
"type": "commonjs",
"private": true
}

View file

@ -24,15 +24,12 @@
"module": "./build/index.js",
"types": "./build/index.d.ts",
"exports": {
".": [
{
"types": "./build/index.d.ts",
"import": "./build/index.js",
"require": "./cjs/common/api.js"
},
"./cjs/common/api.js"
],
"./package.json": "./package.json"
".": {
"types": "./build/index.d.ts",
"import": "./build/index.js",
"requireSource": "./src/common/api.ts",
"require": "./build/index.cjs"
}
},
"typeScriptVersion": "3.8.3",
"engines": {

View file

@ -1,14 +0,0 @@
{
"extends": "./tsconfig.prod.json",
"compilerOptions": {
"module": "CommonJS",
"moduleResolution": "Node",
"outDir": "./cjs",
"declaration": false,
"declarationMap": false
},
"include": [
"src/common",
"src/constants",
]
}

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -28,8 +28,10 @@
"type": "module",
"types": "./build/index.d.ts",
"exports": {
".": "./build/index.js",
"./package.json": "./package.json"
".": {
"import": "./build/index.js",
"types": "./build/index.d.ts"
}
},
"typeScriptVersion": "3.8.3",
"dependencies": {

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -25,11 +25,39 @@
"type": "module",
"types": "./build/index.d.ts",
"exports": {
".": "./build/index.js",
"./package.json": "./package.json",
".": {
"types": "./build/index.d.ts",
"import": "./build/index.js"
},
"./stencil": {
"importSource": "./src/browser/integrations/stencil.ts",
"import": "./build/browser/integrations/stencil.js",
"types": "./stencil/index.d.ts"
"types": "./build/browser/integrations/stencil.d.ts"
},
"./driver": {
"browserSource": "./src/browser/driver.ts",
"browser": "./build/browser/driver.js",
"types": "./build/browser/driver.d.ts"
},
"./mock": {
"browserSource": "./src/browser/mock.ts",
"browser": "./build/browser/mock.js",
"types": "./build/browser/mock.d.ts"
},
"./setup": {
"browserSource": "./src/browser/setup.ts",
"browser": "./build/browser/setup.js",
"types": "./build/browser/setup.d.ts"
},
"./spy": {
"browserSource": "./src/browser/spy.ts",
"browser": "./build/browser/spy.js",
"types": "./build/browser/spy.d.ts"
},
"./expect": {
"browserSource": "./src/browser/expect.ts",
"browser": "./build/browser/expect.js",
"types": "./build/browser/expect.d.ts"
}
},
"typeScriptVersion": "3.8.3",
@ -65,16 +93,18 @@
"webdriver": "workspace:*",
"webdriverio": "workspace:*"
},
"scripts": {
"prepare": "rimraf node_modules/@wdio/config node_modules/@wdio/repl node_modules/@wdio/utils"
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-lib-report": "^3.0.3",
"@types/istanbul-reports": "^3.0.4",
"esbuild": "^0.21.3"
},
"optionalDependencies": {
"@nuxt/kit": "^3.12.4",
"@stencil/core": "^4.20.0",
"unimport": "^3.10.0"
},
"publishConfig": {
"access": "public"
}
}

View file

@ -31,4 +31,5 @@ export const type = 'browser'
export const sync = () => {}
export const locateChrome = () => {}
export const locateFirefox = () => {}
export const locateApp = () => {}
export default () => {}

View file

@ -47,7 +47,7 @@ export async function optimizeForStencil(rootDir: string) {
async function stencilVitePlugin(rootDir: string): Promise<Plugin> {
const { transpileSync, ts } = await import('@stencil/core/compiler/stencil.js')
const stencilHelperPath = path.resolve(__dirname, '..', '..', 'browser', 'integrations', 'stencil.js')
const stencilHelperPath = path.resolve(__dirname, 'browser', 'integrations', 'stencil.js')
return {
name: 'wdio-stencil',
enforce: 'pre',

View file

@ -50,7 +50,7 @@ const POLYFILLS = [
...builtinModules.map((m) => `node:${m}`)
]
export function testrunner(options: WebdriverIO.BrowserRunnerOptions): Plugin[] {
const browserModules = path.resolve(__dirname, '..', '..', 'browser')
const browserModules = path.resolve(__dirname, 'browser')
const automationProtocolPath = `/@fs${url.pathToFileURL(path.resolve(browserModules, 'driver.js')).pathname}`
const mockModulePath = path.resolve(browserModules, 'mock.js')
const setupModulePath = path.resolve(browserModules, 'setup.js')
@ -91,6 +91,11 @@ export function testrunner(options: WebdriverIO.BrowserRunnerOptions): Plugin[]
return wdioExpectModulePath
}
if (id === '@wdio/logger') {
const newId = url.fileURLToPath(await resolve(id, import.meta.url))
return path.resolve(path.dirname(newId), 'browser.js')
}
/**
* make sure WDIO imports are resolved properly as ESM module
*/

View file

@ -26,32 +26,6 @@ export async function getTemplate(options: WebdriverIO.BrowserRunnerOptions, env
delete env.config.runner
}
let vueDeps = ''
if (options.preset === 'vue') {
try {
const vueDir = path.dirname(url.fileURLToPath(await resolve('vue', `${rootFileUrl}/node_modules`)))
const vueScript = (await fs.readFile(path.join(vueDir, 'dist', 'vue.global.prod.js'), 'utf-8')).toString()
vueDeps += /*html*/`
<script type="module">
${vueScript}
window.Vue = Vue
</script>`
const vueCompilerDir = path.dirname(url.fileURLToPath(await resolve('@vue/compiler-dom', `${rootFileUrl}/node_modules`)))
const vueCompilerScript = (await fs.readFile(path.join(vueCompilerDir, 'dist', 'compiler-dom.global.prod.js'))).toString()
vueDeps += /*html*/`
<script type="module">
${vueCompilerScript}
window.VueCompilerDOM = VueCompilerDOM
</script>`
} catch (err: any) {
throw new Error(
`Fail to set-up Vue environment: ${err.message}\n\n` +
'Make sure you have "vue" and "@vue/compiler-dom" installed as dependencies!\n' +
`Error: ${err.stack}`
)
}
}
let sourceMapScript = ''
let sourceMapSetupCommand = ''
try {
@ -141,7 +115,6 @@ export async function getTemplate(options: WebdriverIO.BrowserRunnerOptions, env
margin: 0;
}
</style>
${vueDeps}
</head>
<body>
<mocha-framework spec="${spec}" ${isHeadless ? 'style="display: none"' : ''}></mocha-framework>

View file

@ -139,15 +139,6 @@ exports[`getTemplate > renders template correctly 1`] = `
margin: 0;
}
</style>
<script type="module">
some code
window.Vue = Vue
</script>
<script type="module">
some code
window.VueCompilerDOM = VueCompilerDOM
</script>
</head>
<body>
<mocha-framework spec="/spec.js" style="display: none"></mocha-framework>

View file

@ -1,7 +1,6 @@
import os from 'node:os'
import url from 'node:url'
import path from 'node:path'
import fs from 'node:fs/promises'
import { describe, it, vi, expect } from 'vitest'
import { resolve } from 'import-meta-resolve'
@ -29,12 +28,6 @@ vi.mock('fakeDep', () => ({
// skip for Windows
if (os.platform() !== 'win32') {
describe('getTemplate', () => {
it('fails if vue helpers are not installed', async () => {
vi.mocked(resolve).mockRejectedValue(new Error('not there'))
await expect(getTemplate({ preset: 'vue' }, { config: {} } as any, ''))
.rejects.toThrow(/Fail to set-up Vue environment/)
})
it('renders template correctly', async () => {
vi.mocked(resolve).mockResolvedValue('file:///foo/bar/vue')
/**
@ -44,8 +37,7 @@ if (os.platform() !== 'win32') {
process.env.CI = '1'
}
const p: any = { env: { some: 'env' }, cwd: () => '/some/cwd' }
expect(await getTemplate({ preset: 'vue' }, { config: {} } as any, '/spec.js', p)).toMatchSnapshot()
expect(fs.readFile).toBeCalledTimes(2)
expect(await getTemplate({ preset: 'lit' }, { config: {} } as any, '/spec.js', p)).toMatchSnapshot()
})
})
}

View file

@ -3,8 +3,7 @@
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src",
"types": ["@wdio/globals/types"]
"rootDir": "./src"
},
"include": [
"src/**/*",

View file

@ -1,14 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src",
"types": ["@wdio/globals/types"]
},
"include": [
"src/**/*",
"../../@types",
"../wdio-globals/types"
]
}

View file

@ -25,8 +25,10 @@
"type": "module",
"types": "./build/index.d.ts",
"exports": {
".": "./build/index.js",
"./package.json": "./package.json"
".": {
"types": "./build/index.d.ts",
"import": "./build/index.js"
}
},
"typeScriptVersion": "3.8.3",
"dependencies": {

View file

@ -1,7 +1,7 @@
import type { BrowserstackConfig } from './types.js'
import { createRequire } from 'node:module'
const require = createRequire(import.meta.url)
const { version: bstackServiceVersion } = require('../package.json')
import pkg from '../package.json' assert { type: 'json' }
const bstackServiceVersion = pkg.version
export const BROWSER_DESCRIPTION = [
'device',

View file

@ -1,13 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src",
"types": ["@wdio/globals/types"]
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -11,9 +11,6 @@
"engines": {
"node": ">=18"
},
"scripts": {
"copy": "copyfiles -u 1 -V \"src/templates/**/*\" ./build/"
},
"repository": {
"type": "git",
"url": "git://github.com/webdriverio/webdriverio.git",
@ -33,15 +30,12 @@
"module": "./build/index.js",
"types": "./build/index.d.ts",
"exports": {
".": [
{
"types": "./build/index.d.ts",
"import": "./build/index.js",
"require": "./build/index.cjs"
},
"./build/index.cjs"
],
"./package.json": "./package.json"
".": {
"types": "./build/index.d.ts",
"import": "./build/index.js",
"requireSource": "./src/index.cts",
"require": "./build/index.cjs"
}
},
"typeScriptVersion": "3.8.3",
"dependencies": {

View file

@ -1,4 +1,5 @@
import fs from 'node:fs/promises'
import fss from 'node:fs'
import path from 'node:path'
import inquirer from 'inquirer'
@ -15,7 +16,13 @@ import {
} from '../utils.js'
import type { ConfigCommandArguments, ParsedAnswers } from '../types.js'
const hasYarnLock = await fs.access('yarn.lock').then(() => true, () => false)
let hasYarnLock = false
try {
fss.accessSync('yarn.lock')
hasYarnLock = true
} catch {
hasYarnLock = false
}
export const command = 'config'
export const desc = 'Initialize WebdriverIO and setup configuration in your current project.'

View file

@ -1,3 +1,4 @@
/// <reference types="@wdio/globals/types" />
import pickBy from 'lodash.pickby'
import { remote } from 'webdriverio'
import type { Argv, Options } from 'yargs'

View file

@ -1,6 +1,5 @@
import fs from 'node:fs/promises'
import fs from 'node:fs'
import path from 'node:path'
import { createRequire } from 'node:module'
import { HOOK_DEFINITION } from '@wdio/utils'
import type { Options, Services, Reporters } from '@wdio/types'
@ -12,10 +11,9 @@ import {
detectPackageManager,
} from './utils.js'
import type { Questionnair } from './types.js'
import pkgJSON from '../package.json' with { type: 'json' }
const require = createRequire(import.meta.url)
export const pkg = require('../package.json')
export const pkg = pkgJSON
export const CLI_EPILOGUE = `Documentation: https://webdriver.io\n@wdio/cli (v${pkg.version})`
export const CONFIG_HELPER_INTRO = `
@ -24,6 +22,7 @@ export const CONFIG_HELPER_INTRO = `
===============================
`
export const SUPPORTED_COMMANDS = ['run', 'install', 'config', 'repl']
export const PMs = ['npm', 'yarn', 'pnpm', 'bun'] as const
export const SUPPORTED_CONFIG_FILE_EXTENSION = ['js', 'ts', 'mjs', 'mts', 'cjs', 'cts']
export const configHelperSuccessMessage = ({ projectRootDir, runScript, extraInfo = '' }: { projectRootDir: string, runScript: string, extraInfo: string }) => `
@ -229,19 +228,19 @@ function getTestingPurpose (answers: Questionnair) {
return convertPackageHashToObject(answers.runner).purpose as 'e2e' | 'electron' | 'component' | 'vscode' | 'macos'
}
export const isNuxtProject = await Promise.all(
[
path.join(process.cwd(), 'nuxt.config.js'),
path.join(process.cwd(), 'nuxt.config.ts'),
path.join(process.cwd(), 'nuxt.config.mjs'),
path.join(process.cwd(), 'nuxt.config.mts')
].map(
(p) => fs.access(p).then(() => true, () => false)
)
).then(
(res) => res.some(Boolean),
() => false
)
export const isNuxtProject = [
path.join(process.cwd(), 'nuxt.config.js'),
path.join(process.cwd(), 'nuxt.config.ts'),
path.join(process.cwd(), 'nuxt.config.mjs'),
path.join(process.cwd(), 'nuxt.config.mts')
].map((p) => {
try {
fs.accessSync(p)
return true
} catch {
return false
}
}).some(Boolean)
function selectDefaultService (serviceNames: string | string[]) {
serviceNames = Array.isArray(serviceNames) ? serviceNames : [serviceNames]

View file

@ -6,8 +6,8 @@ class Launcher {
args: any = {},
isWatchMode = false
) {
this.#esmLauncher = import('./launcher.js').then(
({ default: Launcher }) => new Launcher(configFilePath, args, isWatchMode))
this.#esmLauncher = import('./index.js').then(
({ Launcher }) => new Launcher(configFilePath, args, isWatchMode))
}
/**

View file

@ -1,5 +1,3 @@
import fs from 'node:fs'
import url from 'node:url'
import path from 'node:path'
import yargs from 'yargs'
@ -7,11 +5,9 @@ import { hideBin } from 'yargs/helpers'
import { commands } from './commands/index.js'
import { handler, cmdArgs } from './commands/run.js'
import { CLI_EPILOGUE, pkg } from './constants.js'
import { CLI_EPILOGUE, pkg, SUPPORTED_COMMANDS } from './constants.js'
import type { RunCommandArguments } from './types.js'
const __dirname = path.dirname(url.fileURLToPath(import.meta.url))
const DEFAULT_CONFIG_FILENAME = 'wdio.conf.js'
const DESCRIPTION = [
'The `wdio` command allows you run and manage your WebdriverIO test suite.',
@ -26,7 +22,6 @@ const DESCRIPTION = [
]
export default async function run() {
const commandDir = path.join(__dirname, 'commands')
const argv = yargs(hideBin(process.argv))
.command(commands)
.example('wdio run wdio.conf.js --suite foobar', 'Run suite on testsuite "foobar"')
@ -58,11 +53,7 @@ export default async function run() {
* we don't have to check that again here.
*/
const params = await argv.parse()
const supportedCommands = fs
.readdirSync(commandDir)
.map((file) => file.slice(0, -3))
if (!params._ || params._.find((param: string) => supportedCommands.includes(param))) {
if (!params._ || params._.find((param: string) => SUPPORTED_COMMANDS.includes(param))) {
return
}

View file

@ -328,7 +328,7 @@ export async function getCapabilities(arg: ReplCommandArguments) {
// multiremote
(requiredCaps as Capabilities.RequestedMultiremoteCapabilities)[arg.capabilities]
)
const requiredW3CCaps = pickBy(requiredCaps, (_, key) => CAPABILITY_KEYS.includes(key) || key.includes(':'))
const requiredW3CCaps = pickBy(requiredCaps, (_: never, key: string) => CAPABILITY_KEYS.includes(key) || key.includes(':'))
if (!Object.keys(requiredW3CCaps).length) {
throw Error(`No capability found in given config file with the provided capability indexed/named property: ${arg.capabilities}. Please check the capability in your wdio config file.`)
}

View file

@ -3,8 +3,7 @@
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src",
"types": ["@wdio/globals/types"]
"rootDir": "./src"
},
"include": [
"src/**/*",

View file

@ -1,14 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src",
"types": ["@wdio/globals/types"]
},
"include": [
"src/**/*",
"../../@types",
"src/cjs/package.json"
]
}

View file

@ -24,8 +24,10 @@
"type": "module",
"types": "./build/index.d.ts",
"exports": {
".": "./build/index.js",
"./package.json": "./package.json"
".": {
"types": "./build/index.d.ts",
"import": "./build/index.js"
}
},
"typeScriptVersion": "3.8.3",
"dependencies": {

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -13,10 +13,10 @@
"types": "./build/index.d.ts"
},
"./node": {
"importSource": "./src/node/index.ts",
"import": "./build/node/index.js",
"types": "./build/node/index.d.ts"
},
"./package.json": "./package.json"
}
},
"typeScriptVersion": "3.8.3",
"engines": {

View file

@ -418,7 +418,7 @@ export default class ConfigParser {
/**
* return capabilities
*/
getCapabilities(i?: number) {
getCapabilities(i?: number): Capabilities.TestrunnerCapabilities | Capabilities.RequestedStandaloneCapabilities {
if (!this.#isInitialised) {
throw new Error('ConfigParser was not initialized, call "await config.initialize()" first!')
}
@ -427,7 +427,7 @@ export default class ConfigParser {
return this._capabilities[i]
}
return this._capabilities
return this._capabilities!
}
/**

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -25,15 +25,16 @@
"type": "module",
"module": "./build/index.js",
"exports": {
".": [
{
"types": "./build/index.d.ts",
"import": "./build/index.js",
"require": "./build/index.cjs"
},
"./build/index.cjs"
],
"./package.json": "./package.json"
".": {
"types": "./build/index.d.ts",
"import": "./build/index.js",
"requireSource": "./src/index.cts",
"require": "./build/index.cjs"
},
"./formatter": {
"source": "./src/cucumberFormatter.ts",
"import": "./build/cucumberFormatter.js"
}
},
"types": "./build/index.d.ts",
"typeScriptVersion": "3.8.3",
@ -45,6 +46,7 @@
"@wdio/logger": "workspace:*",
"@wdio/types": "workspace:*",
"@wdio/utils": "workspace:*",
"import-meta-resolve": "^4.1.0",
"glob": "^10.2.2",
"is-glob": "^4.0.0"
},

View file

@ -57,6 +57,7 @@ export const FILE_PROTOCOL = 'file://'
const uuidFn = IdGenerator.uuid()
const log = logger('@wdio/cucumber-framework')
const require = createRequire(import.meta.url)
const __dirname = path.dirname(url.fileURLToPath(import.meta.url))
function getResultObject(
world: Cucumber.ITestCaseHookParameter
@ -87,7 +88,7 @@ class CucumberAdapter {
private _reporter: EventEmitter,
private _eventEmitter: EventEmitter,
private _generateSkipTags: boolean = true,
private _cucumberFormatter: string = url.pathToFileURL(path.resolve(url.fileURLToPath(import.meta.url), '..', 'cucumberFormatter.js')).href
private _cucumberFormatter: string = url.pathToFileURL(path.resolve(__dirname, 'cucumberFormatter.js')).href
) {
this._eventEmitter = new EventEmitter()
this._cucumberOpts = Object.assign(

View file

@ -204,7 +204,7 @@ export function generateSkipTagsFromCapabilities(capabilities: Capabilities.Reso
const pos = splitItem.indexOf('=')
if (pos > 0) {
try {
acc[splitItem.substring(0, pos)] = eval(
acc[splitItem.substring(0, pos)] = (0, eval)(
splitItem.substring(pos + 1)
)
} catch (err: any) {

View file

@ -1,13 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types",
"src/cjs/package.json"
]
}

View file

@ -23,8 +23,10 @@
},
"type": "module",
"exports": {
".": "./build/index.js",
"./package.json": "./package.json"
".": {
"import": "./build/index.js",
"types": "./build/index.d.ts"
}
},
"typeScriptVersion": "3.8.3",
"dependencies": {

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -31,8 +31,10 @@
"type": "module",
"types": "./build/index.d.ts",
"exports": {
".": "./build/index.js",
"./package.json": "./package.json"
".": {
"import": "./build/index.js",
"types": "./build/index.d.ts"
}
},
"typeScriptVersion": "3.8.3",
"dependencies": {

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -1,5 +1,4 @@
src
tests
tsconfig.json
tsconfig.prod.json
tsconfig.cjs.json
tsconfig.prod.jsontsconfig.cjs.json

View file

@ -1,5 +0,0 @@
{
"name": "@wdio/globals-cjs",
"type": "commonjs",
"private": true
}

View file

@ -5,20 +5,18 @@
"author": "Christian Bromann <mail@bromann.dev>",
"homepage": "https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-globals",
"license": "MIT",
"main": "./cjs/index.js",
"main": "./build/index.cjs",
"type": "module",
"module": "./build/index.js",
"exports": {
".": [
{
"types": "./build/index.d.ts",
"import": "./build/index.js",
"require": "./cjs/index.js"
},
"./cjs/index.js"
],
"./types": "./types.d.ts",
"./package.json": "./package.json"
".": {
"types": "./build/index.d.ts",
"import": "./build/index.js",
"require": "./build/index.cjs"
},
"./types": {
"types": "./types.d.ts"
}
},
"types": "./build/index.d.ts",
"typeScriptVersion": "3.8.3",

View file

@ -5,6 +5,11 @@ type SupportedGlobals = 'browser' | 'driver' | 'multiremotebrowser' | '$' | '$$'
declare global {
// eslint-disable-next-line no-var
var _wdioGlobals: Map<SupportedGlobals, any>
namespace WebdriverIO {
interface Browser {}
interface Element {}
interface MultiRemoteBrowser {}
}
}
/**

View file

@ -1,10 +0,0 @@
{
"extends": "./tsconfig.prod.json",
"compilerOptions": {
"module": "CommonJS",
"moduleResolution": "Node",
"outDir": "./cjs",
"declaration": false,
"declarationMap": false
}
}

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -8,8 +8,10 @@
"type": "module",
"types": "./build/index.d.ts",
"exports": {
".": "./build/index.js",
"./package.json": "./package.json"
".": {
"import": "./build/index.js",
"types": "./build/index.d.ts"
}
},
"typeScriptVersion": "3.8.3",
"engines": {

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -25,12 +25,14 @@
"type": "module",
"exports": {
"./mergeResults": {
"types": "./build/mergeResults.d.ts",
"source": "./src/mergeResults.ts",
"import": "./build/mergeResults.js",
"require": "./build/mergeResults.cjs"
},
".": "./build/index.js",
"./package.json": "./package.json"
".": {
"import": "./build/index.js",
"types": "./build/index.d.ts"
}
},
"types": "./build/index.d.ts",
"typeScriptVersion": "3.8.3",

View file

@ -1,4 +0,0 @@
module.exports = async function (...args: any[]) {
const mergeResults = (await import('./mergeResults.js')).default
return mergeResults(...args)
}

View file

@ -1,13 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types",
"src/cjs/package.json"
]
}

View file

@ -26,8 +26,10 @@
"type": "module",
"types": "./build/index.d.ts",
"exports": {
".": "./build/index.js",
"./package.json": "./package.json"
".": {
"import": "./build/index.js",
"types": "./build/index.d.ts"
}
},
"typeScriptVersion": "3.8.3",
"dependencies": {

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -33,8 +33,10 @@
"type": "module",
"types": "./build/index.d.ts",
"exports": {
".": "./build/index.js",
"./package.json": "./package.json"
".": {
"types": "./build/index.d.ts",
"import": "./build/index.js"
}
},
"typeScriptVersion": "3.8.3",
"dependencies": {

View file

@ -1,13 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src",
"types": ["@wdio/globals/types"]
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -25,8 +25,14 @@
"type": "module",
"types": "./build/index.d.ts",
"exports": {
".": "./build/index.js",
"./package.json": "./package.json"
".": {
"types": "./build/index.d.ts",
"import": "./build/index.js"
},
"./run": {
"source": "./src/run.ts",
"import": "./build/run.js"
}
},
"typeScriptVersion": "3.8.3",
"dependencies": {

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -7,8 +7,15 @@
"license": "MIT",
"type": "module",
"types": "./build/index.d.ts",
"main": "./build/index.cjs",
"browser": "./build/browser.js",
"exports": {
".": "./build/index.js",
".": {
"browser": "./build/browser.js",
"import": "./build/index.js",
"types": "./build/index.d.ts",
"browserSource": "./src/browser.ts"
},
"./package.json": "./package.json"
},
"typeScriptVersion": "3.8.3",

View file

@ -2,6 +2,12 @@
const LOG_METHODS = ['error', 'warn', 'info', 'debug', 'trace', 'silent']
export type { Logger } from './index.js'
/**
* This implementation of the Logger package is a simple adptation to run it within
* a browser environment.
*/
export default function getLogger (component: string) {
return LOG_METHODS.reduce((acc: Console, cur: string): Console => {
const prop = cur as keyof Console

View file

@ -1,25 +1,232 @@
/* istanbul ignore file */
import fs from 'node:fs'
import util from 'node:util'
import type loggerType from './node.js'
export type { Logger } from './node.js'
import log from 'loglevel'
import type { ColorName } from 'chalk'
import chalk from 'chalk'
import prefix from 'loglevel-plugin-prefix'
import ansiStrip from 'strip-ansi'
/**
* environment check to allow to use this package in a web context
*/
// By default, import the web code using a literal require, so that in webpack
// contexts, it will always be bundled
let mode = await import('./web.js') as any
prefix.reg(log)
// Then, if we're in a Node.js context, require the node version of this module
// using a variable, so that it will _not_ be included in a bundle, either
// during compilation or execution
if (typeof process !== 'undefined' && typeof process.release !== 'undefined' && process.release.name === 'node') {
const nodeMode = './node.js'
mode = await import(nodeMode)
const DEFAULT_LEVEL = process.env.WDIO_DEBUG
? 'trace'
: 'info'
const COLORS: Record<string, ColorName> = {
error: 'red',
warn: 'yellow',
info: 'cyanBright',
debug: 'green',
trace: 'cyan',
progress: 'magenta'
}
// The net result will be that in a Node context, we'll have required both
// files but will use the correct one, and in the web context, we'll have only
// required the web file, thus ensuring that the Node file and related
// dependencies will not be bundled inadvertently.
export default mode.default as typeof loggerType
const matches = {
COMMAND: 'COMMAND',
BIDICOMMAND: 'BIDI COMMAND',
DATA: 'DATA',
RESULT: 'RESULT',
BIDIRESULT: 'BIDI RESULT'
}
const SERIALIZERS = [{
/**
* display error stack
*/
matches: (err: any) => err instanceof Error,
serialize: (err: any) => err.stack
}, {
/**
* color commands blue
*/
matches: (log: string) => log === matches.COMMAND || log === matches.BIDICOMMAND,
serialize: (log: string) => chalk.magenta(log)
}, {
/**
* color data yellow
*/
matches: (log: string) => log === matches.DATA,
serialize: (log: string) => chalk.yellow(log)
}, {
/**
* color result cyan
*/
matches: (log: string) => log === matches.RESULT || log === matches.BIDIRESULT,
serialize: (log: string) => chalk.cyan(log)
}]
interface LoggerInterface extends log.Logger {
progress(...msg: any[]): void;
}
interface Loggers {
[name: string]: LoggerInterface
}
const loggers: Loggers = log.getLoggers() as Loggers
let logLevelsConfig: Record<string, log.LogLevelDesc> = {}
const logCache = new Set()
let logFile: fs.WriteStream | null
const originalFactory = log.methodFactory
const wdioLoggerMethodFactory = function (this: log.Logger, methodName: log.LogLevelNames, logLevel: log.LogLevelNumbers, loggerName: string) {
const rawMethod = originalFactory(methodName, logLevel, loggerName)
return (...args: string[]) => {
/**
* create logFile lazily
*/
if (!logFile && process.env.WDIO_LOG_PATH) {
logFile = fs.createWriteStream(process.env.WDIO_LOG_PATH)
}
/**
* split `prefixer: value` sting to `prefixer: ` and `value`
* so that SERIALIZERS can match certain string
*/
const match = Object.values(matches).filter(x => args[0].endsWith(`: ${x}`))[0]
if (match) {
const prefixStr = args.shift()!.slice(0, -match.length - 1)
args.unshift(prefixStr, match)
}
args = args.map((arg) => {
for (const s of SERIALIZERS) {
if (s.matches(arg)) {
return s.serialize(arg)
}
}
return arg
})
const logText = ansiStrip(`${util.format.apply(this, args as [format: string, ...params: string[]])}\n`)
if (logFile && logFile.writable) {
/**
* empty logging cache if stuff got logged before
*/
if (logCache.size) {
logCache.forEach((log) => {
if (logFile) {
logFile.write(log)
}
})
logCache.clear()
}
if (!logsContainInitPackageError(logText)) {
return logFile.write(logText)
}
// If we get Error during init of integration packages, write logs to both "outputDir" and the terminal
logFile.write(logText)
}
logCache.add(logText)
rawMethod(...args)
}
}
const progress = function (this: any, data: string) {
if (process.stdout.isTTY && this.getLevel() <= log.levels.INFO) {
const level = 'progress'
const timestampFormatter = chalk.gray(new Date().toISOString())
const levelFormatter = chalk[COLORS[level]](level.toUpperCase())
const nameFormatter = chalk.whiteBright(this.name)
const _data = data.length > 0 ? `${timestampFormatter} ${levelFormatter} ${nameFormatter}: ${data}` : '\r\x1b[K\x1b[?25h'
process.stdout.write('\u001B[?25l') // Disable cursor in terminal
process.stdout.write(`${_data}\r`)
}
}
export default function getLogger (name: string) {
/**
* check if logger was already initiated
*/
if (loggers[name]) {
return loggers[name]
}
let logLevel: log.LogLevelDesc = (process.env.WDIO_LOG_LEVEL || DEFAULT_LEVEL) as log.LogLevelDesc
const logLevelName = getLogLevelName(name)
if (logLevelsConfig[logLevelName]) {
logLevel = logLevelsConfig[logLevelName]
}
loggers[name] = log.getLogger(name) as LoggerInterface
loggers[name].setLevel(logLevel)
loggers[name].methodFactory = wdioLoggerMethodFactory
loggers[name].progress = progress
prefix.apply(loggers[name], {
template: '%t %l %n:',
timestampFormatter: (date) => chalk.gray(date.toISOString()),
levelFormatter: (level: string) => chalk[COLORS[level]](level.toUpperCase()),
nameFormatter: (name) => chalk.whiteBright(name)
})
return loggers[name]
}
/**
* Wait for writable stream to be flushed.
* Calling this prevents part of the logs in the very env to be lost.
*/
getLogger.waitForBuffer = async () => new Promise<void>(resolve => {
// @ts-ignore
if (logFile && Array.isArray(logFile.writableBuffer) && logFile.writableBuffer.length !== 0) {
return setTimeout(async () => {
await getLogger.waitForBuffer()
resolve()
}, 20)
}
resolve()
})
getLogger.setLevel = (name: string, level: log.LogLevelDesc) => loggers[name].setLevel(level)
getLogger.clearLogger = () => {
if (logFile) {
logFile.end()
}
logFile = null
}
getLogger.setLogLevelsConfig = (logLevels: Record<string, log.LogLevelDesc> = {}, wdioLogLevel: log.LogLevelDesc = DEFAULT_LEVEL) => {
/**
* set log level
*/
if (process.env.WDIO_LOG_LEVEL === undefined) {
process.env.WDIO_LOG_LEVEL = wdioLogLevel as string
}
logLevelsConfig = {}
/**
* build logLevelsConfig object
*/
Object.entries(logLevels).forEach(([logName, logLevel]) => {
const logLevelName = getLogLevelName(logName)
logLevelsConfig[logLevelName] = logLevel
})
/**
* set log level for each logger
*/
Object.keys(loggers).forEach(logName => {
const logLevelName = getLogLevelName(logName)
/**
* either apply log level from logLevels object or use global logLevel
*/
const logLevel = typeof logLevelsConfig[logLevelName] !== 'undefined' ? logLevelsConfig[logLevelName] : process.env.WDIO_LOG_LEVEL as log.LogLevelDesc
loggers[logName].setLevel(logLevel)
})
}
const getLogLevelName = (logName: string) => logName.split(':').shift() as log.LogLevelDesc
export type Logger = LoggerInterface
function logsContainInitPackageError(logText: string) {
return ERROR_LOG_VALIDATOR.every(pattern => logText.includes(pattern))
}
const ERROR_LOG_VALIDATOR = [
'Couldn\'t find plugin',
'neither as wdio scoped package',
'nor as community package',
'Please make sure you have it installed'
]

View file

@ -1,232 +0,0 @@
import fs from 'node:fs'
import util from 'node:util'
import log from 'loglevel'
import type { ColorName } from 'chalk'
import chalk from 'chalk'
import prefix from 'loglevel-plugin-prefix'
import ansiStrip from 'strip-ansi'
prefix.reg(log)
const DEFAULT_LEVEL = process.env.WDIO_DEBUG
? 'trace'
: 'info'
const COLORS: Record<string, ColorName> = {
error: 'red',
warn: 'yellow',
info: 'cyanBright',
debug: 'green',
trace: 'cyan',
progress: 'magenta'
}
const matches = {
COMMAND: 'COMMAND',
BIDICOMMAND: 'BIDI COMMAND',
DATA: 'DATA',
RESULT: 'RESULT',
BIDIRESULT: 'BIDI RESULT'
}
const SERIALIZERS = [{
/**
* display error stack
*/
matches: (err: any) => err instanceof Error,
serialize: (err: any) => err.stack
}, {
/**
* color commands blue
*/
matches: (log: string) => log === matches.COMMAND || log === matches.BIDICOMMAND,
serialize: (log: string) => chalk.magenta(log)
}, {
/**
* color data yellow
*/
matches: (log: string) => log === matches.DATA,
serialize: (log: string) => chalk.yellow(log)
}, {
/**
* color result cyan
*/
matches: (log: string) => log === matches.RESULT || log === matches.BIDIRESULT,
serialize: (log: string) => chalk.cyan(log)
}]
interface LoggerInterface extends log.Logger {
progress(...msg: any[]): void;
}
interface Loggers {
[name: string]: LoggerInterface
}
const loggers: Loggers = log.getLoggers() as Loggers
let logLevelsConfig: Record<string, log.LogLevelDesc> = {}
const logCache = new Set()
let logFile: fs.WriteStream | null
const originalFactory = log.methodFactory
const wdioLoggerMethodFactory = function (this: log.Logger, methodName: log.LogLevelNames, logLevel: log.LogLevelNumbers, loggerName: string) {
const rawMethod = originalFactory(methodName, logLevel, loggerName)
return (...args: string[]) => {
/**
* create logFile lazily
*/
if (!logFile && process.env.WDIO_LOG_PATH) {
logFile = fs.createWriteStream(process.env.WDIO_LOG_PATH)
}
/**
* split `prefixer: value` sting to `prefixer: ` and `value`
* so that SERIALIZERS can match certain string
*/
const match = Object.values(matches).filter(x => args[0].endsWith(`: ${x}`))[0]
if (match) {
const prefixStr = args.shift()!.slice(0, -match.length - 1)
args.unshift(prefixStr, match)
}
args = args.map((arg) => {
for (const s of SERIALIZERS) {
if (s.matches(arg)) {
return s.serialize(arg)
}
}
return arg
})
const logText = ansiStrip(`${util.format.apply(this, args as [format: string, ...params: string[]])}\n`)
if (logFile && logFile.writable) {
/**
* empty logging cache if stuff got logged before
*/
if (logCache.size) {
logCache.forEach((log) => {
if (logFile) {
logFile.write(log)
}
})
logCache.clear()
}
if (!logsContainInitPackageError(logText)) {
return logFile.write(logText)
}
// If we get Error during init of integration packages, write logs to both "outputDir" and the terminal
logFile.write(logText)
}
logCache.add(logText)
rawMethod(...args)
}
}
const progress = function (this: any, data: string) {
if (process.stdout.isTTY && this.getLevel() <= log.levels.INFO) {
const level = 'progress'
const timestampFormatter = chalk.gray(new Date().toISOString())
const levelFormatter = chalk[COLORS[level]](level.toUpperCase())
const nameFormatter = chalk.whiteBright(this.name)
const _data = data.length > 0 ? `${timestampFormatter} ${levelFormatter} ${nameFormatter}: ${data}` : '\r\x1b[K\x1b[?25h'
process.stdout.write('\u001B[?25l') // Disable cursor in terminal
process.stdout.write(`${_data}\r`)
}
}
export default function getLogger (name: string) {
/**
* check if logger was already initiated
*/
if (loggers[name]) {
return loggers[name]
}
let logLevel: log.LogLevelDesc = (process.env.WDIO_LOG_LEVEL || DEFAULT_LEVEL) as log.LogLevelDesc
const logLevelName = getLogLevelName(name)
if (logLevelsConfig[logLevelName]) {
logLevel = logLevelsConfig[logLevelName]
}
loggers[name] = log.getLogger(name) as LoggerInterface
loggers[name].setLevel(logLevel)
loggers[name].methodFactory = wdioLoggerMethodFactory
loggers[name].progress = progress
prefix.apply(loggers[name], {
template: '%t %l %n:',
timestampFormatter: (date) => chalk.gray(date.toISOString()),
levelFormatter: (level: string) => chalk[COLORS[level]](level.toUpperCase()),
nameFormatter: (name) => chalk.whiteBright(name)
})
return loggers[name]
}
/**
* Wait for writable stream to be flushed.
* Calling this prevents part of the logs in the very env to be lost.
*/
getLogger.waitForBuffer = async () => new Promise<void>(resolve => {
// @ts-ignore
if (logFile && Array.isArray(logFile.writableBuffer) && logFile.writableBuffer.length !== 0) {
return setTimeout(async () => {
await getLogger.waitForBuffer()
resolve()
}, 20)
}
resolve()
})
getLogger.setLevel = (name: string, level: log.LogLevelDesc) => loggers[name].setLevel(level)
getLogger.clearLogger = () => {
if (logFile) {
logFile.end()
}
logFile = null
}
getLogger.setLogLevelsConfig = (logLevels: Record<string, log.LogLevelDesc> = {}, wdioLogLevel: log.LogLevelDesc = DEFAULT_LEVEL) => {
/**
* set log level
*/
if (process.env.WDIO_LOG_LEVEL === undefined) {
process.env.WDIO_LOG_LEVEL = wdioLogLevel as string
}
logLevelsConfig = {}
/**
* build logLevelsConfig object
*/
Object.entries(logLevels).forEach(([logName, logLevel]) => {
const logLevelName = getLogLevelName(logName)
logLevelsConfig[logLevelName] = logLevel
})
/**
* set log level for each logger
*/
Object.keys(loggers).forEach(logName => {
const logLevelName = getLogLevelName(logName)
/**
* either apply log level from logLevels object or use global logLevel
*/
const logLevel = typeof logLevelsConfig[logLevelName] !== 'undefined' ? logLevelsConfig[logLevelName] : process.env.WDIO_LOG_LEVEL as log.LogLevelDesc
loggers[logName].setLevel(logLevel)
})
}
const getLogLevelName = (logName: string) => logName.split(':').shift() as log.LogLevelDesc
export type Logger = LoggerInterface
function logsContainInitPackageError(logText: string) {
return ERROR_LOG_VALIDATOR.every(pattern => logText.includes(pattern))
}
const ERROR_LOG_VALIDATOR = [
'Couldn\'t find plugin',
'neither as wdio scoped package',
'nor as community package',
'Please make sure you have it installed'
]

View file

@ -1,8 +1,8 @@
import fs from 'node:fs'
import { it, describe, expect, vi, afterEach, beforeEach, afterAll } from 'vitest'
import nodeLogger from '../src/node.js'
import nodeLogger2 from '../build/node.js'
import nodeLogger from '../src/index.js'
import nodeLogger2 from '../build/index.js'
import type log from 'loglevel'
@ -151,7 +151,6 @@ describe('wdio-logger node', () => {
// @ts-ignore
return writableBuffer
},
// @ts-expect-error
end: vi.fn()
}))

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -28,8 +28,8 @@
"types": "./build/index.d.ts"
},
"./common": {
"import": "./build/common.js",
"types": "./build/common.d.ts"
"source": "./src/common.ts",
"import": "./build/common.js"
},
"./package.json": "./package.json"
},

View file

@ -21,6 +21,7 @@ type EventTypes = 'hook' | 'test' | 'suite'
type EventTypeProps = '_hookCnt' | '_testCnt' | '_suiteCnt'
interface ParsedConfiguration extends Required<Options.Testrunner> {
rootDir: string
mochaOpts: MochaOptsImport
}
/**

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -8,8 +8,10 @@
"type": "module",
"types": "./build/index.d.ts",
"exports": {
".": "./build/index.js",
"./package.json": "./package.json"
".": {
"import": "./build/index.js",
"types": "./build/index.d.ts"
}
},
"typeScriptVersion": "3.8.3",
"repository": {

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "build",
"rootDir": "src",
"removeComments": false
},
"include": [
"src/**/*"
]
}

View file

@ -25,8 +25,10 @@
"type": "module",
"types": "./build/index.d.ts",
"exports": {
".": "./build/index.js",
"./package.json": "./package.json"
".": {
"import": "./build/index.js",
"types": "./build/index.d.ts"
}
},
"typeScriptVersion": "3.8.3",
"dependencies": {

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -1,5 +0,0 @@
{
"name": "@wdio/reporter-cjs",
"type": "commonjs",
"private": true
}

View file

@ -25,19 +25,15 @@
"access": "public"
},
"type": "module",
"main": "./cjs/index.js",
"main": "./build/index.cjs",
"module": "./build/index.js",
"types": "./build/index.d.ts",
"exports": {
"./package.json": "./package.json",
".": [
{
"types": "./build/index.d.ts",
"import": "./build/index.js",
"require": "./cjs/index.js"
},
"./cjs/index.js"
]
".": {
"types": "./build/index.d.ts",
"import": "./build/index.js",
"require": "./build/index.cjs"
}
},
"typeScriptVersion": "3.8.3",
"dependencies": {

View file

@ -8,7 +8,7 @@ import type { Suite } from './stats/suite.js'
import SuiteStats from './stats/suite.js'
import type { Hook } from './stats/hook.js'
import HookStats from './stats/hook.js'
import TestStats, { Test } from './stats/test.js'
import TestStats, { type Test } from './stats/test.js'
import RunnerStats from './stats/runner.js'
import type { AfterCommandArgs, BeforeCommandArgs, CommandArgs, Tag, Argument } from './types.js'

View file

@ -1,10 +0,0 @@
{
"extends": "./tsconfig.prod.json",
"compilerOptions": {
"module": "CommonJS",
"moduleResolution": "Node",
"outDir": "./cjs",
"declaration": false,
"declarationMap": false
}
}

View file

@ -1,12 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -24,8 +24,10 @@
"type": "module",
"types": "./build/index.d.ts",
"exports": {
".": "./build/index.js",
"./package.json": "./package.json"
".": {
"types": "./build/index.d.ts",
"import": "./build/index.js"
}
},
"typeScriptVersion": "3.8.3",
"dependencies": {

View file

@ -120,7 +120,7 @@ export default class BrowserFramework implements Omit<TestFramework, 'init'> {
* is no need to call the url command again
*/
if (!this._config.sessionId) {
await browser.url(`/?cid=${this._cid}&spec=${url.parse(spec).pathname}`)
await browser.url(`/?cid=${this._cid}&spec=${(new URL(spec)).pathname}`)
}
// await browser.debug()
@ -473,8 +473,8 @@ export default class BrowserFramework implements Omit<TestFramework, 'init'> {
const logs = typeof browser.getLogs === 'function'
? (await browser.getLogs('browser').catch(() => []))
: []
const severeLogs = logs.filter((log: LogMessage) => log.level === 'SEVERE') as LogMessage[]
if (logs.length) {
const severeLogs = logs.filter((log: LogMessage) => log.level === 'SEVERE' && log.source !== 'deprecation') as LogMessage[]
if (severeLogs.length) {
if (!this.#retryOutdatedOptimizeDep && severeLogs.some((log) => log.message?.includes('(Outdated Optimize Dep)'))) {
log.info('Retry test run due to outdated optimize dep')
this.#retryOutdatedOptimizeDep = true

View file

@ -1,13 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src",
"types": ["@wdio/globals/types"]
},
"include": [
"src/**/*",
"../../@types"
]
}

View file

@ -25,8 +25,10 @@
"type": "module",
"types": "./build/index.d.ts",
"exports": {
".": "./build/index.js",
"./package.json": "./package.json"
".": {
"types": "./build/index.d.ts",
"import": "./build/index.js"
}
},
"typeScriptVersion": "3.8.3",
"dependencies": {

View file

@ -1,13 +0,0 @@
{
"extends": "../../tsconfig.prod",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src",
"types": ["@wdio/globals/types"]
},
"include": [
"src/**/*",
"../../@types"
]
}

Some files were not shown because too many files have changed in this diff Show more