Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/accept-webdriverio-v10.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@wdio/devtools-service': minor
'@wdio/elements': minor
---

Accept WebdriverIO 10 as a peer. The service required `webdriverio` `^9.19.1` and `@wdio/protocols` at exactly `9.30.1`, and `@wdio/elements` required `webdriverio` `^9.0.0`, so adding either to a v10 project conflicted with the project's own `webdriverio` and `@wdio/protocols`. Both majors are now accepted. The service uses none of the APIs v10 removed: its `addCommand` call already passes no third argument, and assertion folding keys on the matcher's value-read command, not on the matcher name that v10 now reports as the alias.
5 changes: 5 additions & 0 deletions .changeset/raise-backend-server-floors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@wdio/devtools-backend': patch
---

Raise the minimum versions of the dashboard server's dependencies: `fastify` to 5.12.5, `@fastify/static` to 10.1.5 and `@fastify/websocket` to 11.3.1. A fresh install already resolves these, but an existing lockfile could keep the older releases the previous ranges allowed.
5 changes: 5 additions & 0 deletions .changeset/share-the-projects-wdio-packages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@wdio/devtools-service': patch
---

Use the project's own `@wdio/types`, `@wdio/logger` and `@wdio/reporter` instead of pinned copies. The service pinned them at exact 9.x versions in `dependencies`, so a WebdriverIO 10 project installed a second set beside its own. On v10 that made the service class fail to type-check when passed directly in `services` (`[DevToolsHookService, options]`), because its types came from the 9.x copy. They are now peers accepting 9 and 10: `webdriverio` already brings the first two, and npm and pnpm install a missing `@wdio/reporter` automatically.
5 changes: 5 additions & 0 deletions .changeset/wait-for-a-late-body.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@wdio/devtools-script': patch
---

Keep waiting for a `<body>` however late it arrives. The collector checked for a body on one animation frame only, then gave up after 10 seconds. It runs as a document-start preload, so a page whose `<head>` blocked on a slow asset (measured: 30 seconds behind a 503) got no DOM anchor and no form-field capture. Every action on that page then replayed an earlier document instead, and typed values never showed. The collector now checks on every frame, and on `DOMContentLoaded` for a background tab that paints none, with no timeout. A body still missing after 10 seconds is logged, so a page that never gets one shows up in the collector's logs instead of going uncaptured silently.
66 changes: 66 additions & 0 deletions .github/scripts/wdio-peer-smoke/check-imports.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import assert from 'node:assert/strict'
import { execFileSync } from 'node:child_process'

const major = process.argv[2]

function installedVersions(name) {
// npm ls exits non-zero on any tree problem, but still prints the tree.
let out
try {
out = execFileSync('npm', ['ls', name, '--all', '--json'], {
encoding: 'utf8'
})
} catch (err) {
out = err.stdout
}
const versions = new Set()
const walk = (deps = {}) => {
for (const [dep, info] of Object.entries(deps)) {
if (dep === name && info.version) {
versions.add(info.version)
}
walk(info.dependencies)
}
}
walk(JSON.parse(out).dependencies)
return [...versions]
}

async function checkEntryPoints() {
const service = await import('@wdio/devtools-service')
assert.equal(typeof service.default, 'function', 'service default export')
assert.equal(typeof service.launcher, 'function', 'service launcher export')
assert.equal(typeof service.setupForDevtools, 'function', 'standalone export')

const { DevToolsAppLauncher } =
await import('@wdio/devtools-service/launcher')
assert.equal(typeof DevToolsAppLauncher, 'function', 'launcher entry')
await import('@wdio/devtools-service/types')

const elements = await import('@wdio/elements')
for (const fn of [
'getSnapshot',
'getElements',
'getBrowserAccessibilityTree'
]) {
assert.equal(typeof elements[fn], 'function', `@wdio/elements ${fn}`)
}
const locators = await import('@wdio/elements/locators')
assert.equal(typeof locators.xmlToJSON, 'function', '@wdio/elements/locators')
}

const webdriverio = installedVersions('webdriverio')
assert.deepEqual(
webdriverio.map((v) => v.split('.')[0]),
[major],
`expected one webdriverio@${major}, found ${webdriverio.join(', ')}`
)

checkEntryPoints().then(() => {
// Informational: the service pins these exactly, so a newer major runs with
// a second copy of each. Printed so the CI log shows what a user installs.
for (const name of ['@wdio/reporter', '@wdio/types', '@wdio/logger']) {
console.log(`${name}: ${installedVersions(name).join(', ')}`)
}
console.log(`webdriverio ${webdriverio[0]}: entry points import`)
})
57 changes: 57 additions & 0 deletions .github/scripts/wdio-peer-smoke/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
# Installs the packed service and elements beside a given WebdriverIO major, the
# way a user's project gets them, then proves they import and type-check there.
#
# run.sh <webdriverio major> [work dir]
#
# Expects the workspace to be built. NPM overrides the npm command, so a local
# run can go through a package-age guard (NPM="pmg npm").
set -euo pipefail

