diff --git a/.github/actions/setup-webdriverio/action.yml b/.github/actions/setup-webdriverio/action.yml deleted file mode 100644 index c89cb4773..000000000 --- a/.github/actions/setup-webdriverio/action.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Setup WebDriverIO Browsers -description: Setup Chrome, ChromeDriver, and optional Firefox for WebDriverIO tests - -inputs: - chrome-version: - description: Chrome for Testing version to install, or false to skip - # Pin to Chrome 148 while Chrome for Testing 149 Linux downloads/install are broken. - default: '148' - firefox-version: - description: Firefox version to install, or false to skip - default: latest - -runs: - using: composite - steps: - - uses: browser-actions/setup-chrome@4f8e94349a351df0f048634f25fec36c3c91eded # v2.1.1 - if: inputs.chrome-version != 'false' - id: setup-chrome - with: - chrome-version: ${{ inputs.chrome-version }} - install-chromedriver: true - - - name: Export Chrome binaries - if: inputs.chrome-version != 'false' - shell: bash - env: - CHROME_PATH: ${{ steps.setup-chrome.outputs.chrome-path }} - CHROMEDRIVER_PATH_VALUE: ${{ steps.setup-chrome.outputs.chromedriver-path }} - run: | # zizmor: ignore[github-env] values come from pinned browser-actions/setup-chrome outputs. - echo "CHROME_BIN=$CHROME_PATH" >> "$GITHUB_ENV" - echo "CHROMEDRIVER_PATH=$CHROMEDRIVER_PATH_VALUE" >> "$GITHUB_ENV" - - - name: Allow setup-chrome sandbox - if: inputs.chrome-version != 'false' && runner.os == 'Linux' - shell: bash - env: - CHROME_PATH: ${{ steps.setup-chrome.outputs.chrome-path }} - run: | - # Chrome for Testing is not covered by Ubuntu's AppArmor sandbox policy on CI. - # https://pptr.dev/troubleshooting#issues-with-apparmor-on-ubuntu - # https://chromium.googlesource.com/chromium/src/+/main/docs/security/apparmor-userns-restrictions.md - # https://github.com/browser-actions/setup-chrome/issues/639 - cat <, - include - - profile chrome-for-testing "$CHROME_PATH" flags=(unconfined) { - userns, - include if exists - } - EOF - sudo apparmor_parser -r /etc/apparmor.d/chrome-for-testing - - - uses: browser-actions/setup-firefox@fcf821c621167805dd63a29662bd7cb5676c81a8 # v1.7.1 - if: inputs.firefox-version != 'false' - id: setup-firefox - with: - firefox-version: ${{ inputs.firefox-version }} - - - name: Export Firefox binary - if: inputs.firefox-version != 'false' - shell: bash - env: - FIREFOX_PATH: ${{ steps.setup-firefox.outputs.firefox-path }} - run: echo "FIREFOX_BIN=$FIREFOX_PATH" >> "$GITHUB_ENV" # zizmor: ignore[github-env] value comes from pinned browser-actions/setup-firefox output. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0790e8c75..3c780abf4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -110,11 +110,6 @@ jobs: with: node-version: ${{ matrix.node_version }} - - uses: ./.github/actions/setup-webdriverio - id: setup-webdriverio - with: - firefox-version: false - - name: Install run: pnpm i @@ -164,11 +159,6 @@ jobs: with: node-version: ${{ matrix.node_version }} - - uses: ./.github/actions/setup-webdriverio - id: setup-webdriverio - with: - firefox-version: false - - name: Install run: pnpm i @@ -205,9 +195,6 @@ jobs: with: node-version: ${{ matrix.node_version }} - - uses: ./.github/actions/setup-webdriverio - id: setup-webdriverio - - name: Install run: pnpm i @@ -219,9 +206,6 @@ jobs: - name: Test Browser (playwright) run: pnpm run test:browser:playwright - - name: Test Browser (webdriverio) - run: pnpm run test:browser:webdriverio - test-rolldown: needs: changed # macos-latest is the fastest one @@ -240,11 +224,6 @@ jobs: with: node-version: 22 - - uses: ./.github/actions/setup-webdriverio - id: setup-webdriverio - with: - firefox-version: false - - name: Install run: | yq -i '.overrides.vite = "npm:vite@8"' pnpm-workspace.yaml diff --git a/AGENTS.md b/AGENTS.md index 1d3787d41..0108dac37 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,7 +33,7 @@ Vitest is a next-generation testing framework powered by Vite. This is a monorep - **Examples**: `CI=true pnpm test:examples` - **Specific test suite**: `CI=true cd test/ && pnpm test ` - **Core directory test**: `CI=true pnpm test ` (for `test/core`) -- **Browser tests**: `CI=true pnpm test:browser:playwright` or `CI=true pnpm test:browser:webdriverio` +- **Browser tests**: `CI=true pnpm test:browser:playwright` **IMPORTANT: Do NOT use `--` when passing test filters to pnpm.** Using `--` causes pnpm to drop the filter, resulting in a full test run instead of a filtered one. diff --git a/package.json b/package.json index 054b6553f..1b43c2327 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ "ui:dev": "npm -C packages/ui run dev:client", "ui:test": "npm -C packages/ui run test:run", "override-rolldown": "yq -i '.overrides.vite = \"npm:vite@8\"' pnpm-workspace.yaml", - "test:browser:webdriverio": "pnpm -C test/browser run test:webdriverio", "test:browser:playwright": "pnpm -C test/browser run test:playwright" }, "devDependencies": { diff --git a/packages/browser-webdriverio/README.md b/packages/browser-webdriverio/README.md deleted file mode 100644 index a9c395017..000000000 --- a/packages/browser-webdriverio/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# @vitest/browser-webdriverio - -[![NPM version](https://img.shields.io/npm/v/@vitest/browser-webdriverio?color=a1b858&label=)](https://npmx.dev/package/@vitest/browser-webdriverio) - -Run your Vitest [browser tests](https://vitest.dev/guide/browser/) using [webdriverio](https://webdriver.io/docs/api/browser) API. Note that Vitest does not use webdriverio as a test runner, but only as a browser provider. - -We recommend using this package if you are already using webdriverio in your project. - -## Installation - -Install the package with your favorite package manager: - -```sh -npm install -D @vitest/browser-webdriverio -# or -yarn add -D @vitest/browser-webdriverio -# or -pnpm add -D @vitest/browser-webdriverio -``` - -Then specify it in the `browser.provider` field of your Vitest configuration: - -```ts -// vitest.config.ts -import { defineConfig } from 'vitest/config' -import { webdriverio } from '@vitest/browser-webdriverio' - -export default defineConfig({ - test: { - browser: { - provider: webdriverio({ - // ...custom webdriverio options - }), - instances: [ - { browser: 'chrome' }, - ], - }, - }, -}) -``` - -Then run Vitest in the browser mode: - -```sh -npx vitest --browser -``` - -[GitHub](https://github.com/vitest-dev/vitest/tree/main/packages/browser-webdriverio) | [Documentation](https://vitest.dev/config/browser/webdriverio) diff --git a/packages/browser-webdriverio/context.d.ts b/packages/browser-webdriverio/context.d.ts deleted file mode 100644 index a022f2f10..000000000 --- a/packages/browser-webdriverio/context.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '@vitest/browser/context' diff --git a/packages/browser-webdriverio/package.json b/packages/browser-webdriverio/package.json deleted file mode 100644 index 8f57c6886..000000000 --- a/packages/browser-webdriverio/package.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "name": "@vitest/browser-webdriverio", - "type": "module", - "version": "4.1.11", - "description": "Browser running for Vitest using webdriverio", - "license": "MIT", - "funding": "https://opencollective.com/vitest", - "homepage": "https://vitest.dev/config/browser/webdriverio", - "repository": { - "type": "git", - "url": "git+https://github.com/vitest-dev/vitest.git", - "directory": "packages/browser-webdriverio" - }, - "bugs": { - "url": "https://github.com/vitest-dev/vitest/issues" - }, - "keywords": [ - "browser", - "webdriverio", - "wdio", - "component", - "mocks", - "test", - "testing" - ], - "sideEffects": false, - "exports": { - ".": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - }, - "./context": { - "types": "./context.d.ts" - }, - "./package.json": "./package.json" - }, - "main": "./dist/index.js", - "module": "./dist/index.js", - "types": "./dist/index.d.ts", - "files": [ - "context.d.ts", - "dist" - ], - "scripts": { - "build": "premove dist && pnpm rollup -c", - "dev": "rollup -c --watch --watch.include 'src/**'" - }, - "peerDependencies": { - "vitest": "workspace:*", - "webdriverio": "*" - }, - "peerDependenciesMeta": { - "webdriverio": { - "optional": false - } - }, - "dependencies": { - "@vitest/browser": "workspace:*" - }, - "devDependencies": { - "@wdio/types": "^9.24.0", - "vitest": "workspace:*", - "webdriverio": "^9.20.0" - } -} diff --git a/packages/browser-webdriverio/rollup.config.js b/packages/browser-webdriverio/rollup.config.js deleted file mode 100644 index 059c23eb2..000000000 --- a/packages/browser-webdriverio/rollup.config.js +++ /dev/null @@ -1,60 +0,0 @@ -import { createRequire } from 'node:module' -import commonjs from '@rollup/plugin-commonjs' -import json from '@rollup/plugin-json' -import resolve from '@rollup/plugin-node-resolve' -import { defineConfig } from 'rollup' -import oxc from 'unplugin-oxc/rollup' -import { createDtsUtils } from '../../scripts/build-utils.js' - -const require = createRequire(import.meta.url) -const pkg = require('./package.json') - -const external = [ - ...Object.keys(pkg.dependencies), - ...Object.keys(pkg.peerDependencies || {}), - /^@?vitest(\/|$)/, -] - -const dtsUtils = createDtsUtils() - -const plugins = [ - resolve({ - preferBuiltins: true, - }), - json(), - commonjs(), - oxc({ - transform: { target: 'node20' }, - }), -] - -export default () => - defineConfig([ - { - input: { - index: './src/index.ts', - locators: './src/locators.ts', - }, - output: { - dir: 'dist', - format: 'esm', - }, - external, - context: 'null', - plugins: [ - ...dtsUtils.isolatedDecl(), - ...plugins, - ], - }, - { - input: dtsUtils.dtsInput('src/index.ts'), - output: { - dir: 'dist', - entryFileNames: '[name].d.ts', - format: 'esm', - }, - watch: false, - external, - plugins: dtsUtils.dts(), - }, - ]) diff --git a/packages/browser-webdriverio/src/commands/clear.ts b/packages/browser-webdriverio/src/commands/clear.ts deleted file mode 100644 index 214f72afa..000000000 --- a/packages/browser-webdriverio/src/commands/clear.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { UserEvent } from 'vitest/browser' -import type { UserEventCommand } from './utils' - -export const clear: UserEventCommand = async ( - context, - selector, -) => { - const browser = context.browser - await browser.$(selector).clearValue() -} diff --git a/packages/browser-webdriverio/src/commands/click.ts b/packages/browser-webdriverio/src/commands/click.ts deleted file mode 100644 index 997850a8d..000000000 --- a/packages/browser-webdriverio/src/commands/click.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { UserEvent } from 'vitest/browser' -import type { UserEventCommand } from './utils' - -export const click: UserEventCommand = async ( - context, - selector, - options, -) => { - const browser = context.browser - await browser.$(selector).click(options) -} - -export const dblClick: UserEventCommand = async ( - context, - selector, - _options, -) => { - const browser = context.browser - await browser.$(selector).doubleClick() -} - -export const tripleClick: UserEventCommand = async ( - context, - selector, - _options, -) => { - const browser = context.browser - await browser - .action('pointer', { parameters: { pointerType: 'mouse' } }) - // move the pointer over the button - .move({ origin: browser.$(selector) }) - // simulate 3 clicks - .down() - .up() - .pause(50) - .down() - .up() - .pause(50) - .down() - .up() - .pause(50) - // run the sequence - .perform() -} diff --git a/packages/browser-webdriverio/src/commands/dragAndDrop.ts b/packages/browser-webdriverio/src/commands/dragAndDrop.ts deleted file mode 100644 index 549f4dbcc..000000000 --- a/packages/browser-webdriverio/src/commands/dragAndDrop.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { UserEvent } from 'vitest/browser' -import type { UserEventCommand } from './utils' - -export const dragAndDrop: UserEventCommand = async ( - context, - source, - target, - options_, -) => { - const $source = context.browser.$(source) - const $target = context.browser.$(target) - const options = (options_ || {}) as any - const duration = options.duration ?? 10 - - // https://github.com/webdriverio/webdriverio/issues/8022#issuecomment-1700919670 - await context.browser - .action('pointer') - .move({ duration: 0, origin: $source, x: options.sourceX ?? 0, y: options.sourceY ?? 0 }) - .down({ button: 0 }) - .move({ duration: 0, origin: 'pointer', x: 0, y: 0 }) - .pause(duration) - .move({ duration: 0, origin: $target, x: options.targetX ?? 0, y: options.targetY ?? 0 }) - .move({ duration: 0, origin: 'pointer', x: 1, y: 0 }) - .move({ duration: 0, origin: 'pointer', x: -1, y: 0 }) - .up({ button: 0 }) - .perform() -} diff --git a/packages/browser-webdriverio/src/commands/fill.ts b/packages/browser-webdriverio/src/commands/fill.ts deleted file mode 100644 index f3f0b1ebb..000000000 --- a/packages/browser-webdriverio/src/commands/fill.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { UserEvent } from 'vitest/browser' -import type { UserEventCommand } from './utils' - -export const fill: UserEventCommand = async ( - context, - selector, - text, - _options = {}, -) => { - const browser = context.browser - await browser.$(selector).setValue(text) -} diff --git a/packages/browser-webdriverio/src/commands/hover.ts b/packages/browser-webdriverio/src/commands/hover.ts deleted file mode 100644 index 3a0f5d248..000000000 --- a/packages/browser-webdriverio/src/commands/hover.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { UserEvent } from 'vitest/browser' -import type { UserEventCommand } from './utils' - -export const hover: UserEventCommand = async ( - context, - selector, - options = {}, -) => { - const browser = context.browser - await browser.$(selector).moveTo(options as any) -} diff --git a/packages/browser-webdriverio/src/commands/index.ts b/packages/browser-webdriverio/src/commands/index.ts deleted file mode 100644 index 3fbb5b7f9..000000000 --- a/packages/browser-webdriverio/src/commands/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { clear } from './clear' -import { click, dblClick, tripleClick } from './click' -import { dragAndDrop } from './dragAndDrop' -import { fill } from './fill' -import { hover } from './hover' -import { keyboard, keyboardCleanup } from './keyboard' -import { takeScreenshot } from './screenshot' -import { selectOptions } from './select' -import { tab } from './tab' -import { type } from './type' -import { upload } from './upload' -import { viewport } from './viewport' -import { wheel } from './wheel' - -export default { - __vitest_upload: upload as typeof upload, - __vitest_click: click as typeof click, - __vitest_dblClick: dblClick as typeof dblClick, - __vitest_tripleClick: tripleClick as typeof tripleClick, - __vitest_wheel: wheel as typeof wheel, - __vitest_takeScreenshot: takeScreenshot as typeof takeScreenshot, - __vitest_type: type as typeof type, - __vitest_clear: clear as typeof clear, - __vitest_fill: fill as typeof fill, - __vitest_tab: tab as typeof tab, - __vitest_keyboard: keyboard as typeof keyboard, - __vitest_selectOptions: selectOptions as typeof selectOptions, - __vitest_dragAndDrop: dragAndDrop as typeof dragAndDrop, - __vitest_hover: hover as typeof hover, - __vitest_cleanup: keyboardCleanup as typeof keyboardCleanup, - __vitest_viewport: viewport as typeof viewport, -} diff --git a/packages/browser-webdriverio/src/commands/keyboard.ts b/packages/browser-webdriverio/src/commands/keyboard.ts deleted file mode 100644 index 6204e311f..000000000 --- a/packages/browser-webdriverio/src/commands/keyboard.ts +++ /dev/null @@ -1,125 +0,0 @@ -import type { BrowserProvider } from 'vitest/node' -import type { WebdriverBrowserProvider } from '../webdriverio' -import type { UserEventCommand } from './utils' -import { parseKeyDef } from '@vitest/browser' -import { Key } from 'webdriverio' - -export interface KeyboardState { - unreleased: string[] -} - -export const keyboard: UserEventCommand<( - text: string, - state: KeyboardState, -) => Promise<{ unreleased: string[] }>> = async ( - context, - text, - state, -) => { - await context.browser.execute(focusIframe) - - const pressed = new Set(state.unreleased) - - await keyboardImplementation( - pressed, - context.provider, - context.sessionId, - text, - async () => { - await context.browser.execute(selectAll) - }, - true, - ) - - return { - unreleased: Array.from(pressed), - } -} - -export const keyboardCleanup: UserEventCommand<(state: KeyboardState) => Promise> = async ( - context, - state, -) => { - if (!state.unreleased) { - return - } - const keyboard = context.browser.action('key') - for (const key of state.unreleased) { - keyboard.up(key) - } - await keyboard.perform() -} - -export async function keyboardImplementation( - pressed: Set, - provider: BrowserProvider, - _sessionId: string, - text: string, - selectAll: () => Promise, - skipRelease: boolean, -): Promise<{ pressed: Set }> { - const browser = (provider as WebdriverBrowserProvider).browser! - const actions = parseKeyDef(text) - - let keyboard = browser.action('key') - - for (const { releasePrevious, releaseSelf, repeat, keyDef } of actions) { - let key = keyDef.key! - const special = Key[key as 'Shift'] - - if (special) { - key = special - } - - if (pressed.has(key)) { - keyboard.up(key) - pressed.delete(key) - } - - if (!releasePrevious) { - if (key === 'selectall') { - await keyboard.perform() - keyboard = browser.action('key') - await selectAll() - continue - } - - for (let i = 1; i <= repeat; i++) { - keyboard.down(key) - } - - if (releaseSelf) { - keyboard.up(key) - } - else { - pressed.add(key) - } - } - } - - // seems like webdriverio doesn't release keys automatically if skipRelease is true and all events are keyUp - const allRelease = keyboard.toJSON().actions.every(action => action.type === 'keyUp') - - await keyboard.perform(allRelease ? false : skipRelease) - - return { - pressed, - } -} - -function focusIframe() { - if ( - !document.activeElement - || document.activeElement.ownerDocument !== document - || document.activeElement === document.body - ) { - window.focus() - } -} - -function selectAll() { - const element = document.activeElement as HTMLInputElement - if (element && typeof element.select === 'function') { - element.select() - } -} diff --git a/packages/browser-webdriverio/src/commands/screenshot.ts b/packages/browser-webdriverio/src/commands/screenshot.ts deleted file mode 100644 index 4ba84652f..000000000 --- a/packages/browser-webdriverio/src/commands/screenshot.ts +++ /dev/null @@ -1,73 +0,0 @@ -import type { ScreenshotOptions } from 'vitest/browser' -import type { BrowserCommandContext } from 'vitest/node' -import crypto from 'node:crypto' -import { mkdir, rm } from 'node:fs/promises' -import { normalize as platformNormalize } from 'node:path' -import { assertBrowserApiWrite, assertBrowserFileAccess, resolveScreenshotPath } from '@vitest/browser' -import { dirname, normalize, resolve } from 'pathe' - -interface ScreenshotCommandOptions extends Omit { - element?: string - mask?: readonly string[] -} - -/** - * Takes a screenshot using the provided browser context and returns a buffer and the expected screenshot path. - * - * **Note**: the returned `path` indicates where the screenshot *might* be found. - * It is not guaranteed to exist, especially if `options.save` is `false`. - * - * @throws {Error} If the function is not called within a test or if the browser provider does not support screenshots. - */ -export async function takeScreenshot( - context: BrowserCommandContext, - name: string, - options: Omit, -): Promise<{ buffer: Buffer; path: string }> { - if (!context.testPath) { - throw new Error(`Cannot take a screenshot without a test path`) - } - - const path = resolveScreenshotPath( - context.testPath, - name, - context.project.config, - options.path, - ) - - // playwright does not need a screenshot path if we don't intend to save it - let savePath: string | undefined - - if (options.save) { - savePath = normalize(path) - - assertBrowserApiWrite(context.project, savePath) - assertBrowserFileAccess(context.project, savePath) - - await mkdir(dirname(savePath), { recursive: true }) - } - - // webdriverio needs a path, so if one is not already set we create a temporary one - if (savePath === undefined) { - savePath = resolve(context.project.tmpDir, crypto.randomUUID()) - - await mkdir(context.project.tmpDir, { recursive: true }) - } - - const page = context.browser - const element = !options.element - ? await page.$('body') - : await page.$(`${options.element}`) - - // webdriverio expects the path to contain the extension and only works with PNG files - const savePathWithExtension = savePath.endsWith('.png') ? savePath : `${savePath}.png` - - // there seems to be a bug in webdriverio, `X:/` gets appended to cwd, so we convert to `X:\` - const buffer = await element.saveScreenshot( - platformNormalize(savePathWithExtension), - ) - if (!options.save) { - await rm(savePathWithExtension, { force: true }) - } - return { buffer, path } -} diff --git a/packages/browser-webdriverio/src/commands/select.ts b/packages/browser-webdriverio/src/commands/select.ts deleted file mode 100644 index 409633803..000000000 --- a/packages/browser-webdriverio/src/commands/select.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { UserEvent } from 'vitest/browser' -import type { UserEventCommand } from './utils' - -export const selectOptions: UserEventCommand = async ( - context, - selector, - userValues, - _options = {}, -) => { - const values = userValues as any as [({ index: number })] - - if (!values.length) { - return - } - - const browser = context.browser - - if (values.length === 1 && 'index' in values[0]) { - const selectElement = browser.$(selector) - await selectElement.selectByIndex(values[0].index) - } - else { - throw new Error('Provider "webdriverio" doesn\'t support selecting multiple values at once') - } -} diff --git a/packages/browser-webdriverio/src/commands/tab.ts b/packages/browser-webdriverio/src/commands/tab.ts deleted file mode 100644 index 3d9fc77b8..000000000 --- a/packages/browser-webdriverio/src/commands/tab.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { UserEvent } from 'vitest/browser' -import type { UserEventCommand } from './utils' -import { Key } from 'webdriverio' - -export const tab: UserEventCommand = async ( - context, - options = {}, -) => { - const browser = context.browser - await browser.keys(options.shift === true ? [Key.Shift, Key.Tab] : [Key.Tab]) -} diff --git a/packages/browser-webdriverio/src/commands/type.ts b/packages/browser-webdriverio/src/commands/type.ts deleted file mode 100644 index 24b71aa58..000000000 --- a/packages/browser-webdriverio/src/commands/type.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { UserEvent } from 'vitest/browser' -import type { UserEventCommand } from './utils' -import { keyboardImplementation } from './keyboard' - -export const type: UserEventCommand = async ( - context, - selector, - text, - options = {}, -) => { - const { skipClick = false, skipAutoClose = false } = options - const unreleased = new Set(Reflect.get(options, 'unreleased') as string[] ?? []) - - const browser = context.browser - const element = browser.$(selector) - - if (!skipClick && !await element.isFocused()) { - await element.click() - } - - await keyboardImplementation( - unreleased, - context.provider, - context.sessionId, - text, - () => browser.execute(() => { - const element = document.activeElement as HTMLInputElement - if (element && typeof element.select === 'function') { - element.select() - } - }), - skipAutoClose, - ) - - return { - unreleased: Array.from(unreleased), - } -} diff --git a/packages/browser-webdriverio/src/commands/upload.ts b/packages/browser-webdriverio/src/commands/upload.ts deleted file mode 100644 index cf5e98272..000000000 --- a/packages/browser-webdriverio/src/commands/upload.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { UserEventUploadOptions } from 'vitest/browser' -import type { UserEventCommand } from './utils' -import { assertBrowserFileAccess } from '@vitest/browser' -import { resolve } from 'pathe' - -export const upload: UserEventCommand<(element: string, files: Array, options: UserEventUploadOptions) => void> = async ( - context, - selector, - files, - _options, -) => { - const testPath = context.testPath - if (!testPath) { - throw new Error(`Cannot upload files outside of a test`) - } - const root = context.project.config.root - - for (const file of files) { - if (typeof file !== 'string') { - throw new TypeError(`The "${context.provider.name}" provider doesn't support uploading files objects. Provide a file path instead.`) - } - } - - const element = context.browser.$(selector) - - for (const file of files) { - const filepath = resolve(root, file as string) - assertBrowserFileAccess(context.project, filepath) - const remoteFilePath = await context.browser.uploadFile(filepath) - await element.addValue(remoteFilePath) - } -} diff --git a/packages/browser-webdriverio/src/commands/utils.ts b/packages/browser-webdriverio/src/commands/utils.ts deleted file mode 100644 index 89afac85a..000000000 --- a/packages/browser-webdriverio/src/commands/utils.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { Locator } from 'vitest/browser' -import type { BrowserCommand } from 'vitest/node' - -export type UserEventCommand any> = BrowserCommand< - ConvertUserEventParameters> -> - -type ConvertElementToLocator = T extends Element | Locator ? string : T -type ConvertUserEventParameters = { - [K in keyof T]: ConvertElementToLocator; -} diff --git a/packages/browser-webdriverio/src/commands/viewport.ts b/packages/browser-webdriverio/src/commands/viewport.ts deleted file mode 100644 index 98111fad6..000000000 --- a/packages/browser-webdriverio/src/commands/viewport.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { WebdriverBrowserProvider } from '../webdriverio' -import type { UserEventCommand } from './utils' - -export const viewport: UserEventCommand<(options: { - width: number - height: number -}) => void> = async (context, options) => { - await (context.provider as WebdriverBrowserProvider).setViewport(options) -} diff --git a/packages/browser-webdriverio/src/commands/wheel.ts b/packages/browser-webdriverio/src/commands/wheel.ts deleted file mode 100644 index 9a06417e8..000000000 --- a/packages/browser-webdriverio/src/commands/wheel.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Locator, UserEventWheelDeltaOptions } from 'vitest/browser' -import type { UserEventCommand } from './utils' - -type WheelCommand = (element: Locator | Element, options: UserEventWheelDeltaOptions) => Promise - -export const wheel: UserEventCommand = async ( - context, - selector, - options, -) => { - const browser = context.browser - const times = options.times ?? 1 - const deltaX = options.delta.x ?? 0 - const deltaY = options.delta.y ?? 0 - - let action = browser.action('wheel') - const wheelOptions: Parameters[0] = { - deltaX, - deltaY, - origin: browser.$(selector), - } - - for (let count = 0; count < times; count += 1) { - action = action.scroll(wheelOptions) - } - - await action.perform() -} diff --git a/packages/browser-webdriverio/src/constants.ts b/packages/browser-webdriverio/src/constants.ts deleted file mode 100644 index 7229579f4..000000000 --- a/packages/browser-webdriverio/src/constants.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { fileURLToPath } from 'node:url' -import { resolve } from 'pathe' - -const pkgRoot = resolve(fileURLToPath(import.meta.url), '../..') -export const distRoot: string = resolve(pkgRoot, 'dist') diff --git a/packages/browser-webdriverio/src/index.ts b/packages/browser-webdriverio/src/index.ts deleted file mode 100644 index c49f1550a..000000000 --- a/packages/browser-webdriverio/src/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { - WebdriverBrowserProvider, - webdriverio, - type WebdriverProviderOptions, -} from './webdriverio' -export { defineBrowserCommand } from '@vitest/browser' diff --git a/packages/browser-webdriverio/src/locators.ts b/packages/browser-webdriverio/src/locators.ts deleted file mode 100644 index e7210d1b9..000000000 --- a/packages/browser-webdriverio/src/locators.ts +++ /dev/null @@ -1,303 +0,0 @@ -import type { - LocatorScreenshotOptions, - UserEventClearOptions, - UserEventClickOptions, - UserEventDragAndDropOptions, - UserEventFillOptions, - UserEventHoverOptions, - UserEventSelectOptions, - UserEventWheelOptions, -} from 'vitest/browser' -import { - convertElementToCssSelector, - ensureAwaited, - getByAltTextSelector, - getByLabelSelector, - getByPlaceholderSelector, - getByRoleSelector, - getByTestIdSelector, - getByTextSelector, - getByTitleSelector, - getIframeScale, - Locator, - selectorEngine, - triggerCommandWithTrace, -} from '@vitest/browser/locators' -import { page, server, utils } from 'vitest/browser' -import { __INTERNAL } from 'vitest/internal/browser' - -class WebdriverIOLocator extends Locator { - constructor(protected _pwSelector: string, protected _container?: Element) { - super() - } - - // This exists to avoid calling `this.elements` in `this.selector`'s getter in interactive actions - private withElement(element: Element, error: Error | undefined) { - const pwSelector = selectorEngine.generateSelectorSimple(element) - const cssSelector = convertElementToCssSelector(element) - return new ElementWebdriverIOLocator(cssSelector, error, pwSelector, element) - } - - override get selector(): string { - const selectors = this.elements().map(element => convertElementToCssSelector(element)) - if (!selectors.length) { - throw utils.getElementError(this._pwSelector, this._container || document.body) - } - let hasShadowRoot = false - const newSelectors = selectors.map((selector) => { - if (selector.startsWith('>>>')) { - hasShadowRoot = true - return selector.slice(3) - } - return selector - }) - return (hasShadowRoot ? '>>>' : '') + newSelectors.join(', ') - } - - public override click(options?: UserEventClickOptions): Promise { - return ensureAwaited(async (error) => { - const element = await this.findElement(options) - return this.withElement(element, error).click(processClickOptions(options)) - }) - } - - public override dblClick(options?: UserEventClickOptions): Promise { - return ensureAwaited(async (error) => { - const element = await this.findElement(options) - return this.withElement(element, error).dblClick(processClickOptions(options)) - }) - } - - public override tripleClick(options?: UserEventClickOptions): Promise { - return ensureAwaited(async (error) => { - const element = await this.findElement(options) - return this.withElement(element, error).tripleClick(processClickOptions(options)) - }) - } - - public selectOptions( - value: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[], - options?: UserEventSelectOptions, - ): Promise { - return ensureAwaited(async (error) => { - const element = await this.findElement(options) - const values = getWebdriverioSelectOptions(element, value) - return triggerCommandWithTrace({ - name: '__vitest_selectOptions', - arguments: [convertElementToCssSelector(element), values, options], - errorSource: error, - }) - }) - } - - public override hover(options?: UserEventHoverOptions): Promise { - return ensureAwaited(async (error) => { - const element = await this.findElement(options) - return this.withElement(element, error).hover(processHoverOptions(options)) - }) - } - - public override dropTo(target: Locator, options?: UserEventDragAndDropOptions): Promise { - // playwright doesn't enforce a single element, it selects the first one, - // so we just follow the behavior - return super.dropTo(target, processDragAndDropOptions(options)) - } - - public override wheel(options: UserEventWheelOptions): Promise { - return ensureAwaited(async (error) => { - const element = await this.findElement(options) - return this.withElement(element, error).wheel(options) - }) - } - - public override clear(options?: UserEventClearOptions): Promise { - return ensureAwaited(async (error) => { - const element = await this.findElement(options) - return this.withElement(element, error).clear(options) - }) - } - - public override fill(text: string, options?: UserEventFillOptions): Promise { - return ensureAwaited(async (error) => { - const element = await this.findElement(options) - return this.withElement(element, error).fill(text, options) - }) - } - - public override screenshot(options?: LocatorScreenshotOptions): Promise { - return ensureAwaited(async (error) => { - const element = await this.findElement(options) - return this.withElement(element, error).screenshot(options) - }) - } - - // playwright doesn't enforce a single element in upload - // public override async upload(): Promise - - protected locator(selector: string) { - return new WebdriverIOLocator(`${this._pwSelector} >> ${selector}`, this._container) - } - - protected elementLocator(element: Element) { - return new WebdriverIOLocator(selectorEngine.generateSelectorSimple(element), element) - } -} - -const kElementLocator = Symbol.for('$$vitest:locator-resolved') - -class ElementWebdriverIOLocator extends Locator { - public [kElementLocator] = true - - constructor( - private _cssSelector: string, - protected _errorSource: Error | undefined, - protected _pwSelector: string, - protected _container: Element, - ) { - super() - } - - override get selector() { - return this._cssSelector - } - - protected locator(_selector: string): Locator { - throw new Error(`should not be called`) - } - - protected elementLocator(_element: Element): Locator { - throw new Error(`should not be called`) - } -} - -page.extend({ - getByLabelText(text, options) { - return new WebdriverIOLocator(getByLabelSelector(text, options)) - }, - getByRole(role, options) { - return new WebdriverIOLocator(getByRoleSelector(role, options)) - }, - getByTestId(testId) { - return new WebdriverIOLocator(getByTestIdSelector(server.config.browser.locators.testIdAttribute, testId)) - }, - getByAltText(text, options) { - return new WebdriverIOLocator(getByAltTextSelector(text, options)) - }, - getByPlaceholder(text, options) { - return new WebdriverIOLocator(getByPlaceholderSelector(text, options)) - }, - getByText(text, options) { - return new WebdriverIOLocator(getByTextSelector(text, options)) - }, - getByTitle(title, options) { - return new WebdriverIOLocator(getByTitleSelector(title, options)) - }, - - elementLocator(element: Element) { - return new WebdriverIOLocator(selectorEngine.generateSelectorSimple(element)) - }, -}) - -__INTERNAL._createLocator = selector => new WebdriverIOLocator(selector) - -function getWebdriverioSelectOptions(element: Element, value: string | string[] | HTMLElement[] | HTMLElement | Locator | Locator[]) { - const options = [...element.querySelectorAll('option')] as HTMLOptionElement[] - - const arrayValues = Array.isArray(value) ? value : [value] - - if (!arrayValues.length) { - return [] - } - - if (arrayValues.length > 1) { - throw new Error('Provider "webdriverio" doesn\'t support selecting multiple values at once') - } - - const optionValue = arrayValues[0] - - if (typeof optionValue !== 'string') { - const element = ('element' in optionValue ? optionValue.element() : optionValue) as HTMLOptionElement - const index = options.indexOf(element) - if (index === -1) { - throw new Error(`The element ${selectorEngine.previewNode(element)} was not found in the "select" options.`) - } - - return [{ index }] - } - - const valueIndex = options.findIndex(option => option.value === optionValue) - if (valueIndex !== -1) { - return [{ index: valueIndex }] - } - - const labelIndex = options.findIndex(option => - option.textContent?.trim() === optionValue || option.ariaLabel === optionValue, - ) - - if (labelIndex === -1) { - throw new Error(`The option "${optionValue}" was not found in the "select" options.`) - } - - return [{ index: labelIndex }] -} - -function processClickOptions(options?: UserEventClickOptions) { - // only ui scales the iframe, so we need to adjust the position - if (!options || !server.config.browser.ui) { - return options - } - if (options.x != null || options.y != null) { - const cache = {} - if (options.x != null) { - options.x = scaleCoordinate(options.x, cache) - } - if (options.y != null) { - options.y = scaleCoordinate(options.y, cache) - } - } - return options -} - -function processHoverOptions(options?: UserEventHoverOptions) { - // only ui scales the iframe, so we need to adjust the position - if (!options || !server.config.browser.ui) { - return options - } - const cache = {} - if (options.xOffset != null) { - options.xOffset = scaleCoordinate(options.xOffset, cache) - } - if (options.yOffset != null) { - options.yOffset = scaleCoordinate(options.yOffset, cache) - } - return options -} - -function processDragAndDropOptions(options?: UserEventDragAndDropOptions) { - // only ui scales the iframe, so we need to adjust the position - if (!options || !server.config.browser.ui) { - return options - } - const cache = {} - if (options.sourceX != null) { - options.sourceX = scaleCoordinate(options.sourceX, cache) - } - if (options.sourceY != null) { - options.sourceY = scaleCoordinate(options.sourceY, cache) - } - if (options.targetX != null) { - options.targetX = scaleCoordinate(options.targetX, cache) - } - if (options.targetY != null) { - options.targetY = scaleCoordinate(options.targetY, cache) - } - return options -} - -function scaleCoordinate(coordinate: number, cache: any) { - return Math.round(coordinate * getCachedScale(cache)) -} - -function getCachedScale(cache: { scale: number | undefined }) { - return cache.scale ??= getIframeScale() -} diff --git a/packages/browser-webdriverio/src/webdriverio.ts b/packages/browser-webdriverio/src/webdriverio.ts deleted file mode 100644 index 796390080..000000000 --- a/packages/browser-webdriverio/src/webdriverio.ts +++ /dev/null @@ -1,337 +0,0 @@ -import type { CustomComparatorsRegistry } from '@vitest/browser' -import type { Capabilities } from '@wdio/types' -import type { - ScreenshotComparatorRegistry, - ScreenshotMatcherOptions, - SelectorOptions, -} from 'vitest/browser' -import type { - BrowserCommand, - BrowserProvider, - BrowserProviderOption, - CDPSession, - TestProject, -} from 'vitest/node' -import type { ClickOptions, DragAndDropOptions, MoveToOptions, remote } from 'webdriverio' -import { defineBrowserProvider } from '@vitest/browser' - -import { resolve } from 'pathe' -import { createDebugger } from 'vitest/node' -import commands from './commands' -import { distRoot } from './constants' - -const debug = createDebugger('vitest:browser:wdio') - -const webdriverBrowsers = ['firefox', 'chrome', 'edge', 'safari'] as const -type WebdriverBrowser = (typeof webdriverBrowsers)[number] - -export interface WebdriverProviderOptions extends Partial< - Parameters[0] -> {} - -export function webdriverio(options: WebdriverProviderOptions = {}): BrowserProviderOption { - return defineBrowserProvider({ - name: 'webdriverio', - supportedBrowser: webdriverBrowsers, - options, - providerFactory(project) { - return new WebdriverBrowserProvider(project, options) - }, - }) -} - -export class WebdriverBrowserProvider implements BrowserProvider { - public name = 'webdriverio' as const - public supportsParallelism: boolean = false - - public browser: WebdriverIO.Browser | null = null - - private browserName!: WebdriverBrowser - private project!: TestProject - - private options?: WebdriverProviderOptions - - private closing = false - private iframeSwitched = false - private topLevelContext: string | undefined - - public initScripts: string[] = [ - resolve(distRoot, 'locators.js'), - ] - - getSupportedBrowsers(): readonly string[] { - return webdriverBrowsers - } - - constructor( - project: TestProject, - options: WebdriverProviderOptions, - ) { - // increase shutdown timeout because WDIO takes some extra time to kill the driver - if (!project.vitest.state._data.timeoutIncreased) { - project.vitest.state._data.timeoutIncreased = true - project.vitest.config.teardownTimeout += 10_000 - } - - this.closing = false - this.project = project - this.browserName = project.config.browser.name as WebdriverBrowser - this.options = options - - for (const [name, command] of Object.entries(commands)) { - project.browser!.registerCommand(name as any, command as BrowserCommand) - } - } - - isIframeSwitched(): boolean { - return this.iframeSwitched - } - - async switchToTestFrame(): Promise { - const browser = this.browser! - // support wdio@9 - if (browser.switchFrame) { - await browser.switchFrame(browser.$('iframe[data-vitest]')) - } - else { - const iframe = await browser.findElement( - 'css selector', - 'iframe[data-vitest]', - ) - await browser.switchToFrame(iframe) - } - this.iframeSwitched = true - } - - async switchToMainFrame(): Promise { - const page = this.browser! - if (page.switchFrame) { - await page.switchFrame(null) - } - else { - await page.switchToParentFrame() - } - this.iframeSwitched = false - } - - async setViewport(options: { width: number; height: number }): Promise { - if (this.topLevelContext == null || !this.browser) { - throw new Error(`The browser has no open pages.`) - } - if (this.browser.isBidi) { - await this.browser.send({ - method: 'browsingContext.setViewport', - params: { - context: this.topLevelContext, - devicePixelRatio: 1, - viewport: options, - }, - }) - } - else { - await this.browser.setWindowSize(options.width, options.height) - } - } - - getCommandsContext(): { - browser: WebdriverIO.Browser | null - } { - return { - browser: this.browser, - } - } - - async openBrowser(): Promise { - await this._throwIfClosing('opening the browser') - - if (this.browser) { - debug?.('[%s] the browser is already opened, reusing it', this.browserName) - return this.browser - } - - const options = this.project.config.browser - - if (this.browserName === 'safari') { - if (options.headless) { - throw new Error( - 'You\'ve enabled headless mode for Safari but it doesn\'t currently support it.', - ) - } - } - - const { remote } = await import('webdriverio') - - const remoteOptions: Capabilities.WebdriverIOConfig = { - logLevel: 'silent', - ...this.options, - capabilities: this.buildCapabilities(), - } - - debug?.('[%s] opening the browser with options: %O', this.browserName, remoteOptions) - // TODO: close everything, if browser is closed from the outside - this.browser = await remote(remoteOptions) - await this._throwIfClosing() - - return this.browser - } - - private buildCapabilities() { - const capabilities: Capabilities.WebdriverIOConfig['capabilities'] = { - ...this.options?.capabilities, - browserName: this.browserName, - } - - const headlessMap = { - chrome: ['goog:chromeOptions', ['headless', 'disable-gpu']], - firefox: ['moz:firefoxOptions', ['-headless']], - edge: ['ms:edgeOptions', ['--headless']], - } as const - - const options = this.project.config.browser - const browser = this.browserName - if (browser !== 'safari' && options.headless) { - const [key, args] = headlessMap[browser] - const currentValues = (this.options?.capabilities as any)?.[key] || {} - const newArgs = [...(currentValues.args || []), ...args] - capabilities[key] = { ...currentValues, args: newArgs as any } - } - - // start Vitest UI maximized only on supported browsers - if (options.ui && (browser === 'chrome' || browser === 'edge')) { - const key = browser === 'chrome' - ? 'goog:chromeOptions' - : 'ms:edgeOptions' - const args = capabilities[key]?.args || [] - if (!args.includes('--start-maximized') && !args.includes('--start-fullscreen')) { - args.push('--start-maximized') - } - capabilities[key] ??= {} - capabilities[key]!.args = args - } - - const inspector = this.project.vitest.config.inspector - if (inspector.enabled && (browser === 'chrome' || browser === 'edge')) { - const key = browser === 'chrome' - ? 'goog:chromeOptions' - : 'ms:edgeOptions' - const args = capabilities[key]?.args || [] - - // NodeJS equivalent defaults: https://nodejs.org/en/learn/getting-started/debugging#enable-inspector - const port = inspector.port || 9229 - const host = inspector.host || '127.0.0.1' - - args.push(`--remote-debugging-port=${port}`) - - if (host !== 'localhost' && host !== '127.0.0.1' && host !== '::1') { - this.project.vitest.logger.warn(`Custom inspector host "${host}" will be ignored. Chrome only allows remote debugging on localhost.`) - } - this.project.vitest.logger.log(`Debugger listening on ws://127.0.0.1:${port}`) - - capabilities[key] ??= {} - capabilities[key]!.args = args - } - - return capabilities - } - - async openPage(sessionId: string, url: string): Promise { - await this._throwIfClosing('creating the browser') - debug?.('[%s][%s] creating the browser page for %s', sessionId, this.browserName, url) - const browserInstance = await this.openBrowser() - debug?.('[%s][%s] browser page is created, opening %s', sessionId, this.browserName, url) - await browserInstance.url(url) - this.topLevelContext = await browserInstance.getWindowHandle() - await this._throwIfClosing('opening the url') - } - - private async _throwIfClosing(action?: string) { - if (this.closing) { - debug?.(`[%s] provider was closed, cannot perform the action${action ? ` ${action}` : ''}`, this.browserName) - await (this.browser?.sessionId ? this.browser?.deleteSession?.() : null) - throw new Error(`[vitest] The provider was closed.`) - } - } - - async close(): Promise { - debug?.('[%s] closing provider', this.browserName) - this.closing = true - const browser = this.browser - const sessionId = browser?.sessionId - if (!browser || !sessionId) { - return - } - - // https://github.com/webdriverio/webdriverio/blob/ab1a2e82b13a9c7d0e275ae87e7357e1b047d8d3/packages/wdio-runner/src/index.ts#L486 - await browser.deleteSession() - browser.sessionId = undefined as unknown as string - this.browser = null - } - - async getCDPSession(_sessionId: string): Promise { - return { - send: (method, params) => { - if (!this.browser) { - throw new Error(`The environment was torn down.`) - } - return this.browser.sendCommandAndGetResult(method, params ?? {}).catch((error) => { - return Promise.reject(new Error(`Failed to execute "${method}" command.`, { cause: error })) - }) - }, - on: () => { - throw new Error(`webdriverio provider doesn't support cdp.on()`) - }, - once: () => { - throw new Error(`webdriverio provider doesn't support cdp.once()`) - }, - off: () => { - throw new Error(`webdriverio provider doesn't support cdp.off()`) - }, - } - } -} - -declare module 'vitest/browser' { - export interface UserEventClickOptions extends Partial, SelectorOptions {} - export interface UserEventHoverOptions extends MoveToOptions, SelectorOptions {} - export interface UserEventDragAndDropOptions extends DragAndDropOptions { - sourceX?: number - sourceY?: number - targetX?: number - targetY?: number - } - export interface UserEventFillOptions extends SelectorOptions {} - export interface UserEventSelectOptions extends SelectorOptions {} - export interface UserEventClearOptions extends SelectorOptions {} - export interface UserEventDoubleClickOptions extends SelectorOptions {} - export interface UserEventTripleClickOptions extends SelectorOptions {} - export interface UserEventWheelBaseOptions extends SelectorOptions {} - export interface LocatorScreenshotOptions extends SelectorOptions {} -} - -interface WebdriverCDPSession { - send: (method: string, params?: Record) => Promise - on: (event: string, listener: (...args: unknown[]) => void) => void - once: (event: string, listener: (...args: unknown[]) => void) => void - off: (event: string, listener: (...args: unknown[]) => void) => void -} - -declare module 'vitest/node' { - export interface BrowserCommandContext { - browser: WebdriverIO.Browser - } - - export interface _BrowserNames { - webdriverio: WebdriverBrowser - } - - export interface ToMatchScreenshotOptions - extends Omit< - ScreenshotMatcherOptions, - 'comparatorName' | 'comparatorOptions' - >, CustomComparatorsRegistry {} - - export interface ToMatchScreenshotComparators - extends ScreenshotComparatorRegistry {} - - export interface CDPSession extends WebdriverCDPSession {} -} diff --git a/packages/browser-webdriverio/tsconfig.json b/packages/browser-webdriverio/tsconfig.json deleted file mode 100644 index 89c57bbd4..000000000 --- a/packages/browser-webdriverio/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "types": ["node", "vite/client"], - "isolatedDeclarations": true - }, - "exclude": [ - "dist", - "node_modules", - "**/vite.config.ts", - "src/client/**/*.ts" - ] -} diff --git a/packages/vitest/package.json b/packages/vitest/package.json index feab76d1b..946e40b94 100644 --- a/packages/vitest/package.json +++ b/packages/vitest/package.json @@ -138,7 +138,7 @@ "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "workspace:*", "@vitest/browser-preview": "workspace:*", - "@vitest/browser-webdriverio": "workspace:*", + "@vitest/browser-webdriverio": "^4.1.11", "@vitest/coverage-istanbul": "workspace:*", "@vitest/coverage-v8": "workspace:*", "@vitest/ui": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bc1b51866..2c1f8765e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -171,7 +171,6 @@ overrides: '@vitest/browser': workspace:* '@vitest/browser-playwright': workspace:* '@vitest/browser-preview': workspace:* - '@vitest/browser-webdriverio': workspace:* '@vitest/ui': workspace:* acorn: 8.11.3 mlly: ^1.8.0 @@ -626,22 +625,6 @@ importers: specifier: workspace:* version: link:../vitest - packages/browser-webdriverio: - dependencies: - '@vitest/browser': - specifier: workspace:* - version: link:../browser - devDependencies: - '@wdio/types': - specifier: ^9.24.0 - version: 9.24.0 - vitest: - specifier: workspace:* - version: link:../vitest - webdriverio: - specifier: ^9.20.0 - version: 9.20.0 - packages/coverage-istanbul: dependencies: '@babel/core': @@ -1030,8 +1013,8 @@ importers: specifier: workspace:* version: link:../browser-preview '@vitest/browser-webdriverio': - specifier: workspace:* - version: link:../browser-webdriverio + specifier: ^4.1.11 + version: 4.1.11(vitest@packages+vitest)(webdriverio@9.20.0) '@vitest/coverage-istanbul': specifier: workspace:* version: link:../coverage-istanbul @@ -1239,9 +1222,6 @@ importers: '@vitest/browser-preview': specifier: workspace:* version: link:../../packages/browser-preview - '@vitest/browser-webdriverio': - specifier: workspace:* - version: link:../../packages/browser-webdriverio '@vitest/bundled-lib': specifier: link:./bundled-lib version: link:bundled-lib @@ -1314,9 +1294,6 @@ importers: '@vitest/browser-preview': specifier: workspace:* version: link:../../packages/browser-preview - '@vitest/browser-webdriverio': - specifier: workspace:* - version: link:../../packages/browser-webdriverio '@vitest/mocker': specifier: workspace:* version: link:../../packages/mocker @@ -1428,9 +1405,6 @@ importers: '@vitest/browser-preview': specifier: workspace:* version: link:../../packages/browser-preview - '@vitest/browser-webdriverio': - specifier: workspace:* - version: link:../../packages/browser-webdriverio '@vitest/test-dep-optimizer-external': specifier: file:./deps/optimizer/external version: file:test/config/deps/optimizer/external @@ -5608,6 +5582,12 @@ packages: '@vitejs/test-dep-virtual@file:test/config/deps/test-dep-virtual': resolution: {directory: test/config/deps/test-dep-virtual, type: directory} + '@vitest/browser-webdriverio@4.1.11': + resolution: {integrity: sha512-utftie0XLjhATDCCRAaCZFVlosjQX6mF8UK+mo0q2yTn+XASUdz21tqvAA6fYRgLDiHAIVI06cBaKAklRp4UVA==} + peerDependencies: + vitest: workspace:* + webdriverio: '*' + '@vitest/cjs-lib@file:test/browser/cjs-lib': resolution: {directory: test/browser/cjs-lib, type: directory} @@ -5888,10 +5868,6 @@ packages: resolution: {integrity: sha512-zMmAtse2UMCSOW76mvK3OejauAdcFGuKopNRH7crI0gwKTZtvV89yXWRziz9cVXpFgfmJCjf9edxKFWdhuF5yw==} engines: {node: '>=18.20.0'} - '@wdio/types@9.24.0': - resolution: {integrity: sha512-PYYunNl8Uq1r8YMJAK6ReRy/V/XIrCSyj5cpCtR5EqCL6heETOORFj7gt4uPnzidfgbtMBcCru0LgjjlMiH1UQ==} - engines: {node: '>=18.20.0'} - '@wdio/utils@9.20.0': resolution: {integrity: sha512-T1ze005kncUTocYImSBQc/FAVcOwP/vOU4MDJFgzz/RTcps600qcKX98sVdWM5/ukXCVkjOufWteDHIbX5/tEA==} engines: {node: '>=18.20.0'} @@ -13193,7 +13169,7 @@ snapshots: extract-zip: 2.0.1 progress: 2.0.3 proxy-agent: 6.5.0 - semver: 7.7.4 + semver: 7.8.4 tar-fs: 3.0.8 yargs: 17.7.2 transitivePeerDependencies: @@ -14214,6 +14190,12 @@ snapshots: '@vitejs/test-dep-virtual@file:test/config/deps/test-dep-virtual': {} + '@vitest/browser-webdriverio@4.1.11(vitest@packages+vitest)(webdriverio@9.20.0)': + dependencies: + '@vitest/browser': link:packages/browser + vitest: link:packages/vitest + webdriverio: 9.20.0 + '@vitest/cjs-lib@file:test/browser/cjs-lib': {} '@vitest/eslint-plugin@1.6.9(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3)(vitest@packages+vitest)': @@ -14542,10 +14524,6 @@ snapshots: dependencies: '@types/node': 24.12.0 - '@wdio/types@9.24.0': - dependencies: - '@types/node': 24.12.0 - '@wdio/utils@9.20.0': dependencies: '@puppeteer/browsers': 2.7.1 @@ -20046,7 +20024,7 @@ snapshots: deepmerge-ts: 7.1.5 https-proxy-agent: 7.0.6 undici: 6.21.3 - ws: 8.19.0 + ws: 8.21.0 transitivePeerDependencies: - bufferutil - supports-color diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 47b091f74..a2deae7ea 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -31,7 +31,6 @@ overrides: '@vitest/browser': workspace:* '@vitest/browser-playwright': workspace:* '@vitest/browser-preview': workspace:* - '@vitest/browser-webdriverio': workspace:* '@vitest/ui': workspace:* acorn: 8.11.3 mlly: ^1.8.0 diff --git a/test/browser/README.md b/test/browser/README.md index f4217a00f..34a949d0e 100644 --- a/test/browser/README.md +++ b/test/browser/README.md @@ -14,7 +14,7 @@ BROWSER=chromium pnpm run test:playwright pnpm run test-fixtures --root ./fixtures/locators # run specific fixture with selected provider and browser -PROVIDER=webdriverio BROWSER=firefox pnpm run test-fixtures --root ./fixtures/locators +PROVIDER=playwright BROWSER=firefox pnpm run test-fixtures --root ./fixtures/locators ``` ## Using docker playwright diff --git a/test/browser/fixtures/browser-crash/vitest.config.ts b/test/browser/fixtures/browser-crash/vitest.config.ts index 4aaf57d98..a1ff489b4 100644 --- a/test/browser/fixtures/browser-crash/vitest.config.ts +++ b/test/browser/fixtures/browser-crash/vitest.config.ts @@ -16,17 +16,6 @@ const forceCrash: BrowserCommand<[]> = async (context) => { throw new Error(`Browser crash not supported for ${browser}`) } - if (context.provider.name === 'webdriverio') { - const browser = context.browser - const name = context.project.config.browser.name - if (name === 'chrome') { - await browser.url('chrome://crash') - } - if (name === 'firefox') { - await browser.url('about:crashcontent') - } - throw new Error(`Browser crash not supported for ${name}`) - } } export default defineConfig({ diff --git a/test/browser/fixtures/inspect/vitest.config.ts b/test/browser/fixtures/inspect/vitest.config.ts index 3e50a726c..3485d3409 100644 --- a/test/browser/fixtures/inspect/vitest.config.ts +++ b/test/browser/fixtures/inspect/vitest.config.ts @@ -9,7 +9,7 @@ export default defineConfig({ enabled: true, provider, instances: [ - { browser: provider.name === 'webdriverio' ? "chrome" : "chromium" }, + { browser: "chromium" }, ], headless: true, }, diff --git a/test/browser/fixtures/inspect/vitest.config.with-workspace.ts b/test/browser/fixtures/inspect/vitest.config.with-workspace.ts index 90fa31391..f3b97d134 100644 --- a/test/browser/fixtures/inspect/vitest.config.with-workspace.ts +++ b/test/browser/fixtures/inspect/vitest.config.with-workspace.ts @@ -15,7 +15,7 @@ export default defineConfig({ enabled: true, headless: true, instances: [ - { browser: provider.name === 'webdriverio' ? "chrome" : "chromium" }, + { browser: "chromium" }, ], }, }, diff --git a/test/browser/fixtures/server-url/vitest.config.ts b/test/browser/fixtures/server-url/vitest.config.ts index 78c525250..44cad72f5 100644 --- a/test/browser/fixtures/server-url/vitest.config.ts +++ b/test/browser/fixtures/server-url/vitest.config.ts @@ -9,11 +9,9 @@ import { instances, providers, provider } from '../../settings' // ignore https errors due to self-signed certificate from plugin-basic-ssl // https://playwright.dev/docs/api/class-browser#browser-new-context-option-ignore-https-errors -// https://webdriver.io/docs/configuration/#strictssl and acceptInsecureCerts in https://webdriver.io/docs/api/browser/#properties const configuredProvider = (function () { switch (provider.name) { case 'playwright': return providers.playwright() - case 'webdriverio': return providers.webdriverio({ strictSSL: false, capabilities: { acceptInsecureCerts: true } }) default: { throw new Error(`Invalid provider: ${provider.name}`) } diff --git a/test/browser/fixtures/user-event/clipboard.test.ts b/test/browser/fixtures/user-event/clipboard.test.ts index 0b65562e4..34c8708e5 100644 --- a/test/browser/fixtures/user-event/clipboard.test.ts +++ b/test/browser/fixtures/user-event/clipboard.test.ts @@ -2,7 +2,6 @@ import { expect, test } from 'vitest'; import { page, userEvent } from 'vitest/browser'; test('clipboard', async () => { - // make it smaller since webdriverio fails when scaled page.viewport(300, 300) document.body.innerHTML = ` diff --git a/test/browser/fixtures/user-event/keyboard.test.ts b/test/browser/fixtures/user-event/keyboard.test.ts index 8792f70ba..84f0ed699 100644 --- a/test/browser/fixtures/user-event/keyboard.test.ts +++ b/test/browser/fixtures/user-event/keyboard.test.ts @@ -15,7 +15,6 @@ test('non US keys', async () => { await expect.element(page.getByPlaceholder("fill-#7396")).toHaveValue('éèù') // playwright: garbled characters - // webdriverio: error: invalid argument: missing command parameters // preview: ok if (server.provider === 'playwright') { await userEvent.type(page.getByPlaceholder("type-emoji"), '😊😍') @@ -24,31 +23,15 @@ test('non US keys', async () => { } else { await expect.element(page.getByPlaceholder("type-emoji")).toHaveValue('😊😍') } - } else if (server.provider === 'webdriverio') { - await expect(() => - userEvent.type(page.getByPlaceholder("type-emoji"), '😊😍') - ).rejects.toThrow() } else { await userEvent.type(page.getByPlaceholder("type-emoji"), '😊😍') await expect.element(page.getByPlaceholder("type-emoji")).toHaveValue('😊😍') } // playwright: ok - // webdriverio: error: ChromeDriver only supports characters in the BMP // preview: ok - if (server.provider === 'webdriverio') { - if (server.browser === 'firefox') { - await userEvent.fill(page.getByPlaceholder("fill-emoji"), '😊😍') - await expect.element(page.getByPlaceholder("fill-emoji")).toHaveValue('😊😍') - } else { - await expect(() => - userEvent.fill(page.getByPlaceholder("fill-emoji"), '😊😍') - ).rejects.toThrow() - } - } else { - await userEvent.fill(page.getByPlaceholder("fill-emoji"), '😊😍') - await expect.element(page.getByPlaceholder("fill-emoji")).toHaveValue('😊😍') - } + await userEvent.fill(page.getByPlaceholder("fill-emoji"), '😊😍') + await expect.element(page.getByPlaceholder("fill-emoji")).toHaveValue('😊😍') }) test('click with modifier', async () => { @@ -63,7 +46,6 @@ test('click with modifier', async () => { }); await userEvent.keyboard('{Shift>}') - // By using an empty object as the option, this opts in to using a chain of actions instead of an elementClick in webdriver. await userEvent.click(el, {}) await userEvent.keyboard('{/Shift}') await expect.poll(() => el.textContent).toContain("[ok]") @@ -73,7 +55,6 @@ test('click with modifier', async () => { // https://testing-library.com/docs/user-event/keyboard // https://github.com/testing-library/user-event/blob/main/src/keyboard/keyMap.ts // https://playwright.dev/docs/api/class-keyboard -// https://webdriver.io/docs/api/browser/keys/ test('special keys', async () => { async function testKeyboard(text: string) { let data: any; @@ -99,14 +80,6 @@ test('special keys', async () => { expect(await testKeyboard('[ShiftLeft]')).toMatchInlineSnapshot(`"Shift|ShiftLeft|1"`); expect(await testKeyboard('[ShiftRight]')).toMatchInlineSnapshot(`"Shift|ShiftLeft|1"`); } - if (server.provider === 'webdriverio') { - expect(await testKeyboard('{Shift}')).toMatchInlineSnapshot(`"Shift|ShiftLeft|1"`); - expect(await testKeyboard('{ShiftLeft}')).toMatchInlineSnapshot(`"ERROR"`); - expect(await testKeyboard('{ShiftRight}')).toMatchInlineSnapshot(`"ERROR"`); - expect(await testKeyboard('[Shift]')).toMatchInlineSnapshot(`"ERROR"`); - expect(await testKeyboard('[ShiftLeft]')).toMatchInlineSnapshot(`"Shift|ShiftLeft|1"`); - expect(await testKeyboard('[ShiftRight]')).toMatchInlineSnapshot(`"Shift|ShiftLeft|1"`); - } if (server.provider === 'preview') { expect(await testKeyboard('{Shift}')).toMatchInlineSnapshot(`"Shift|ShiftLeft|0"`); expect(await testKeyboard('{ShiftLeft}')).toMatchInlineSnapshot(`"ShiftLeft|Unknown|0"`); diff --git a/test/browser/package.json b/test/browser/package.json index ce82afe9e..faab58ee4 100644 --- a/test/browser/package.json +++ b/test/browser/package.json @@ -3,11 +3,9 @@ "type": "module", "private": true, "scripts": { - "test": "pnpm run test:webdriverio && pnpm run test:playwright", + "test": "pnpm run test:playwright", "test:unit": "vitest --no-watch --config=vitest.config.unit.mts", - "test:webdriverio": "PROVIDER=webdriverio pnpm run test:unit", "test:playwright": "PROVIDER=playwright pnpm run test:unit", - "test:safaridriver": "PROVIDER=webdriverio BROWSER=safari pnpm run test:unit", "test-fixtures": "vitest", "test-expect-dom": "vitest --root ./fixtures/expect-dom", "test-mocking": "vitest --root ./fixtures/mocking", @@ -25,7 +23,6 @@ "coverage": "vitest --coverage.enabled --coverage.provider=istanbul --browser.headless=yes", "test:browser:preview": "PROVIDER=preview vitest", "test:browser:playwright": "PROVIDER=playwright vitest", - "test:browser:webdriverio": "PROVIDER=webdriverio vitest", "test:browser:playwright:html": "PROVIDER=playwright vitest --reporter=html", "docker": "docker compose" }, @@ -36,7 +33,6 @@ "@vitest/browser": "workspace:*", "@vitest/browser-playwright": "workspace:*", "@vitest/browser-preview": "workspace:*", - "@vitest/browser-webdriverio": "workspace:*", "@vitest/bundled-lib": "link:./bundled-lib", "@vitest/cjs-lib": "link:./cjs-lib", "playwright": "catalog:", diff --git a/test/browser/settings.ts b/test/browser/settings.ts index 87f43d4d1..8c3fc4fc4 100644 --- a/test/browser/settings.ts +++ b/test/browser/settings.ts @@ -1,9 +1,8 @@ import type { BrowserInstanceOption } from 'vitest/node' import { playwright } from '@vitest/browser-playwright' import { preview } from '@vitest/browser-preview' -import { webdriverio } from '@vitest/browser-webdriverio' -const providerName = (process.env.PROVIDER || 'playwright') as 'playwright' | 'webdriverio' | 'preview' +const providerName = (process.env.PROVIDER || 'playwright') as 'playwright' | 'preview' const wsEndpoint = process.env.BROWSER_WS_ENDPOINT === 'true' ? 'ws://127.0.0.1:6677/' : process.env.BROWSER_WS_ENDPOINT @@ -18,41 +17,6 @@ export const providers = { } : options), preview, - webdriverio: (options?: Parameters[0]) => { - const capabilities = options?.capabilities || {} - - return webdriverio({ - ...options, - capabilities: { - ...capabilities, - // Explicit browser/driver binaries keep WebDriverIO from auto-downloading mismatched versions. - // https://webdriver.io/docs/driverbinaries - // https://webdriver.io/docs/capabilities#webdriverio-capabilities-to-manage-browser-driver-options - ...(process.env.CHROMEDRIVER_PATH && process.env.CHROME_BIN - ? { - 'wdio:chromedriverOptions': { - ...(capabilities as any)['wdio:chromedriverOptions'], - binary: process.env.CHROMEDRIVER_PATH, - }, - // https://developer.chrome.com/docs/chromedriver/capabilities#chromeoptions-object - 'goog:chromeOptions': { - ...(capabilities as any)['goog:chromeOptions'], - binary: process.env.CHROME_BIN, - }, - } - : {}), - ...(process.env.FIREFOX_BIN - ? { - // https://developer.mozilla.org/en-US/docs/Web/WebDriver/Reference/Capabilities/firefoxOptions - 'moz:firefoxOptions': { - ...(capabilities as any)['moz:firefoxOptions'], - binary: process.env.FIREFOX_BIN, - }, - } - : {}), - }, - }) - }, } export const provider = providers[providerName]() @@ -65,7 +29,7 @@ const playwrightInstances: BrowserInstanceOption[] = [ ...(process.env.BROWSER_NO_WEBKIT ? [] : [{ browser: 'webkit' as const }]), ] -const webdriverioInstances: BrowserInstanceOption[] = [ +const previewInstances: BrowserInstanceOption[] = [ { browser: 'chrome' }, { browser: 'firefox' }, ] @@ -82,4 +46,4 @@ export const instances: BrowserInstanceOption[] = process.env.BROWSER ] : provider.name === 'playwright' ? playwrightInstances - : webdriverioInstances + : previewInstances diff --git a/test/browser/specs/multiple-different-configs.test.ts b/test/browser/specs/multiple-different-configs.test.ts index eb25d39c3..bf473b785 100644 --- a/test/browser/specs/multiple-different-configs.test.ts +++ b/test/browser/specs/multiple-different-configs.test.ts @@ -12,14 +12,3 @@ test.runIf(provider.name === 'playwright')('[playwright] runs multiple different expect(stdout).toContain('[chromium] HTML_INJECTED_VAR is true') expect(stdout).toContain('[firefox] HTML_INJECTED_VAR is undefined') }) - -test.runIf(provider.name === 'webdriverio')('[webdriverio] runs multiple different configurations correctly', async () => { - const { stdout, exitCode, stderr } = await runBrowserTests({ - root: './fixtures/multiple-different-configs', - }) - - expect(stderr).toBe('') - expect(exitCode).toBe(0) - expect(stdout).toContain('[chromium] HTML_INJECTED_VAR is true') - expect(stdout).toContain('[firefox] HTML_INJECTED_VAR is undefined') -}) diff --git a/test/browser/specs/runner.test.ts b/test/browser/specs/runner.test.ts index 5808d9e98..b53e6bea4 100644 --- a/test/browser/specs/runner.test.ts +++ b/test/browser/specs/runner.test.ts @@ -282,9 +282,7 @@ test('user-event', async () => { const { stdout, stderr } = await runBrowserTests({ root: './fixtures/user-event', }) - if (provider.name !== 'webdriverio') { - expect(stderr).toBe('') - } + expect(stderr).toBe('') onTestFailed(() => console.error(stderr)) instances.forEach(({ browser }) => { expect(stdout).toReportPassedTest('cleanup-retry.test.ts', browser) @@ -304,9 +302,6 @@ test('timeout settings', async () => { expect(stderr).toContain('locator.click: Timeout 500ms exceeded.') expect(stderr).toContain('locator.click: Timeout 345ms exceeded.') } - if (provider.name === 'webdriverio') { - expect(stderr).toContain('Cannot find element with locator') - } }) test('viewport', async () => { diff --git a/test/browser/test/dom.test.ts b/test/browser/test/dom.test.ts index a7115b93d..be26dd589 100644 --- a/test/browser/test/dom.test.ts +++ b/test/browser/test/dom.test.ts @@ -1,6 +1,6 @@ import { createNode } from '#src/createNode' import { afterAll, beforeEach, describe, expect, test } from 'vitest' -import { page, server } from 'vitest/browser' +import { page } from 'vitest/browser' import '../src/button.css' afterAll(() => { @@ -115,25 +115,6 @@ describe('dom related activity', () => { /__screenshots__\/dom.test.ts\/dom-related-activity-svg-screenshot-1.png/, ) }) - - test.runIf(server.provider === 'webdriverio')('shadow dom works with multiple elements', async () => { - const wrapper = createWrapper() - const div = createNode() - wrapper.appendChild(div) - - const shadow = div.attachShadow({ mode: 'open' }) - const shadowDiv1 = createNode() - shadowDiv1.role = 'tab' - const shadowDiv2 = createNode() - shadowDiv2.role = 'tab' - shadow.appendChild(shadowDiv1) - shadow.appendChild(shadowDiv2) - - expect( - page.getByRole('tab').selector, - 'there is only a single >>> in the selector', - ).toBe('>>>html > body > div > div > div, html > body > div > div > div') - }) }) function createWrapper() { diff --git a/test/browser/test/userEvent.test.ts b/test/browser/test/userEvent.test.ts index 6e0cd6f6a..468a71ab2 100644 --- a/test/browser/test/userEvent.test.ts +++ b/test/browser/test/userEvent.test.ts @@ -767,7 +767,6 @@ describe('userEvent.keyboard', async () => { ]) }) - // looks like wdio doesn't support releasing Enter on its own test('should not auto release', async () => { const spyKeydown = vi.fn() const spyKeyup = vi.fn() @@ -928,8 +927,7 @@ describe.each([ expect(select.value).toBe('2') }) - // webdriverio doesn't support selecting multiple values - describe.skipIf(server.provider === 'webdriverio')('multiple values', () => { + describe('multiple values', () => { test('can select multiple values', async () => { const { select, options } = createSelect() select.multiple = true @@ -972,7 +970,7 @@ describe.each([ }) describe('uploading files', async () => { - test.skipIf(server.provider === 'webdriverio')('can upload an instance of File', async () => { + test('can upload an instance of File', async () => { const file = new File(['hello'], 'hello.png', { type: 'image/png' }) const input = document.createElement('input') input.id = 'file' @@ -987,7 +985,7 @@ describe('uploading files', async () => { expect(await uploadedFile.text()).toBe('hello') }) - test.skipIf(server.provider === 'webdriverio')('can upload several instances of File', async () => { + test('can upload several instances of File', async () => { const file1 = new File(['hello1'], 'hello1.png', { type: 'image/png' }) const file2 = new File(['hello2'], 'hello2.png', { type: 'image/png' }) const input = document.createElement('input') @@ -1007,9 +1005,7 @@ describe('uploading files', async () => { expect(uploadedFile2.type).toBe('image/png') }) - test.skipIf( - server.provider === 'webdriverio' && server.browser === 'firefox', - )('can upload a file by filepath relative to test file', async () => { + test('can upload a file by filepath relative to test file', async () => { const input = document.createElement('input') input.id = 'file' input.type = 'file' @@ -1022,9 +1018,7 @@ describe('uploading files', async () => { expect(uploadedFile.type).toBe('text/css') }) - test.skipIf( - server.provider === 'webdriverio' && server.browser === 'firefox', - )('can upload several files by filepath relative to test file', async () => { + test('can upload several files by filepath relative to test file', async () => { const input = document.createElement('input') input.id = 'file' input.type = 'file' diff --git a/test/cli/package.json b/test/cli/package.json index 92c675cb6..093f94d09 100644 --- a/test/cli/package.json +++ b/test/cli/package.json @@ -22,7 +22,6 @@ "@vitejs/plugin-basic-ssl": "^2.1.4", "@vitest/browser-playwright": "workspace:*", "@vitest/browser-preview": "workspace:*", - "@vitest/browser-webdriverio": "workspace:*", "@vitest/mocker": "workspace:*", "@vitest/runner": "workspace:*", "@vitest/utils": "workspace:*", diff --git a/test/cli/test/config/browser-configs.test.ts b/test/cli/test/config/browser-configs.test.ts index ce8cf63fd..29a73e618 100644 --- a/test/cli/test/config/browser-configs.test.ts +++ b/test/cli/test/config/browser-configs.test.ts @@ -467,21 +467,6 @@ test('core provider has options if `provider` is playwright', async () => { }) }) -test('core provider has options if `provider` is wdio', async () => { - const v = await vitest({}, { - browser: { - enabled: true, - provider: playwright({ contextOptions: { hasTouch: true } }), - instances: [ - { browser: 'chrome' }, - ], - }, - }) - expect(v.config.browser.provider?.options).toEqual({ - contextOptions: { hasTouch: true }, - }) -}) - test('core provider has options if `provider` is preview', async () => { const v = await vitest({}, { browser: { diff --git a/test/cli/test/mocking.test.ts b/test/cli/test/mocking.test.ts index c3a14c8d2..fe2e55bc7 100644 --- a/test/cli/test/mocking.test.ts +++ b/test/cli/test/mocking.test.ts @@ -1,16 +1,10 @@ import type { RunVitestConfig } from '../../test-utils' -import { setDefaultResultOrder } from 'node:dns' import path from 'node:path' import { playwright } from '@vitest/browser-playwright' -import { webdriverio } from '@vitest/browser-webdriverio' -import { afterAll, expect, test } from 'vitest' +import { expect, test } from 'vitest' import { rolldownVersion } from 'vitest/node' import { runInlineTests, runVitest } from '../../test-utils' -// webdriver@9 sets dns.setDefaultResultOrder("ipv4first") on import, -// which makes Vite resolve localhost to 127.0.0.1 and breaks other tests asserting "localhost" -afterAll(() => setDefaultResultOrder('verbatim')) - test('setting resetMocks works if restoreMocks is also set', async () => { const { stderr, testTree } = await runInlineTests({ 'vitest.config.js': { @@ -146,15 +140,6 @@ test('redirect mock works without loading broken original', () => { `) }) -function replaceRoot(tree: any, root: string): any { - for (const child of Object.values(tree) as any[]) { - if (child?.__module_errors__) { - child.__module_errors__ = child.__module_errors__.map((e: string) => e.replace(root, '')) - } - } - return tree -} - function modeToConfig(mode: string): RunVitestConfig { if (mode === 'playwright') { return { @@ -166,34 +151,11 @@ function modeToConfig(mode: string): RunVitestConfig { }, } } - if (mode === 'webdriverio') { - return { - browser: { - enabled: true, - provider: webdriverio({ - ...(process.env.CHROMEDRIVER_PATH && process.env.CHROME_BIN - ? { - 'wdio:chromedriverOptions': { - binary: process.env.CHROMEDRIVER_PATH, - }, - 'capabilities': { - 'goog:chromeOptions': { - binary: process.env.CHROME_BIN, - }, - }, - } - : {}), - }), - instances: [{ browser: 'chrome' }], - headless: true, - }, - } - } return {} } -test.for(['node', 'playwright', 'webdriverio'])('importOriginal for virtual modules (%s)', async (mode) => { - const { stderr, errorTree, root } = await runInlineTests({ +test.for(['node', 'playwright'])('importOriginal for virtual modules (%s)', async (mode) => { + const { stderr, errorTree } = await runInlineTests({ 'vitest.config.js': ` import { defineConfig } from 'vitest/config' export default defineConfig({ @@ -227,36 +189,17 @@ test('importOriginal returns original virtual module exports', () => { `, }, modeToConfig(mode)) - // webdriverio uses a server-side interceptor plugin whose load hook - // intercepts the clean id, so importActual returns the mock instead - // of the original module. This is a known limitation. - if (mode === 'webdriverio') { - expect(replaceRoot(errorTree(), root)).toMatchInlineSnapshot(` - { - "__unhandled_errors__": [ - "[vitest] There was an error when mocking a module. If you are using "vi.mock" factory, make sure there are no top level variables inside, since this call is hoisted to top of the file. Read more: https://vitest.dev/api/vi.html#vi-mock", - ], - "basic.test.js": { - "__module_errors__": [ - "Failed to import test file /basic.test.js", - ], - }, - } - `) - } - else { - expect(stderr).toBe('') - expect(errorTree()).toMatchInlineSnapshot(` - { - "basic.test.js": { - "importOriginal returns original virtual module exports": "passed", - }, - } - `) - } + expect(stderr).toBe('') + expect(errorTree()).toMatchInlineSnapshot(` + { + "basic.test.js": { + "importOriginal returns original virtual module exports": "passed", + }, + } + `) }) -test.for(['node', 'playwright', 'webdriverio'])('mocking virtual module without importOriginal skips loading original (%s)', async (mode) => { +test.for(['node', 'playwright'])('mocking virtual module without importOriginal skips loading original (%s)', async (mode) => { const { stderr, testTree } = await runInlineTests({ 'vitest.config.js': ` import { defineConfig } from 'vitest/config' @@ -300,8 +243,8 @@ test('mock works without loading original', () => { `) }) -test.for(['node', 'playwright', 'webdriverio'])('mocking actual module with factory skips loading original (%s)', async (mode) => { - const { stderr, errorTree, root } = await runInlineTests({ +test.for(['node', 'playwright'])('mocking actual module with factory skips loading original (%s)', async (mode) => { + const { stderr, errorTree } = await runInlineTests({ 'vitest.config.js': ` import { defineConfig } from 'vitest/config' export default defineConfig({ @@ -330,19 +273,6 @@ test('mock works without loading original', () => { `, }, modeToConfig(mode)) - if (mode === 'webdriverio') { - expect(replaceRoot(errorTree(), root)).toMatchInlineSnapshot(` - { - "basic.test.js": { - "__module_errors__": [ - "Failed to import test file /basic.test.js", - ], - }, - } - `) - return - } - expect(stderr).toBe('') expect(errorTree()).toMatchInlineSnapshot(` { @@ -353,8 +283,8 @@ test('mock works without loading original', () => { `) }) -test.for(['node', 'playwright', 'webdriverio'])('mocking actual module via __mocks__ skips loading original (%s)', async (mode) => { - const { stderr, errorTree, root } = await runInlineTests({ +test.for(['node', 'playwright'])('mocking actual module via __mocks__ skips loading original (%s)', async (mode) => { + const { stderr, errorTree } = await runInlineTests({ 'vitest.config.js': ` import { defineConfig } from 'vitest/config' export default defineConfig({ @@ -382,19 +312,6 @@ test('mock works without loading original', () => { `, }, modeToConfig(mode)) - if (mode === 'webdriverio') { - expect(replaceRoot(errorTree(), root)).toMatchInlineSnapshot(` - { - "basic.test.js": { - "__module_errors__": [ - "Failed to import test file /basic.test.js", - ], - }, - } - `) - return - } - expect(stderr).toBe('') expect(errorTree()).toMatchInlineSnapshot(` { @@ -449,7 +366,6 @@ ${importChecks} test.for([ 'node', 'playwright', - 'webdriverio', ])('repeating mock, importActual, and resetModules (%s)', async (mode) => { const { stderr, errorTree } = await runInlineTests({ // external @@ -551,7 +467,7 @@ test("local", async () => { './local.js': `export const local = 'local'`, }, modeToConfig(mode)) - if (mode === 'webdriverio' || mode === 'playwright') { + if (mode === 'playwright') { // browser mode doesn't support resetModules nor node builtin expect(errorTree()).toMatchInlineSnapshot(` { diff --git a/test/config/package.json b/test/config/package.json index 13d5ea706..00e608650 100644 --- a/test/config/package.json +++ b/test/config/package.json @@ -10,7 +10,6 @@ "@vitejs/test-dep-virtual": "file:./deps/test-dep-virtual", "@vitest/browser-playwright": "workspace:*", "@vitest/browser-preview": "workspace:*", - "@vitest/browser-webdriverio": "workspace:*", "@vitest/test-dep-optimizer-external": "file:./deps/optimizer/external", "@vitest/test-dep-optimizer-optimized": "file:./deps/optimizer/optimized", "inline-dep": "file:./deps/vite-ssr-resolve/inline-dep", diff --git a/test/config/test/failures.test.ts b/test/config/test/failures.test.ts index fb7be8484..3c9244073 100644 --- a/test/config/test/failures.test.ts +++ b/test/config/test/failures.test.ts @@ -1,7 +1,6 @@ import type { RunVitestConfig, VitestRunnerCLIOptions } from '../../test-utils' import { playwright } from '@vitest/browser-playwright' import { preview } from '@vitest/browser-preview' -import { webdriverio } from '@vitest/browser-webdriverio' import { normalize, resolve } from 'pathe' import { beforeEach, expect, test } from 'vitest' import { version } from 'vitest/package.json' @@ -9,10 +8,9 @@ import * as testUtils from '../../test-utils' const providers = [ playwright(), - webdriverio(), preview(), ] as const -const names = ['edge', 'chromium', 'webkit', 'chrome', 'firefox', 'safari'] as const +const names = ['chromium', 'webkit', 'firefox'] as const const browsers = providers.map(provider => names.map(name => ({ name, provider }))).flat() function runVitest(config: RunVitestConfig, runnerOptions?: VitestRunnerCLIOptions) { @@ -109,9 +107,6 @@ test('inspect and --inspect-brk cannot be used when not playwright + chromium', if (provider.name === 'playwright' && name === 'chromium') { continue } - if (provider.name === 'webdriverio' && (name === 'chrome' || name === 'edge')) { - continue - } const { stderr } = await runVitest({ [option]: true, @@ -137,9 +132,9 @@ test('inspect and --inspect-brk cannot be used when not playwright + chromium', Use either: { browser: { - provider: ${provider.name === 'preview' ? 'playwright' : provider.name}(), + provider: playwright(), instances: [ - { browser: '${(provider.name === 'preview' || provider.name === 'playwright') ? 'chromium' : 'chrome'}' } + { browser: 'chromium' } ], }, } @@ -156,9 +151,6 @@ test.each( if (provider.name === 'playwright') { return name !== 'chromium' } - if (provider.name === 'webdriverio') { - return name !== 'chrome' && name !== 'edge' - } return true }), )('v8 coverage provider throws when $provider.name + $name', async ({ provider, name }) => { @@ -187,9 +179,9 @@ test.each( Use either: { browser: { - provider: ${provider.name === 'preview' ? 'playwright' : provider.name}(), + provider: playwright(), instances: [ - { browser: '${(provider.name === 'preview' || provider.name === 'playwright') ? 'chromium' : 'chrome'}' } + { browser: 'chromium' } ], }, } @@ -262,7 +254,7 @@ test('v8 coverage provider cannot be used in workspace without chromium', async name: 'Browser project', browser: { enabled: true, - provider: webdriverio(), + provider: playwright(), instances: [{ browser: 'webkit' }], }, }, @@ -273,7 +265,7 @@ test('v8 coverage provider cannot be used in workspace without chromium', async `Error: @vitest/coverage-v8 does not work with { browser: { - provider: webdriverio(), + provider: playwright(), instances: [ { browser: 'webkit' } ],