MAJOR="${1:?usage: run.sh <webdriverio major> [work dir]}"
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "$HERE/../../.." && pwd)"
WORK="${2:-$(mktemp -d)}"
NPM="${NPM:-npm}"
PACKS="$WORK/packs"
PROJECT="$WORK/project"

rm -rf "$PACKS" "$PROJECT"
mkdir -p "$PACKS" "$PROJECT"

# The service's workspace:^ deps (backend, script, elements, and the app the
# backend serves) pack as ranges on versions that may not be published yet, so
# every one of them is installed from its local tarball rather than the registry.
for pkg in app script backend elements service; do
(cd "$ROOT/packages/$pkg" && pnpm pack --pack-destination "$PACKS" >/dev/null)
done

repo_dev_version() {
node -p "require('$ROOT/package.json').devDependencies['$1']"
}

cp "$HERE/check-imports.mjs" "$HERE/smoke.ts" "$HERE/tsconfig.json" "$PROJECT/"
cat > "$PROJECT/package.json" <<'JSON'
{ "name": "wdio-peer-smoke", "private": true, "type": "module" }
JSON

cd "$PROJECT"

# No --legacy-peer-deps or --force: a peer range that excludes this major has
# to fail the install, which is the first thing this job exists to catch.
$NPM install --no-audit --no-fund --strict-peer-deps \
"webdriverio@^$MAJOR" \
"@wdio/cli@^$MAJOR" \
"@wdio/local-runner@^$MAJOR" \
"@wdio/mocha-framework@^$MAJOR" \
"@wdio/globals@^$MAJOR" \
"@wdio/types@^$MAJOR" \
"@wdio/protocols@^$MAJOR" \
"@wdio/allure-reporter@^$MAJOR" \
"typescript@$(repo_dev_version typescript)" \
"@types/node@$(repo_dev_version @types/node)" \
"$PACKS"/*.tgz

node check-imports.mjs "$MAJOR"
npx tsc -p tsconfig.json
echo "WebdriverIO $MAJOR: install, import and type-check passed"
42 changes: 42 additions & 0 deletions .github/scripts/wdio-peer-smoke/smoke.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Compiled, never run: it exists so tsc checks the published declarations
// against the WebdriverIO types this project installed.
import { remote } from 'webdriverio'
import type { Options } from '@wdio/types'
import DevToolsHookService, {
setupForDevtools,
type ServiceOptions
} from '@wdio/devtools-service'
import { getElements, getSnapshot, type SnapshotResult } from '@wdio/elements'
import { xmlToJSON } from '@wdio/elements/locators'

const serviceOptions: ServiceOptions = {
screenshot: 'only-on-failure',
video: 'retain-on-failure',
devtoolsCapabilities: { browserName: 'chrome' }
}

export const config: WebdriverIO.Config = {
specs: ['./test/**/*.ts'],
capabilities: [{ browserName: 'chrome' }],
framework: 'mocha',
services: [
['devtools', serviceOptions],
[DevToolsHookService, serviceOptions]
]
}

export async function standalone(opts: Options.WebdriverIO): Promise<void> {
const browser = await remote({
...setupForDevtools(opts),
capabilities: { browserName: 'chrome' }
})
await browser.deleteSession()
}

export async function elements(
browser: WebdriverIO.Browser
): Promise<SnapshotResult> {
await getElements(browser, { inViewportOnly: false })
xmlToJSON('<hierarchy />')
return getSnapshot(browser, { inViewportOnly: false })
}
12 changes: 12 additions & 0 deletions .github/scripts/wdio-peer-smoke/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"noEmit": true,
"skipLibCheck": true,
"types": ["node", "@wdio/globals/types", "@wdio/mocha-framework"]
},
"files": ["smoke.ts"]
}
40 changes: 40 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,43 @@ jobs:
# Chrome, and past 2 the heaviest specs time out under that contention.
- name: 🧩 Component Tests
run: pnpm test:ui --maxInstances 2

# The workspace develops against one WebdriverIO major, but the service and
# @wdio/elements declare peers on two. Each published major is installed from
# npm into a scratch project beside the packed tarballs, so a peer conflict, a
# broken entry point or a type mismatch with that major fails here first. 9
# runs too so a red 10 can be told apart from a broken harness.
wdio-peer:
name: wdio-peer (webdriverio ${{ matrix.wdio }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
wdio: [9, 10]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Use Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .nvmrc
- name: Cache pnpm modules
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
env:
cache-name: cache-pnpm-modules
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
with:
version: 10.26.1
run_install: false
- name: Install dependencies
run: pnpm install --frozen-lockfile
# The trailing `...` also builds what the two packages depend on, which
# includes the app the backend tarball serves.
- name: 📦 Bundle
run: pnpm --workspace-concurrency=1 --filter "@wdio/devtools-service..." --filter "@wdio/elements..." build
- name: 🔌 Install, import and type-check against WebdriverIO ${{ matrix.wdio }}
run: bash .github/scripts/wdio-peer-smoke/run.sh ${{ matrix.wdio }} "$RUNNER_TEMP/wdio-peer"
4 changes: 2 additions & 2 deletions .github/workflows/python-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ jobs:
# to that, because it would have to name a version nothing has computed
# yet — so `py-v<version>` is an output, pointing at exactly the tree that
# was published.
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: 'main'
fetch-depth: 0
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.12'
# Consumes changes/ — bumps `__version__` by the strongest level pending
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ jobs:
steps:
# Full history: the change-fragment gate diffs this branch against the
# base, which a depth-1 checkout cannot see.
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: ${{ matrix.python-version }}
# A source change with no fragment is a release that cannot describe
Expand Down
18 changes: 9 additions & 9 deletions examples/wdio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
"private": true,
"type": "module",
"devDependencies": {
"@wdio/cli": "9.30.1",
"@wdio/cucumber-framework": "9.30.1",
"@wdio/mocha-framework": "9.30.1",
"@wdio/cli": "9.32.0",
"@wdio/cucumber-framework": "9.32.0",
"@wdio/devtools-service": "workspace:*",
"@wdio/globals": "9.29.1",
"@wdio/local-runner": "9.30.1",
"@wdio/spec-reporter": "9.30.1",
"@wdio/types": "9.30.1",
"expect-webdriverio": "^6.0.1",
"@wdio/globals": "9.31.3",
"@wdio/local-runner": "9.32.0",
"@wdio/mocha-framework": "9.32.0",
"@wdio/spec-reporter": "9.32.0",
"@wdio/types": "9.32.0",
"expect-webdriverio": "^7.0.0",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"tsx": "^4.22.4",
"tsx": "^4.23.15",
"typescript": "^6.0.3"
},
"scripts": {
Expand Down
47 changes: 20 additions & 27 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,46 +34,39 @@
"watch": "pnpm build --watch",
"changeset:gen": "bash .changeset/changeset-gen.sh"
},
"pnpm": {
"overrides": {
"vite": "^8.0.7",
"@types/node": "26.2.0",
"@codemirror/state": "6.5.4"
}
},
"devDependencies": {
"@changesets/cli": "^2.31.0",
"@changesets/cli": "^3.0.3",
"@eslint/js": "^10.0.1",
"@types/node": "26.2.0",
"@types/node": "26.6.3",
"@types/ws": "^8.18.1",
"@typescript-eslint/eslint-plugin": "^8.60.1",
"@typescript-eslint/parser": "^8.60.1",
"@typescript-eslint/utils": "^8.60.1",
"@vitest/coverage-v8": "^4.1.8",
"@wdio/allure-reporter": "^9.29.1",
"autoprefixer": "^10.5.0",
"eslint": "^10.4.1",
"@typescript-eslint/eslint-plugin": "^8.70.1",
"@typescript-eslint/parser": "^8.70.1",
"@typescript-eslint/utils": "^8.70.1",
"@vitest/coverage-v8": "^5.0.2",
"@wdio/allure-reporter": "^9.32.0",
"autoprefixer": "^10.6.1",
"eslint": "^10.11.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.6",
"eslint-plugin-security": "4.0.1",
"eslint-plugin-unicorn": "^73.0.0",
"happy-dom": "^20.9.0",
"eslint-plugin-security": "4.1.0",
"eslint-plugin-unicorn": "^76.0.0",
"happy-dom": "^20.14.5",
"npm-run-all": "^4.1.5",
"postcss": "^8.5.15",
"postcss": "^8.5.28",
"postcss-lit": "^1.4.1",
"prettier": "^3.8.3",
"tailwindcss": "^4.3.0",
"prettier": "^3.9.9",
"tailwindcss": "^4.3.3",
"ts-node": "^10.9.2",
"tsx": "^4.22.4",
"tsx": "^4.23.15",
"typescript": "^6.0.3",
"unplugin-icons": "^23.0.1",
"vite": "^8.0.16",
"vitest": "^4.1.8",
"unplugin-icons": "^24.0.0",
"vite": "^8.3.1",
"vitest": "^5.0.2",
"webdriverio": "^9.27.2",
"ws": "^8.21.0"
},
"dependencies": {
"@wdio/cli": "9.30.1"
"@wdio/cli": "9.32.0"
}
}
Loading
Loading