diff --git a/.changeset/show-trace-bin.md b/.changeset/show-trace-bin.md new file mode 100644 index 00000000..07c14ef5 --- /dev/null +++ b/.changeset/show-trace-bin.md @@ -0,0 +1,7 @@ +--- +'@wdio/devtools-service': patch +'@wdio/selenium-devtools': patch +'@wdio/nightwatch-devtools': patch +--- + +Ship the `show-trace` bin the package has always declared. The file was never committed, so `npx show-trace ` failed in a project that installed only this adapter. diff --git a/.changeset/snapshot-matches-the-wdio-cli.md b/.changeset/snapshot-matches-the-wdio-cli.md new file mode 100644 index 00000000..6077fdb2 --- /dev/null +++ b/.changeset/snapshot-matches-the-wdio-cli.md @@ -0,0 +1,10 @@ +--- +"@wdio/elements": major +"@wdio/devtools-service": major +--- + +`getSnapshot` now produces the same text as `wdio session snapshot --selectors`, by delegating to `@wdio/snapshot` instead of keeping a second renderer that drifted from the CLI's. Agents that read the CLI's output and agents that call this function now see one format. + +Breaking: it returns `{ text, refs }` rather than `{ text, elements }`, takes `{ viewport }` (default `false`, the full page) in place of `{ inViewportOnly }` (default `true`), no longer prefixes a `[Page: …]` header, and throws on failure instead of returning a placeholder. `serializeWebSnapshot`, `serializeMobileSnapshot` and their option and result types are removed. Requires `webdriverio` ^10, and declares `engines.node` `>=22.19.0`. A mobile browser session (Chrome on Android, Safari on iOS) is now snapshotted from the page rather than from Appium's page source, and Mac and Windows native sessions take the native path. `getElements` on a native session no longer attaches the raw page source as `tree.attributes._sourceXML`. + +Breaking for `@wdio/devtools-service`: it now requires WebdriverIO 10. It consumes `@wdio/elements` 2, which delegates to `@wdio/snapshot`, and that package pins `webdriverio` exactly to a v10 release, so the service's peer ranges for `webdriverio`, `@wdio/types`, `@wdio/reporter`, `@wdio/logger`, `@wdio/protocols` and `@wdio/allure-reporter` are narrowed to `^10.0.0`. Its `browser.getSnapshot()` returns the same `{ text, refs }` instead of `{ text, elements }`, and the `inViewportOnly` option is replaced by `viewport`. The service still defaults to the viewport (`viewport: true`) so repeated calls from an agent loop stay small, whereas calling `getSnapshot` from `@wdio/elements` directly defaults to the full page. diff --git a/.changeset/wdio-10-1.md b/.changeset/wdio-10-1.md new file mode 100644 index 00000000..e3314dc5 --- /dev/null +++ b/.changeset/wdio-10-1.md @@ -0,0 +1,7 @@ +--- +"@wdio/devtools-backend": patch +"@wdio/selenium-devtools": patch +"@wdio/nightwatch-devtools": patch +--- + +The `@wdio/logger` each package depends on, and the `webdriverio` the Selenium and Nightwatch adapters depend on, move to their 10.1.0 lines (`^10.1.0`), alongside the rest of the WebdriverIO toolchain the repository now builds and tests against. An install that pinned either to 10.0.x resolves 10.1.x from now on. diff --git a/.github/scripts/wdio-peer-smoke/smoke.ts b/.github/scripts/wdio-peer-smoke/smoke.ts index 50c7c8b3..e638ab6c 100644 --- a/.github/scripts/wdio-peer-smoke/smoke.ts +++ b/.github/scripts/wdio-peer-smoke/smoke.ts @@ -6,7 +6,7 @@ import DevToolsHookService, { setupForDevtools, type ServiceOptions } from '@wdio/devtools-service' -import { getElements, getSnapshot, type SnapshotResult } from '@wdio/elements' +import { getElements, getSnapshot, type GetSnapshotResult } from '@wdio/elements' import { xmlToJSON } from '@wdio/elements/locators' const serviceOptions: ServiceOptions = { @@ -35,8 +35,8 @@ export async function standalone(opts: Options.WebdriverIO): Promise { export async function elements( browser: WebdriverIO.Browser -): Promise { +): Promise { await getElements(browser, { inViewportOnly: false }) xmlToJSON('') - return getSnapshot(browser, { inViewportOnly: false }) + return getSnapshot(browser, { viewport: false }) } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c70815a4..fcc1c635 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -93,18 +93,17 @@ jobs: - 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. + # The service and @wdio/elements are WebdriverIO-10-only (@wdio/snapshot pins + # webdriverio exactly). The 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. wdio-peer: name: wdio-peer (webdriverio ${{ matrix.wdio }}) runs-on: ubuntu-latest strategy: fail-fast: false matrix: - wdio: [9, 10] + wdio: [10] steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Use Node.js diff --git a/.gitignore b/.gitignore index 1ca4ecec..45b959c0 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,7 @@ coverage/ # pnpm state, cache, logs, and debug files /packages/**/*.mjs +!/packages/*/bin/*.mjs .claude @@ -72,3 +73,7 @@ packages/**/allure-results*/ packages/**/allure-report*/ examples/wdio/cucumber/wdio.allure.conf.ts +# Written on purpose by examples/wdio/mocha/specs/wdio.e2e.ts +examples/wdio/screenshot.jpg +examples/wdio/snapshot-full.txt +examples/wdio/snapshot-viewport.txt diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index c0f9fa98..89c51d0f 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -184,7 +184,7 @@ The execution environment is the browser, not Node, so this package cannot impor The WDIO-typed element-detection API (`@wdio/elements`): `getSnapshot`, `getElements`, the accessibility-tree and interactable-element readers. Unlike `shared` and `core` this package **is** published, so its exported names are public API. -Imports from: `core`. The script bodies, serializers, types, and locator generation all live in `core` (`element-scripts.ts`, `element-snapshot.ts`, `element-types.ts`, `locators/`) because they're framework-agnostic; this package holds only the wrappers that take a `WebdriverIO.Browser` β€” which `core` can't type against. The arrow never reverses: `core` does not import `elements`, and the adapters' per-action capture (`captureActionSnapshot`) calls core's script bodies directly rather than going through this package. `elements/snapshot.ts` and `elements/locators/index.ts` are re-export shims kept for API stability. +Imports from: `core`. The script bodies, serializers, types, and locator generation all live in `core` (`element-scripts.ts`, `element-snapshot.ts`, `element-types.ts`, `locators/`) because they're framework-agnostic; this package holds only the wrappers that take a `WebdriverIO.Browser` β€” which `core` can't type against. The arrow never reverses: `core` does not import `elements`, and the adapters' per-action capture (`captureActionSnapshot`) calls core's script bodies directly rather than going through this package. `elements/locators/index.ts` is a re-export shim kept for API stability. The DOM-walking scripts run in the page via `browser.execute`, so β€” like `script` β€” they avoid Node-only APIs. diff --git a/CLAUDE.md b/CLAUDE.md index e06da11a..c3dfe735 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -353,7 +353,7 @@ Documented divergences from the conventions above. They exist today as debt to b - Relatedly, cucumber's **per-step** `resetCommandTracking()` was wiping the native-assert buffer, so each scenario kept only its *last* step's assertions (measured 1 of 2). The buffer is per **test unit** β€” `resetTestTracking()` at `wrapBrowserOnce` now clears it. - **DOM `mutations` ARE captured**, and the old `ECONNRESET` / "collector not found" attribution is **wrong** β€” neither appears any more. The gap closed itself with document-start injection (`core/bidi-preload.ts`), confirmed on a *baseline* build so the credit belongs to that change and not to anything here. Measured per scenario with `traceGranularity:'test'` + `webSocketUrl: true`: 39 and 19 mutation entries, 2 DOM anchors each, **0 of 19 rows on the wrong document**. What remains is noise, not a gap: the screencast poller issues `/screenshot` every 200 ms into the session Nightwatch quits per scenario, logging 9–26 `WARN webdriverHttp: … socket hang up` per run. Fix is to stop the recorder before the per-scenario quit, or suppress the warn for a session in teardown. - **A tsup entry that another entry imports is not a leaf, so an `import.meta.url === process.argv[1]` self-start check inside it is dead code; a CLI has to be its own leaf entry.** tsup hoists a module body shared by two entries into `dist/chunk-*.js`, and there `import.meta.url` is the chunk's path, which can never equal `process.argv[1]`. `packages/backend/src/show-trace.ts` imports `start` from `index.ts`, which is what made index shared, so index's old "start if run directly" guard was dead in **every** build: `node dist/index.js` exited 0 without ever serving, while `dist/show-trace.js` self-started correctly for exactly the same reason inverted, being a leaf whose body stays in its own output file (it also compares realpaths, because the invoked path is the `node_modules/.bin` symlink). The live dashboard server is therefore its own leaf entry, `packages/backend/src/server.ts` (shebang, built to an executable `dist/server.js`, shipped as the `devtools-backend` bin, accepting `--port`, `--hostname`, `-h`/`--help`), and `index.ts` stays library-only for the three adapters' in-process `start`/`stop`. Same family as the `cucumberHooks.cts` entry above: the tsup entry list is part of the contract, and in both cases the symptom was silence rather than an error. -- **A captured text locator is generated in the recording runner's dialect; every other branch is portable CSS.** `shared/locator-dialect.ts` `locatorDialect(runner)` is the one fact table β€” WDIO runners (`mocha`/`jasmine`/`cucumber`) get `a*=Logout`, `nightwatch*`/`selenium-webdriver` and an **unidentified recorder** get `//a[contains(., "Logout")]`. The id reaches the page script as `CaptureActionSnapshotInput.runner` and the zip as an extension field on `context-options`, read back through `isTestRunnerId` onto `Metadata.runner`; absent in older and foreign zips, where the player shows no hint. Under WDIO a text carrying a `"` still emits XPath β€” WDIO compiles `tag*=` to XPath with `"` quoting and would build a broken expression β€” and WDIO resolves `//` itself. `locatorsMatch` decomposes **both** sides from either dialect, so `after.point` survives whichever way round the two grammars fall; the `concat()`-stitched literal is still left to exact comparison. `@wdio/elements`' standalone `getSnapshot` deliberately keeps the portable XPath default (its output is pasted into arbitrary tools), so a WDIO run's `browser.getSnapshot()` and its trace A11y tab disagree on that one branch. +- **A captured text locator is generated in the recording runner's dialect; every other branch is portable CSS.** `shared/locator-dialect.ts` `locatorDialect(runner)` is the one fact table β€” WDIO runners (`mocha`/`jasmine`/`cucumber`) get `a*=Logout`, `nightwatch*`/`selenium-webdriver` and an **unidentified recorder** get `//a[contains(., "Logout")]`. The id reaches the page script as `CaptureActionSnapshotInput.runner` and the zip as an extension field on `context-options`, read back through `isTestRunnerId` onto `Metadata.runner`; absent in older and foreign zips, where the player shows no hint. Under WDIO a text carrying a `"` still emits XPath β€” WDIO compiles `tag*=` to XPath with `"` quoting and would build a broken expression β€” and WDIO resolves `//` itself. `locatorsMatch` decomposes **both** sides from either dialect, so `after.point` survives whichever way round the two grammars fall; the `concat()`-stitched literal is still left to exact comparison. `@wdio/elements` 2.x `getSnapshot` is not on this table at all: it renders `@wdio/snapshot`'s `attachSelectors` choice so its text matches `wdio session snapshot --selectors`, which can be a WebdriverIO-v10-only strategy (`role/…`, `aria/…`), so a WDIO run's `browser.getSnapshot()` and its trace A11y tab can differ on that branch. - `Metadata.runner` (typed `TestRunnerId`) and `metadata.options.framework` (untyped `string`, read by the sidebar's `getFramework`) are two carriers of the same fact. All three adapters now set both; the next change to either should collapse `getFramework` onto `Metadata.runner`. - Selenium's `ctx.runner` (the *detected JS runner* β€” mocha/jest/cucumber, from `detectRunner()`) shadows the new `Metadata.runner` concept. Renamed to `detectedRunner` at the `driverMetadata` boundary only, where the two met inside one function and a swap would have been a silent dialect bug; the repo-wide rename in `plugin-internals.ts`/`session-lifecycle.ts` is still open. - **A node:assert's target comes from VALUE PROVENANCE, not from the assert call.** node:assert takes values, so `assert.equal(await el.getText(), …)` names no element. `core/read-value-locators.ts` owns the valueβ†’locator registry (`rememberReadValue`/`selectorForReadValue`/`resolveAssertTargetFromArgs`; most-recent-producer-wins, 200 keys, ≀256 chars, primitives only), reached through `patchNodeAssert`'s optional `resolveAssertTarget` hook, which walks the **raw** args (sanitizing destroys handle identity) onto the shared `CommandLog.selector`. It lives in core because two adapters feed it. **Selenium** feeds it from `driverPatcher`'s settle path and composes it with its handle WeakMap (`helpers/element-locators.ts`, adapter-local β€” it keys on `WebElement` identity, which no other framework has). **Nightwatch** feeds it from `browserProxy`'s capture callback via `assertTarget.commandTargetSelector`, an allowlist of element-read commands; every other command β€” every driver-level read (`title`, `getCurrentUrl`, `source`) included β€” records the **null sentinel**, without which a page-title assertion inherits the box of an element that reads the same text (measured on selenium's mocha example, `h1` vs `document.title` both "Example Domain"; reproduced and fixed for Nightwatch on a local `#hero`/`` collision page). Measured: Nightwatch node:assert rows with a locator **0/7 β†’ 4/7** (the 3 without are a title read, the title/`#hero` collision, and a literal); Selenium unchanged at 2/4 mocha and 2/3 cucumber. Residuals: boolean reads are weakly discriminating, so a value collision with no intervening producer can mis-attribute; Nightwatch's `element()/.find()` API and its ignored commands (`execute`, `executeAsync`, `perform`) are never wrapped, so their values neither claim nor clear. **`after.point` is deliberately not extended to assert rows** β€” `resolveActionPoint` gates on `class:'Element'` + `POINTABLE_METHODS`, so WDIO's folded assertion rows get none either; a point draws a click marker an assertion never earned. diff --git a/examples/wdio/package.json b/examples/wdio/package.json index 42f1becc..f3c53228 100644 --- a/examples/wdio/package.json +++ b/examples/wdio/package.json @@ -4,14 +4,14 @@ "private": true, "type": "module", "devDependencies": { - "@wdio/cli": "10.0.2", - "@wdio/cucumber-framework": "10.0.1", + "@wdio/cli": "10.1.0", + "@wdio/cucumber-framework": "10.1.0", "@wdio/devtools-service": "workspace:*", - "@wdio/globals": "10.0.2", - "@wdio/local-runner": "10.0.2", - "@wdio/mocha-framework": "10.0.1", - "@wdio/spec-reporter": "10.0.1", - "@wdio/types": "10.0.1", + "@wdio/globals": "10.1.0", + "@wdio/local-runner": "10.1.0", + "@wdio/mocha-framework": "10.1.0", + "@wdio/spec-reporter": "10.1.0", + "@wdio/types": "10.1.0", "expect-webdriverio": "^8.0.0", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", diff --git a/package.json b/package.json index 9c8942f0..3137699c 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@typescript-eslint/parser": "^8.71.0", "@typescript-eslint/utils": "^8.71.0", "@vitest/coverage-v8": "^5.0.2", - "@wdio/allure-reporter": "^10.0.1", + "@wdio/allure-reporter": "^10.1.0", "autoprefixer": "^10.6.1", "eslint": "^10.11.0", "eslint-config-prettier": "^10.1.8", @@ -63,10 +63,10 @@ "unplugin-icons": "^24.0.0", "vite": "^8.3.2", "vitest": "^5.0.2", - "webdriverio": "^10.0.2", + "webdriverio": "^10.1.0", "ws": "^8.22.0" }, "dependencies": { - "@wdio/cli": "10.0.2" + "@wdio/cli": "10.1.0" } } diff --git a/packages/app/package.json b/packages/app/package.json index 951847dc..43043af7 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -26,12 +26,12 @@ "@iconify-json/mdi": "^1.2.3", "@lit/context": "^1.1.6", "@tailwindcss/postcss": "^4.3.3", - "@wdio/browser-runner": "^10.0.2", + "@wdio/browser-runner": "^10.1.0", "@wdio/devtools-shared": "workspace:^", - "@wdio/globals": "^10.0.2", - "@wdio/mocha-framework": "^10.0.1", + "@wdio/globals": "^10.1.0", + "@wdio/mocha-framework": "^10.1.0", "@wdio/protocols": "10.0.2", - "@wdio/reporter": "10.0.1", + "@wdio/reporter": "10.1.0", "autoprefixer": "^10.6.1", "codemirror": "^6.0.2", "expect-webdriverio": "^8.0.0", diff --git a/packages/backend/package.json b/packages/backend/package.json index 33a834ed..2f4d4a7f 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -44,7 +44,7 @@ "@fastify/websocket": "^11.3.1", "@wdio/devtools-app": "workspace:^", "@wdio/devtools-script": "workspace:^", - "@wdio/logger": "10.0.0", + "@wdio/logger": "10.1.0", "fastify": "^5.12.5", "fflate": "^0.8.2", "get-port": "^7.2.0", @@ -57,7 +57,7 @@ "devDependencies": { "@types/shell-quote": "^1.7.5", "@types/ws": "^8.18.2", - "@wdio/cli": "^10.0.2", + "@wdio/cli": "^10.1.0", "@wdio/devtools-shared": "workspace:^", "@wdio/devtools-trace": "workspace:^", "nodemon": "^3.1.14", diff --git a/packages/conformance/package.json b/packages/conformance/package.json index 6e442076..30db2216 100644 --- a/packages/conformance/package.json +++ b/packages/conformance/package.json @@ -18,19 +18,19 @@ "@types/node": "26.6.4", "@types/selenium-webdriver": "^4.35.6", "@types/ws": "^8.18.2", - "@wdio/cli": "10.0.2", + "@wdio/cli": "10.1.0", "@wdio/devtools-service": "workspace:^", "@wdio/devtools-shared": "workspace:^", - "@wdio/globals": "10.0.2", - "@wdio/local-runner": "10.0.2", - "@wdio/mocha-framework": "10.0.1", + "@wdio/globals": "10.1.0", + "@wdio/local-runner": "10.1.0", + "@wdio/mocha-framework": "10.1.0", "@wdio/nightwatch-devtools": "workspace:^", "@wdio/selenium-devtools": "workspace:^", - "@wdio/spec-reporter": "10.0.1", + "@wdio/spec-reporter": "10.1.0", "expect-webdriverio": "^8.0.0", "nightwatch": "^3.16.0", "selenium-webdriver": "^4.50.0", - "webdriverio": "^10.0.2", + "webdriverio": "^10.1.0", "ws": "^8.22.0" } } diff --git a/packages/conformance/src/constants.ts b/packages/conformance/src/constants.ts index 4fef2ce7..7d2244f5 100644 --- a/packages/conformance/src/constants.ts +++ b/packages/conformance/src/constants.ts @@ -104,6 +104,13 @@ export const PAGES: Record<string, Record<string, string | null>> = { export const BROKEN_PATH = '/broken' +/** W3C's session defaults: a real browser always answers `GET /timeouts` with all three, and WebdriverIO 10.1 reads `script` from it before every BiDi `execute`. */ +export const DEFAULT_TIMEOUTS = { + script: 30_000, + pageLoad: 300_000, + implicit: 0 +} + export const BIDI_PATH = '/session/conformance/bidi' /** BiDi acknowledgements whose callers read a field back; commands the fake browser models are answered from its state. */ diff --git a/packages/conformance/src/fake-webdriver.ts b/packages/conformance/src/fake-webdriver.ts index 0bff064c..bf59569d 100644 --- a/packages/conformance/src/fake-webdriver.ts +++ b/packages/conformance/src/fake-webdriver.ts @@ -14,6 +14,7 @@ import { BLANK_PNG, BROKEN_PATH, COLLECTOR_SIGNATURE, + DEFAULT_TIMEOUTS, ELEMENT_KEY, NAVIGATION_HALF_MS, PAGES, @@ -52,6 +53,13 @@ type Reply = { const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)) +const FIXED_REPLIES: Record<string, unknown> = { + '/screenshot': BLANK_PNG, + '/window/rect': { x: 0, y: 0, width: 1280, height: 720 }, + '/window': WINDOW_HANDLE, + '/window/handles': [WINDOW_HANDLE] +} + const anchorOf = (url: string, bornAt: number): TraceMutation => ({ type: 'childList', url, @@ -206,6 +214,9 @@ export class FakeWebDriver { if (method === 'POST' && (path === '/element' || path === '/elements')) { return this.#find(String(params.value), path === '/elements') } + if (method === 'GET' && path === '/timeouts') { + return { value: DEFAULT_TIMEOUTS } + } const element = path.match(/^\/element\/([^/]+)\/(value|click|clear|text)$/) if (element) { return this.#onElement(element[1], element[2], params) @@ -218,19 +229,7 @@ export class FakeWebDriver { ) } } - if (path === '/screenshot') { - return { value: BLANK_PNG } - } - if (path === '/window/rect') { - return { value: { x: 0, y: 0, width: 1280, height: 720 } } - } - if (path === '/window') { - return { value: WINDOW_HANDLE } - } - if (path === '/window/handles') { - return { value: [WINDOW_HANDLE] } - } - return { value: null } + return { value: FIXED_REPLIES[path] ?? null } } async #navigate(path: string): Promise<Reply> { diff --git a/packages/conformance/tests/fakes.test.ts b/packages/conformance/tests/fakes.test.ts index d31e3502..adcc22f4 100644 --- a/packages/conformance/tests/fakes.test.ts +++ b/packages/conformance/tests/fakes.test.ts @@ -155,6 +155,24 @@ describe('the fake BiDi endpoint', () => { }) }) +describe('the fake WebDriver', () => { + // WebdriverIO 10.1 destructures this before every BiDi execute; a null answer made every script throw unsent. + it('answers GET /timeouts with the W3C timeouts object', async () => { + const driver = await start(true) + await session(driver) + expect(await call(driver, 'GET', '/session/conformance/timeouts')).toEqual({ + script: 30_000, + pageLoad: 300_000, + implicit: 0 + }) + expect( + await call(driver, 'POST', '/session/conformance/timeouts', { + implicit: 5 + }) + ).toBeNull() + }) +}) + describe('the fake collector', () => { // Regression: re-injection kept the document anchored, so a duplicate anchor could never be modelled. it('anchors again after a second injection, which one-anchor-per-document flags', async () => { diff --git a/packages/core/package.json b/packages/core/package.json index 7f63b1bd..5f1c44b8 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -24,10 +24,6 @@ "types": "./src/locators/index.ts", "default": "./src/locators/index.ts" }, - "./element-snapshot": { - "types": "./src/element-snapshot.ts", - "default": "./src/element-snapshot.ts" - }, "./element-scripts": { "types": "./src/element-scripts.ts", "default": "./src/element-scripts.ts" diff --git a/packages/core/src/element-snapshot.ts b/packages/core/src/element-snapshot.ts index 1f627724..3ff5c790 100644 --- a/packages/core/src/element-snapshot.ts +++ b/packages/core/src/element-snapshot.ts @@ -5,13 +5,6 @@ * text files that LLMs can consume without any parsing. */ -import type { - AccessibilityNode, - SnapshotNode, - SnapshotElement, - SnapshotResult -} from './element-types.js' - // The web serializer lives in `trace` because the backend builds the trace for // an adapter that cannot, and Β§2.2 bars the backend from importing core. export { @@ -21,11 +14,8 @@ export { import { SNAPSHOT_INDENT_UNIT, - INTERACTIVE_ROLES, - isStatictextEchoedByParent, SNAPSHOT_LOCATOR_DELIM, - SNAPSHOT_PURPOSE_TOKEN, - xpathLocatorTag + SNAPSHOT_PURPOSE_TOKEN } from '@wdio/devtools-shared' import type { JSONElement } from './locators/types.js' @@ -646,7 +636,7 @@ export function serializeMobileSnapshot( const { platform, deviceName, viewport, sourceXML } = context const { inViewportOnly = true } = options - // Auto-detect source XML stashed by getMobileVisibleElementsWithTree + // Falls back to the page source action-snapshot.ts stamps on the root const effectiveXML = sourceXML || root.attributes._sourceXML const effectiveViewport = viewport ?? { width: 9999, height: 9999 } @@ -675,229 +665,3 @@ export function serializeMobileSnapshot( const lines = renderMobileNodes(nodes) return [header, ...lines].join('\n') } - -// --------------------------------------------------------------------------- -// Unified snapshot formatter β€” web + mobile share the same render pass. -// --------------------------------------------------------------------------- - -/** Derive a tag name from a locator prefix (e.g. `//button[contains(., "Submit")]` - * or "button*=Submit" β†’ "button"). */ -function extractTagFromSelector(selector: string, fallback: string): string { - const xpathTag = xpathLocatorTag(selector) - if (xpathTag) { - return xpathTag - } - // Matches tag name followed by a CSS selector combinator or operator. - // Supports hyphenated custom elements (my-component) and pseudo-classes (:nth-of-type). - const match = selector.match( - /^([a-z][a-z0-9]*(?:-[a-z][a-z0-9]*)*)[*.#\[:=(^$~]/ - ) - if (match) { - return match[1] - } - const spaceMatch = selector.match(/^([a-z][a-z0-9]*(?:-[a-z][a-z0-9]*)*)\s/) - if (spaceMatch) { - return spaceMatch[1] - } - return fallback -} - -/** Walk backwards to find the nearest structural container name for ∈ context. */ -function findContextName( - nodes: SnapshotNode[], - index: number -): string | undefined { - const myDepth = nodes[index].depth - for (let i = index - 1; i >= 0; i--) { - if (nodes[i].depth <= myDepth && nodes[i].name) { - if (nodes[i].depth === myDepth && nodes[i].isInteractive) { - continue - } - // Suppressed tag-interactive nodes (isInteractive=false but role is a - // mobile-interactable label like 'statictext') shouldn't provide context - // at same depth β€” their name is label text, not a container identity. - // Mirrors mobileInferPurpose which skips same-depth nodes not in - // MOBILE_STRUCTURAL_ROLES (which excludes 'statictext'). - if (nodes[i].depth === myDepth && nodes[i].role === 'statictext') { - continue - } - return nodes[i].name - } - } - return undefined -} - -/** - * Core formatter β€” converts a flat SnapshotNode[] into a text tree with - * eN virtual IDs and an elements map for selector resolution. - * - * Platform-agnostic: both web and mobile pipelines feed into this function. - */ -export function buildSnapshot( - header: string, - nodes: SnapshotNode[] -): SnapshotResult { - const selectorCounts = new Map<string, number>() - for (const node of nodes) { - if (node.isInteractive && node.selector) { - selectorCounts.set( - node.selector, - (selectorCounts.get(node.selector) ?? 0) + 1 - ) - } - } - - const lines: string[] = [header] - const elements: Record<string, SnapshotElement> = {} - const selectorIndex = new Map<string, number>() - let counter = 1 - - for (let i = 0; i < nodes.length; i++) { - const node = nodes[i] - const indent = ' '.repeat(node.depth + 1) - - if (node.isInteractive && node.selector) { - let selector = node.selector - const total = selectorCounts.get(selector) ?? 1 - if (total > 1) { - const idx = selectorIndex.get(selector) ?? 0 - selectorIndex.set(selector, idx + 1) - selector = `${selector}.instance(${idx})` - } - - const eId = `e${counter++}` - - const roleLabel = - node.role === 'heading' && node.level - ? `heading[${node.level}]` - : node.role - - const context = findContextName(nodes, i) - if (node.name && context) { - lines.push( - `${indent}${eId} ${roleLabel} "${node.name}" ∈ "${context}" β†’ ${selector}` - ) - } else if (node.name) { - lines.push( - `${indent}${eId} ${roleLabel} "${node.name}" β†’ ${selector}` - ) - } else if (context) { - lines.push( - `${indent}${eId} ${roleLabel} ∈ "${context}" β†’ ${selector}` - ) - } else { - lines.push(`${indent}${eId} ${roleLabel} β†’ ${selector}`) - } - - elements[eId] = { - selector: node.selector, - ...(selector !== node.selector ? { qualifiedSelector: selector } : {}), - tagName: node.tagName, - role: node.role, - text: node.name - } - } else { - const roleLabel = - node.role === 'heading' && node.level - ? `heading[${node.level}]` - : node.role - lines.push( - node.name - ? `${indent}${roleLabel} "${node.name}"` - : `${indent}${roleLabel}` - ) - } - } - - return { text: lines.join('\n'), elements } -} - -// --------------------------------------------------------------------------- -// Web adapter β€” AccessibilityNode[] β†’ SnapshotNode[] -// --------------------------------------------------------------------------- - -export function accessibilityNodesToSnapshotNodes( - nodes: AccessibilityNode[], - options?: { inViewportOnly?: boolean } -): SnapshotNode[] { - const { inViewportOnly = true } = options ?? {} - - const result: SnapshotNode[] = [] - - for (let i = 0; i < nodes.length; i++) { - const node = nodes[i] - - if (inViewportOnly && node.isInViewport === false) { - continue - } - - const isInteractive = INTERACTIVE_ROLES.has(node.role) - - if (isStatictextEchoedByParent(nodes, i)) { - continue - } - - // Interactive nodes without a selector can't be acted on β€” skip them - // so they don't leak as non-actionable entries in the text tree. - // Matches the guard in serializeWebSnapshot (line 141). - if (isInteractive && !node.selector) { - continue - } - - const tagName = - isInteractive && node.selector - ? extractTagFromSelector(node.selector, node.role) - : node.role - - result.push({ - role: node.role, - name: node.name, - selector: node.selector, - depth: node.depth, - isInteractive, - tagName, - level: node.level || undefined - }) - } - - return result -} - -// --------------------------------------------------------------------------- -// Mobile adapter β€” JSONElement tree β†’ SnapshotNode[] -// --------------------------------------------------------------------------- - -export function jsonElementToSnapshotNodes( - root: JSONElement, - platform: 'android' | 'ios', - options?: { - inViewportOnly?: boolean - viewport?: { width: number; height: number } - sourceXML?: string - } -): SnapshotNode[] { - const { inViewportOnly = true } = options ?? {} - const effectiveViewport = options?.viewport ?? { width: 9999, height: 9999 } - const automationName = platform === 'android' ? 'uiautomator2' : 'xcuitest' - const effectiveXML = options?.sourceXML || root.attributes._sourceXML - - const mobileNodes: MobileFlatNode[] = [] - collectMobileNodes(root, platform, 0, mobileNodes, { - inViewportOnly, - viewport: effectiveViewport, - sourceXML: effectiveXML, - automationName: effectiveXML ? automationName : undefined - }) - - suppressTagOnlyChildren(mobileNodes) - - return mobileNodes.map((m) => ({ - role: m.role, - name: m.name, - selector: m.selector, - depth: m.depth, - isInteractive: m.isInteractive, - tagName: m.tagName, - level: undefined - })) -} diff --git a/packages/core/src/element-types.ts b/packages/core/src/element-types.ts index 694b6735..1e2a269f 100644 --- a/packages/core/src/element-types.ts +++ b/packages/core/src/element-types.ts @@ -17,35 +17,3 @@ export type { // Re-export mobile types from locators for convenience. // Downstream consumers can also import directly from @wdio/devtools-core/locators. export type { JSONElement } from './locators/types.js' - -/** - * Flat intermediate node shared by both web and mobile snapshot pipelines. - * Both adapters (web: AccessibilityNode[], mobile: JSONElement tree) convert - * to this shape before buildSnapshot() renders them. - */ -export interface SnapshotNode { - role: string - name: string - selector: string - depth: number - isInteractive: boolean - tagName: string - level?: number | string -} - -/** Entry in the elements map returned by getSnapshot(). */ -export interface SnapshotElement { - /** Raw selector β€” may need .instance(N) on mobile when duplicates exist. */ - selector: string - /** Selector with .instance(N) suffix β€” only set when it differs from `selector` (duplicate disambiguation). */ - qualifiedSelector?: string - tagName: string - role: string - text: string -} - -/** Return type of getSnapshot(). */ -export interface SnapshotResult { - text: string - elements: Record<string, SnapshotElement> -} diff --git a/packages/core/tests/element-snapshot.test.ts b/packages/core/tests/element-snapshot.test.ts deleted file mode 100644 index 245e42da..00000000 --- a/packages/core/tests/element-snapshot.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -// @vitest-environment happy-dom -import { beforeEach, describe, expect, it } from 'vitest' - -import { accessibilityTreeScript } from '@wdio/devtools-shared' -import type { AccessibilityNode } from '@wdio/devtools-shared' -import { accessibilityNodesToSnapshotNodes } from '../src/element-snapshot.js' - -/** The script is injectable source, so it is run the way the adapters run it. */ -function a11yNodes(html: string, runner: 'mocha' | 'nightwatch') { - document.body.innerHTML = html - return new Function( - `return ${accessibilityTreeScript(false, runner)}` - )() as AccessibilityNode[] -} - -beforeEach(() => { - // happy-dom has no layout engine, so the script's visibility gate would reject - // every element and the walk would return nothing. - Element.prototype.checkVisibility = () => true -}) - -describe('accessibilityNodesToSnapshotNodes', () => { - it('yields its tag from a captured locator in either dialect', () => { - // The serializer reads the tag back out of the locator it was handed, so a - // dialect it can't parse would report the ARIA role as the tag instead. - for (const runner of ['mocha', 'nightwatch'] as const) { - const nodes = accessibilityNodesToSnapshotNodes( - a11yNodes('<a href="/logout"><i></i> Logout</a>', runner), - { inViewportOnly: false } - ) - - expect(nodes.find((n) => n.name === 'Logout')?.tagName).toBe('a') - } - }) -}) diff --git a/packages/core/tests/mobile-snapshot.test.ts b/packages/core/tests/mobile-snapshot.test.ts new file mode 100644 index 00000000..ef8a4fc6 --- /dev/null +++ b/packages/core/tests/mobile-snapshot.test.ts @@ -0,0 +1,100 @@ +import { describe, expect, it } from 'vitest' + +import { serializeMobileSnapshot } from '../src/element-snapshot.js' +import type { JSONElement } from '../src/locators/types.js' + +function mobileEl( + tagName: string, + attrs: JSONElement['attributes'], + children: JSONElement[] = [] +): JSONElement { + return { tagName, attributes: attrs, children, path: '' } +} + +describe('serializeMobileSnapshot', () => { + it('produces a platform header with device and viewport', () => { + const root = mobileEl('hierarchy', {}) + const out = serializeMobileSnapshot(root, { + platform: 'android', + deviceName: 'Pixel 7', + viewport: { width: 412, height: 915 } + }) + expect(out).toMatch('[android β€” Pixel 7 (412Γ—915)]') + }) + + it('renders interactive Android element with accessibility-id locator', () => { + const root = mobileEl('hierarchy', {}, [ + mobileEl('android.widget.Button', { + clickable: 'true', + 'content-desc': 'Skip', + text: '' + }) + ]) + const out = serializeMobileSnapshot(root, { platform: 'android' }) + expect(out).toContain('button "Skip" β†’ ~Skip') + }) + + it('falls back to resource-id when no content-desc', () => { + const root = mobileEl('hierarchy', {}, [ + mobileEl('android.widget.EditText', { + clickable: 'true', + 'content-desc': '', + 'resource-id': 'com.example:id/search', + text: '' + }) + ]) + const out = serializeMobileSnapshot(root, { platform: 'android' }) + expect(out).toContain('textbox "search" β†’ id:com.example:id/search') + }) + + it('renders ∈ ancestor context when element has no identity', () => { + const root = mobileEl('hierarchy', {}, [ + mobileEl( + 'android.widget.LinearLayout', + { 'content-desc': 'Search section' }, + [ + mobileEl('android.widget.EditText', { + clickable: 'true', + 'content-desc': '', + 'resource-id': 'com.example:id/search', + text: '' + }) + ] + ) + ]) + const out = serializeMobileSnapshot(root, { platform: 'android' }) + expect(out).toContain( + 'textbox "search" ∈ "Search section" β†’ id:com.example:id/search' + ) + }) + + it('renders iOS element with accessibility-id', () => { + const root = mobileEl('XCUIElementTypeApplication', {}, [ + mobileEl('XCUIElementTypeButton', { + accessible: 'true', + name: 'Accept All Cookies', + label: 'Accept All Cookies' + }) + ]) + const out = serializeMobileSnapshot(root, { platform: 'ios' }) + expect(out).toContain('button "Accept All Cookies" β†’ ~Accept All Cookies') + }) + + it('simplifies iOS XCUIElementType prefix', () => { + const root = mobileEl('XCUIElementTypeApplication', {}, [ + mobileEl('XCUIElementTypeScrollView', {}) + ]) + const out = serializeMobileSnapshot(root, { platform: 'ios' }) + expect(out).toContain('ScrollView') + expect(out).not.toContain('XCUIElementType') + }) + + it('shows container without selector', () => { + const root = mobileEl('hierarchy', {}, [ + mobileEl('android.widget.FrameLayout', { 'content-desc': '' }) + ]) + const out = serializeMobileSnapshot(root, { platform: 'android' }) + expect(out).toContain('FrameLayout') + expect(out).not.toContain('β†’') + }) +}) diff --git a/packages/elements/README.md b/packages/elements/README.md index b188671c..de143690 100644 --- a/packages/elements/README.md +++ b/packages/elements/README.md @@ -8,7 +8,7 @@ Element detection and locator generation for WebdriverIO β€” browser DOM queryin npm install @wdio/elements ``` -Requires `webdriverio` as a peer dependency (`^9.0.0 || ^10.0.0`). +Requires `webdriverio` as a peer dependency (`^10.0.0`). ## Usage @@ -23,30 +23,28 @@ const result = await getElements(browser, { limit: 50, inViewportOnly: true }) ### Accessibility snapshot (`getSnapshot`) -A single call for web and mobile that returns an AI-readable accessibility/DOM snapshot as a `SnapshotResult` β€” a text tree with `e1`, `e2`, … virtual element IDs baked in, plus an `elements` map that resolves each ID to a real selector. No post-processing required. +A single call for web and native sessions that returns the same text as the WebdriverIO CLI's `wdio session snapshot --selectors` (add `--viewport` for `{ viewport: true }`). It is built on `@wdio/snapshot`: each actionable element gets an `eN` ref, and its line ends in `β†’ <selector>`. The default walks the whole document, so on long pages `{ viewport: true }` is much smaller and faster. ```ts import { getSnapshot } from '@wdio/elements' -const { text, elements } = await getSnapshot(browser, { inViewportOnly: true }) -// text: '[Page: Login β€” https://…]\n button "Log in" β†’ //button[contains(., "Log in")]\n …' -// elements: { e1: { selector, qualifiedSelector?, tagName, role, text }, … } +const { text, refs } = await getSnapshot(browser) // full page +const visible = await getSnapshot(browser, { viewport: true }) +// text: '- button "start" [ref=e1] β†’ ~start' (one line per node) +// refs: SnapshotRef[] β€” { id, candidates, … } for every ref in the text ``` -Every locator this API returns is portable across WebdriverIO, Selenium and -Nightwatch: CSS where an id/attribute/class identifies the element uniquely, -XPath where its text does (WebdriverIO resolves a leading `//` as XPath; -Selenium takes it via `By.xpath`, Nightwatch via its `'xpath'` locate strategy). +Web sessions walk the DOM in the page; native sessions (`platformName` of Android, iOS, Mac or Windows with no `browserName`) parse the page source. Errors (`SnapshotError`) propagate instead of returning a placeholder. -The DevTools **per-action trace capture** runs the same scripts but asks for the -locator in the recording runner's own dialect, so a WebdriverIO trace shows -`button*=Log in` while a Selenium one shows the XPath above. Nightwatch prefers a -unique CSS selector and falls back to that XPath only when none exists. Only -the text branch differs; every other branch is the same portable CSS. +The DevTools **per-action trace capture** is a separate path with its own page scripts, so a locator in a trace can differ from the one `getSnapshot` renders. `getSnapshot` renders `@wdio/snapshot`'s output, the same as the CLI. -It auto-detects platform: web sessions walk the browser accessibility tree, mobile sessions parse the page-source XML. `@wdio/devtools-service` also registers a `browser.getSnapshot()` runtime accessor that calls this directly. +Differences from the CLI, which keeps session state this function does not have: -This is the snapshot the DevTools **trace player** consumes: the per-action accessibility tree feeds the player's **A11y tab** (roles + accessible names, hover to highlight, click to copy a locator), and the resolved `elements` back the player's **element overlay / pick-locator** (click-to-copy boxes drawn over each interacted element, cross-linked to the A11y rows). +- No wait for a freshly loaded page to settle before collecting. +- Iframes are not inlined over BiDi. A cut or cross-origin frame renders as the frame-hint note (`wdio session frame <ref>`). +- Refs are numbered from `e1` on every call. + +`@wdio/devtools-service`'s `browser.getSnapshot()` calls this function and returns its `{ text, refs }`. Unlike the default here, it uses `viewport: true` when `viewport` is not set, so it reads the visible viewport; pass `{ viewport: false }` for the full page. It also returns the placeholder `{ text: '[Snapshot unavailable]', refs: [] }` (and logs a warning) instead of throwing, whereas the `getSnapshot` exported here throws `SnapshotError`. ### Browser @@ -76,24 +74,6 @@ const elements = await getMobileVisibleElements(browser, 'ios', { }) ``` -For the raw JSON element tree alongside the flat list: - -```ts -import { getMobileVisibleElementsWithTree } from '@wdio/elements' - -const { elements, tree } = await getMobileVisibleElementsWithTree(browser, 'android') -``` - -### AI-readable snapshots - -```ts -import { serializeWebSnapshot, serializeMobileSnapshot } from '@wdio/elements' - -const snapshot = await serializeWebSnapshot(browser, { includeBounds: true }) -// or -const snapshot = await serializeMobileSnapshot(browser, 'android', { includeLocators: true }) -``` - ### Locator generation ```ts @@ -121,11 +101,11 @@ Auto-detects platform and returns a unified result. ### `getSnapshot(browser, options)` -Auto-detects platform and returns a `SnapshotResult` β€” `{ text, elements }` β€” where `text` is the rendered accessibility tree with embedded `e1`, `e2`, … IDs and `elements` maps each ID to a `SnapshotElement` (`selector`, optional `qualifiedSelector` for `.instance(N)` disambiguation, `tagName`, `role`, `text`). +Returns `GetSnapshotResult` β€” `{ text, refs }` β€” where `text` is the rendered tree with `eN` refs and selectors, and `refs` is the `SnapshotRef[]` behind them. | Param | Type | Default | Description | |---|---|---|---| -| `inViewportOnly` | `boolean` | `true` | Only include elements whose bounds intersect the viewport | +| `viewport` | `boolean` | `false` | Only include what intersects the viewport; `false` snapshots the full page | ### `getInteractableBrowserElements(browser, options)` @@ -139,14 +119,6 @@ Single DOM walk returning the accessibility tree as a flat `AccessibilityNode[]` Parses page source XML (2 HTTP calls total) and returns elements with generated locators. -### `getMobileVisibleElementsWithTree(browser, platform, options)` - -Same as above but also returns the raw `JSONElement` tree. - -### `serializeWebSnapshot(browser, options)` / `serializeMobileSnapshot(browser, platform, options)` - -Generate AI-readable (TOON-format) snapshots for LLM consumption. - ### `@wdio/elements/locators` Re-exports the full locator generation pipeline from `@wdio/devtools-core`: @@ -167,9 +139,8 @@ export type { MobileElementInfo, GetMobileElementsOptions, AccessibilityNode, VisibleElementsResult, - WebSnapshotOptions, MobileSnapshotOptions, - GetSnapshotOptions, - SnapshotResult, SnapshotElement + GetSnapshotOptions, GetSnapshotResult, + CandidateKind, SnapshotCandidate, SnapshotNode, SnapshotRef } from '@wdio/elements' // From @wdio/elements/locators: diff --git a/packages/elements/ROADMAP.md b/packages/elements/ROADMAP.md index e1eeeff6..a5fc510c 100644 --- a/packages/elements/ROADMAP.md +++ b/packages/elements/ROADMAP.md @@ -19,7 +19,9 @@ net first. ### 1.2 Snapshot-output golden tests -`serializeMobileSnapshot` and `serializeWebSnapshot` need output-fidelity tests +`serializeMobileSnapshot` (`packages/core/src/element-snapshot.ts`) and +`serializeWebSnapshot` (`packages/trace/src/a11y-snapshot.ts`, re-exported by +core) need output-fidelity tests before the interactive-element dedup or mobile pipeline unification. Without them, any change to the snapshot format is a blind regression risk for LLM consumers. diff --git a/packages/elements/package.json b/packages/elements/package.json index 483af22b..27f9d158 100644 --- a/packages/elements/package.json +++ b/packages/elements/package.json @@ -35,7 +35,11 @@ "test": "vitest run", "prepublishOnly": "pnpm build" }, + "engines": { + "node": ">=22.19.0" + }, "dependencies": { + "@wdio/snapshot": "^10.0.2", "@xmldom/xmldom": "^0.9.12", "xpath": "^0.0.34" }, @@ -43,13 +47,14 @@ "@microsoft/api-extractor": "^7.59.3", "@types/node": "26.6.4", "@wdio/devtools-core": "workspace:^", - "@wdio/globals": "10.0.2", + "@wdio/devtools-shared": "workspace:^", + "@wdio/globals": "10.1.0", "tsup": "^8.5.1", "typescript": "6.0.3", "vitest": "^5.0.2", - "webdriverio": "^10.0.2" + "webdriverio": "^10.1.0" }, "peerDependencies": { - "webdriverio": "^9.0.0 || ^10.0.0" + "webdriverio": "^10.0.0" } } diff --git a/packages/elements/src/get-snapshot.ts b/packages/elements/src/get-snapshot.ts index 9f003a94..5f9bdb66 100644 --- a/packages/elements/src/get-snapshot.ts +++ b/packages/elements/src/get-snapshot.ts @@ -1,155 +1,96 @@ -/** - * Unified getSnapshot() β€” single call for web and mobile. - * - * Auto-detects platform, fetches the accessibility tree (web) or page source - * (mobile), converts to a flat SnapshotNode[], and renders a text tree with - * e1, e2, … virtual IDs baked in plus an elements map for direct selector - * resolution. - */ - -import type { SnapshotResult } from '@wdio/devtools-core/element-types' import { - buildSnapshot, - accessibilityNodesToSnapshotNodes, - jsonElementToSnapshotNodes -} from '@wdio/devtools-core/element-snapshot' -import { getBrowserAccessibilityTree } from './accessibility-tree.js' -import { xmlToJSON } from './locators/index.js' + attachSelectors, + collectWeb, + formatSnapshot, + inViewport, + nativePlatform, + parseNativeSource +} from '@wdio/snapshot' +import { deepCapString } from '@wdio/devtools-shared/device' +import type { NativePlatform, SnapshotNode, SnapshotRef } from '@wdio/snapshot' export interface GetSnapshotOptions { - /** Only include elements whose bounds intersect the viewport (default true). */ - inViewportOnly?: boolean + /** Only include what intersects the viewport (default false: the full page). */ + viewport?: boolean +} + +export interface GetSnapshotResult { + /** Accessibility tree as text, one `eN` ref per actionable element, each ending in `β†’ <selector>`. */ + text: string + refs: SnapshotRef[] +} + +const frameHint = (ref: string) => `wdio session frame ${ref}` + +const NATIVE_PLATFORMS = new Set(['android', 'ios', 'mac', 'windows']) + +// @wdio/session's `classify`: a browserName makes a mobile session web. Desktop +// browsers also report mac/windows here, which their browserName excludes too. +function nativePlatformName(caps: Record<string, unknown>): string | undefined { + const platformName = ( + deepCapString(caps, 'platformName') ?? + deepCapString(caps, 'appium:platformName') ?? + '' + ).toLowerCase() + return NATIVE_PLATFORMS.has(platformName) && + !deepCapString(caps, 'browserName') + ? platformName + : undefined } /** - * Take a snapshot of the current page/app state. - * - * Returns a text tree with eN virtual IDs for every interactive element - * and an elements map so consumers can resolve e1, e2, … to real selectors - * without any post-processing. + * Same text as `wdio session snapshot --selectors [--viewport]`, for web and + * native sessions alike. Throws SnapshotError rather than returning a partial tree. */ export async function getSnapshot( browser: WebdriverIO.Browser, - options?: GetSnapshotOptions -): Promise<SnapshotResult> { - const { inViewportOnly = true } = options ?? {} - - if (browser.isAndroid || browser.isIOS) { - return getMobileSnapshot(browser, inViewportOnly) + options: GetSnapshotOptions = {} +): Promise<GetSnapshotResult> { + const { viewport = false } = options + const caps = browser.capabilities as Record<string, unknown> + const platformName = nativePlatformName(caps) + const { tree, refs } = platformName + ? await collectNative(browser, nativePlatform(caps, platformName), viewport) + : await collectWebTree(browser, viewport) + + attachSelectors(tree, refs) + return { + text: formatSnapshot(tree, { selectors: true, frameHint }), + refs } - return getWebSnapshot(browser, inViewportOnly) } -// --------------------------------------------------------------------------- -// Web -// --------------------------------------------------------------------------- - -async function getWebSnapshot( - browser: WebdriverIO.Browser, - inViewportOnly: boolean -): Promise<SnapshotResult> { - const [url, title, nodes] = await Promise.all([ - safeCall(() => browser.getUrl()), - safeCall(() => browser.getTitle()), - getBrowserAccessibilityTree(browser, { inViewportOnly }) - ]) - - const header = buildWebHeader(title, url) - const snapshotNodes = accessibilityNodesToSnapshotNodes(nodes, { - inViewportOnly - }) - return buildSnapshot(header, snapshotNodes) -} - -function buildWebHeader(title?: string, url?: string): string { - let h = '[Page' - if (title) { - h += `: ${title}` - } - if (url) { - h += ` β€” ${url}` - } - h += ']' - return h +async function collectWebTree(browser: WebdriverIO.Browser, viewport: boolean) { + return collectWeb( + browser, + { counter: 0, all: false, boxes: false, viewport, assignRefs: 'ephemeral' }, + // Same rule as collectTop in @wdio/session; `bidi` is the path for a classic session. + { transport: browser.isBidi ? 'classic-first' : 'bidi' } + ) } -// --------------------------------------------------------------------------- -// Mobile -// --------------------------------------------------------------------------- - -async function getMobileSnapshot( +async function collectNative( browser: WebdriverIO.Browser, - inViewportOnly: boolean -): Promise<SnapshotResult> { - const platform: 'android' | 'ios' = browser.isAndroid ? 'android' : 'ios' - - const [viewportSize, pageSource] = await Promise.all([ - safeCall(() => browser.getWindowSize()), - safeCall(() => browser.getPageSource()) + platform: NativePlatform, + viewport: boolean +): Promise<{ tree: SnapshotNode; refs: SnapshotRef[] }> { + const [xml, size] = await Promise.all([ + browser.getPageSource(), + viewport ? browser.getWindowSize() : undefined ]) - - if (!pageSource) { - return { text: '[No elements found]', elements: {} } - } - - const root = xmlToJSON(pageSource) - if (!root) { - return { text: '[No elements found]', elements: {} } - } - - // A zero-dimension viewport (minimized app, broken ADB connection) would - // silently clip every element. Treat it as unavailable instead. - const safeViewport = - viewportSize?.width && viewportSize?.height ? viewportSize : undefined - - const deviceName = getDeviceName(browser) - - const header = buildMobileHeader(platform, deviceName, safeViewport) - - const snapshotNodes = jsonElementToSnapshotNodes(root, platform, { - inViewportOnly, - viewport: safeViewport, - sourceXML: pageSource - }) - - return buildSnapshot(header, snapshotNodes) -} - -function buildMobileHeader( - platform: string, - deviceName: string, - viewport?: { width: number; height: number } -): string { - let h = `[${platform}` - if (deviceName) { - h += ` β€” ${deviceName}` - } - if (viewport) { - h += ` (${viewport.width}Γ—${viewport.height})` - } - h += ']' - return h -} - -// --------------------------------------------------------------------------- -// Helpers -// --------------------------------------------------------------------------- - -async function safeCall<T>(fn: () => Promise<T>): Promise<T | undefined> { - try { - return await fn() - } catch { - return undefined + const parsed = parseNativeSource(xml, platform, { all: false, counter: 0 }) + if (!size) { + return parsed } + const tree = inViewport(parsed.tree, size.width, size.height) ?? parsed.tree + const shown = refIds(tree) + return { tree, refs: parsed.refs.filter((ref) => shown.has(ref.id)) } } -function getDeviceName(browser: WebdriverIO.Browser): string { - try { - const caps = browser.capabilities as Record<string, unknown> - return ( - (caps['appium:deviceName'] as string) ?? (caps.deviceName as string) ?? '' - ) - } catch { - return '' +function refIds(node: SnapshotNode, ids = new Set<string>()): Set<string> { + if (node.ref) { + ids.add(node.ref) } + node.children?.forEach((child) => refIds(child, ids)) + return ids } diff --git a/packages/elements/src/index.ts b/packages/elements/src/index.ts index d1b1d9ca..a19f934b 100644 --- a/packages/elements/src/index.ts +++ b/packages/elements/src/index.ts @@ -20,10 +20,14 @@ export type { export { getElements } from './get-elements.js' export type { VisibleElementsResult } from './get-elements.js' -export { serializeWebSnapshot, serializeMobileSnapshot } from './snapshot.js' -export type { WebSnapshotOptions, MobileSnapshotOptions } from './snapshot.js' export type { JSONElement } from './locators/index.js' export { getSnapshot } from './get-snapshot.js' -export type { GetSnapshotOptions } from './get-snapshot.js' -export type { SnapshotResult, SnapshotElement } from './snapshot.js' +export type { GetSnapshotOptions, GetSnapshotResult } from './get-snapshot.js' +export { SnapshotError } from '@wdio/snapshot' +export type { + CandidateKind, + SnapshotCandidate, + SnapshotNode, + SnapshotRef +} from '@wdio/snapshot' diff --git a/packages/elements/src/mobile-elements.ts b/packages/elements/src/mobile-elements.ts index 1eabbc53..e57f3cf2 100644 --- a/packages/elements/src/mobile-elements.ts +++ b/packages/elements/src/mobile-elements.ts @@ -161,12 +161,6 @@ export async function getMobileVisibleElementsWithTree( const tree = xmlToJSON(pageSource) - // Stash the source XML on the root element so serializeMobileSnapshot - // can use the full locator pipeline without requiring it as a separate arg. - if (tree) { - tree.attributes._sourceXML = pageSource - } - const elementLocators = generateAllElementLocators(pageSource, { platform, viewportSize, diff --git a/packages/elements/src/snapshot.ts b/packages/elements/src/snapshot.ts deleted file mode 100644 index e1d30489..00000000 --- a/packages/elements/src/snapshot.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * AI-readable snapshot serializers β€” re-exported from @wdio/devtools-core. - */ - -export { - serializeWebSnapshot, - serializeMobileSnapshot, - buildSnapshot, - accessibilityNodesToSnapshotNodes, - jsonElementToSnapshotNodes -} from '@wdio/devtools-core/element-snapshot' -export type { - WebSnapshotOptions, - MobileSnapshotOptions -} from '@wdio/devtools-core/element-snapshot' -export type { - SnapshotNode, - SnapshotElement, - SnapshotResult -} from '@wdio/devtools-core/element-types' diff --git a/packages/elements/tests/get-snapshot.test.ts b/packages/elements/tests/get-snapshot.test.ts new file mode 100644 index 00000000..7774567a --- /dev/null +++ b/packages/elements/tests/get-snapshot.test.ts @@ -0,0 +1,223 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest' + +vi.mock('@wdio/snapshot', async (importActual) => { + const actual = await importActual<typeof snap>() + return { + ...actual, + collectWeb: vi.fn(), + attachSelectors: vi.fn(), + formatSnapshot: vi.fn(() => 'TEXT'), + inViewport: vi.fn(), + parseNativeSource: vi.fn(actual.parseNativeSource) + } +}) + +import * as snap from '@wdio/snapshot' +import { getSnapshot } from '../src/get-snapshot.js' + +const TREE = { role: 'document', children: [] } as unknown as snap.SnapshotNode +const REFS = [{ id: 'e1', candidates: [] }] as unknown as snap.SnapshotRef[] + +function browser(overrides: Record<string, unknown>) { + return { + capabilities: { browserName: 'chrome' }, + ...overrides + } as unknown as WebdriverIO.Browser +} + +beforeEach(() => { + vi.clearAllMocks() + vi.mocked(snap.collectWeb).mockResolvedValue({ + tree: TREE, + refs: REFS, + counter: 1 + } as never) +}) + +describe('getSnapshot (web)', () => { + it('collects the full page and renders with selectors', async () => { + const b = browser({ isBidi: true }) + const result = await getSnapshot(b) + + expect(snap.collectWeb).toHaveBeenCalledWith( + b, + { + counter: 0, + all: false, + boxes: false, + viewport: false, + assignRefs: 'ephemeral' + }, + { transport: 'classic-first' } + ) + expect(snap.attachSelectors).toHaveBeenCalledWith(TREE, REFS) + expect(snap.formatSnapshot).toHaveBeenCalledWith(TREE, { + selectors: true, + frameHint: expect.any(Function) + }) + expect( + vi.mocked(snap.formatSnapshot).mock.calls[0][1]?.frameHint?.('e3') + ).toBe('wdio session frame e3') + expect(result).toEqual({ text: 'TEXT', refs: REFS }) + }) + + it('passes viewport through, and uses the bidi transport on a classic session', async () => { + const b = browser({ isBidi: false }) + await getSnapshot(b, { viewport: true }) + + expect(snap.collectWeb).toHaveBeenCalledWith( + b, + expect.objectContaining({ viewport: true, assignRefs: 'ephemeral' }), + { transport: 'bidi' } + ) + }) +}) + +const ANDROID_XML = `<?xml version="1.0" encoding="UTF-8"?> +<hierarchy rotation="0"> + <android.widget.FrameLayout bounds="[0,0][1080,2400]"> + <android.widget.Button text="Start" content-desc="start" clickable="true" resource-id="com.x:id/start" bounds="[100,200][400,300]" /> + </android.widget.FrameLayout> +</hierarchy>` + +function nativeBrowser() { + return browser({ + capabilities: { platformName: 'Android' }, + getPageSource: vi.fn().mockResolvedValue(ANDROID_XML), + getWindowSize: vi.fn().mockResolvedValue({ width: 1080, height: 2400 }) + }) +} + +it('parses a vendor-bag-only native session with the resolved platform', async () => { + await getSnapshot( + browser({ + capabilities: { 'bstack:options': { platformName: 'iOS' } }, + getPageSource: vi.fn().mockResolvedValue(ANDROID_XML) + }) + ) + expect(vi.mocked(snap.collectWeb)).not.toHaveBeenCalled() + expect(vi.mocked(snap.parseNativeSource).mock.calls[0][1]).toBe('ios') +}) + +describe('getSnapshot web/native routing (same as wdio session)', () => { + it.each([ + ['Android app', { platformName: 'Android' }, 'native'], + ['iOS app via appium: prefix', { 'appium:platformName': 'iOS' }, 'native'], + ['macOS app', { platformName: 'mac' }, 'native'], + ['Windows app', { platformName: 'Windows' }, 'native'], + [ + 'Android app with platformName only in a vendor bag', + { + 'bstack:options': { platformName: 'Android' }, + 'appium:automationName': 'UiAutomator2' + }, + 'native' + ], + [ + 'Safari on iOS with both only in a vendor bag', + { 'bstack:options': { platformName: 'iOS', browserName: 'Safari' } }, + 'web' + ], + [ + 'Chrome on Android', + { platformName: 'Android', browserName: 'chrome' }, + 'web' + ], + ['Safari on iOS', { platformName: 'iOS', browserName: 'Safari' }, 'web'], + [ + 'desktop Chrome on mac', + { platformName: 'mac', browserName: 'chrome' }, + 'web' + ], + [ + 'desktop Chrome on linux', + { platformName: 'linux', browserName: 'chrome' }, + 'web' + ] + ])('%s is %s', async (_label, capabilities, expected) => { + await getSnapshot( + browser({ + capabilities, + getPageSource: vi.fn().mockResolvedValue(ANDROID_XML) + }) + ) + expect(vi.mocked(snap.collectWeb).mock.calls.length > 0).toBe( + expected === 'web' + ) + }) +}) + +describe('getSnapshot (native)', () => { + it('parses the page source without a viewport cut by default', async () => { + const b = nativeBrowser() + await getSnapshot(b) + + expect(snap.parseNativeSource).toHaveBeenCalledWith( + ANDROID_XML, + 'android', + { + all: false, + counter: 0 + } + ) + expect(b.getWindowSize).not.toHaveBeenCalled() + expect(snap.inViewport).not.toHaveBeenCalled() + expect(snap.collectWeb).not.toHaveBeenCalled() + }) + + it('cuts to the window size when viewport is set, keeping the tree if nothing remains', async () => { + const b = nativeBrowser() + vi.mocked(snap.inViewport).mockReturnValue(undefined) + await getSnapshot(b, { viewport: true }) + + expect(snap.inViewport).toHaveBeenCalledWith(expect.anything(), 1080, 2400) + const rendered = vi.mocked(snap.formatSnapshot).mock.calls[0][0] + expect(rendered).toBe(vi.mocked(snap.attachSelectors).mock.calls[0][0]) + }) + + it('renders refs with selectors from a real parse', async () => { + const actual = await vi.importActual<typeof snap>('@wdio/snapshot') + vi.mocked(snap.attachSelectors).mockImplementation(actual.attachSelectors) + vi.mocked(snap.formatSnapshot).mockImplementation(actual.formatSnapshot) + + const { text, refs } = await getSnapshot(nativeBrowser()) + + expect(refs.length).toBeGreaterThan(0) + expect(text).toMatch(/\be1\b/) + expect(text).toContain('β†’') + expect(text).toContain('start') + }) + + it('parses an appium:-prefixed iOS session as iOS, not the android fallback', async () => { + await getSnapshot( + browser({ + capabilities: { 'appium:platformName': 'iOS' }, + getPageSource: vi + .fn() + .mockResolvedValue('<XCUIElementTypeApplication />') + }) + ) + expect(vi.mocked(snap.parseNativeSource).mock.calls[0][1]).toBe('ios') + }) + + it('returns only the refs left in the tree after a viewport cut', async () => { + const parsedRefs = [ + { id: 'e1', role: 'button', candidates: [] }, + { id: 'e2', role: 'button', candidates: [] } + ] + vi.mocked(snap.parseNativeSource).mockReturnValueOnce({ + tree: TREE, + refs: parsedRefs, + located: [], + counter: 2 + }) + vi.mocked(snap.inViewport).mockReturnValue({ + role: 'application', + children: [{ role: 'button', ref: 'e2' }] + }) + + const { refs } = await getSnapshot(nativeBrowser(), { viewport: true }) + + expect(refs.map((ref) => ref.id)).toEqual(['e2']) + }) +}) diff --git a/packages/elements/tests/locators/locator-generation.test.ts b/packages/elements/tests/locators/locator-generation.test.ts index c5d2de4b..d8d58bf7 100644 --- a/packages/elements/tests/locators/locator-generation.test.ts +++ b/packages/elements/tests/locators/locator-generation.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest' -import { locatorsToObject } from '@wdio/elements/locators' +import { locatorsToObject } from '../../src/locators/index.js' describe('locatorsToObject', () => { it('converts locator array to object', () => { diff --git a/packages/elements/tests/snapshot.test.ts b/packages/elements/tests/snapshot.test.ts deleted file mode 100644 index d739c7ef..00000000 --- a/packages/elements/tests/snapshot.test.ts +++ /dev/null @@ -1,697 +0,0 @@ -import { describe, it, expect } from 'vitest' -import { - serializeWebSnapshot, - serializeMobileSnapshot, - buildSnapshot, - accessibilityNodesToSnapshotNodes, - jsonElementToSnapshotNodes -} from '../src/snapshot.js' -import type { AccessibilityNode } from '../src/accessibility-tree.js' -import type { JSONElement } from '../src/locators/index.js' -import type { SnapshotNode } from '@wdio/devtools-core/element-types' - -// --------------------------------------------------------------------------- -// serializeWebSnapshot -// --------------------------------------------------------------------------- - -function node( - overrides: Partial<AccessibilityNode> & { role: string; depth: number } -): AccessibilityNode { - return { - name: '', - selector: '', - level: '', - disabled: '', - checked: '', - expanded: '', - selected: '', - pressed: '', - required: '', - readonly: '', - ...overrides - } -} - -describe('serializeWebSnapshot', () => { - it('produces a page header', () => { - const out = serializeWebSnapshot([]) - expect(out).toBe('[Page]') - }) - - it('includes title and url in header', () => { - const out = serializeWebSnapshot([], { - title: 'Login', - url: 'https://example.com/login' - }) - expect(out).toMatch('[Page: Login β€” https://example.com/login]') - }) - - it('renders interactive role with name and selector', () => { - const nodes = [ - node({ - role: 'button', - depth: 0, - name: 'Submit', - selector: 'button*=Submit' - }) - ] - const out = serializeWebSnapshot(nodes) - expect(out).toContain('button "Submit" β†’ button*=Submit') - }) - - it('renders interactive role with ∈ ancestor name when self has no name', () => { - const nodes = [ - node({ role: 'form', depth: 0, name: 'Login form' }), - node({ role: 'checkbox', depth: 1, name: '', selector: '#remember' }) - ] - const out = serializeWebSnapshot(nodes) - expect(out).toContain('checkbox ∈ "Login form" β†’ #remember') - }) - - it('omits interactive node with no selector regardless of name', () => { - const nodes = [ - node({ role: 'button', depth: 0, name: '', selector: '' }), - node({ - role: 'button', - depth: 0, - name: 'Named but unselector', - selector: '' - }) - ] - const out = serializeWebSnapshot(nodes) - // Only the header β€” both nodes skipped due to missing selector - expect(out.split('\n').length).toBe(1) - }) - - it('omits interactive node with ∈ context but no selector', () => { - const nodes = [ - node({ role: 'form', depth: 0, name: 'Login form' }), - node({ role: 'combobox', depth: 1, name: '', selector: '' }) - ] - const out = serializeWebSnapshot(nodes) - // combobox has ancestor context but no selector β€” must be dropped - expect(out).not.toContain('combobox') - expect(out).not.toContain('β†’') - }) - - it('renders container role without selector', () => { - const nodes = [node({ role: 'navigation', depth: 0, name: 'Main' })] - const out = serializeWebSnapshot(nodes) - expect(out).toContain('navigation "Main"') - expect(out).not.toContain('β†’') - }) - - it('renders heading with level suffix', () => { - const nodes = [ - node({ role: 'heading', depth: 0, name: 'Sign in', level: 1 }) - ] - const out = serializeWebSnapshot(nodes) - expect(out).toContain('heading[1] "Sign in"') - }) - - it('indents nodes according to depth', () => { - const nodes = [ - node({ role: 'navigation', depth: 0, name: 'Nav' }), - node({ role: 'link', depth: 1, name: 'Home', selector: 'a*=Home' }) - ] - const lines = serializeWebSnapshot(nodes).split('\n') - // depth 0 β†’ 1 level of indent (' ' Γ— 1), depth 1 β†’ 2 levels (' ' Γ— 2) - expect(lines[1]).toMatch(/^ navigation/) - expect(lines[2]).toMatch(/^ link/) - }) - - it('renders full login page example correctly', () => { - const nodes: AccessibilityNode[] = [ - node({ role: 'navigation', depth: 0, name: 'Main' }), - node({ role: 'link', depth: 1, name: 'Home', selector: 'a*=Home' }), - node({ role: 'main', depth: 0, name: '' }), - node({ role: 'heading', depth: 1, name: 'Sign in', level: 1 }), - node({ role: 'form', depth: 1, name: 'Login' }), - node({ - role: 'textbox', - depth: 2, - name: 'Email address', - selector: '#email' - }), - node({ - role: 'button', - depth: 2, - name: 'Sign in', - selector: 'button*=Sign in' - }) - ] - const out = serializeWebSnapshot(nodes, { - title: 'Login', - url: 'https://example.com/login' - }) - expect(out).toContain('[Page: Login β€” https://example.com/login]') - expect(out).toContain('navigation "Main"') - expect(out).toContain('link "Home" ∈ "Main" β†’ a*=Home') - expect(out).toContain('heading[1] "Sign in"') - expect(out).toContain('textbox "Email address" ∈ "Login" β†’ #email') - expect(out).toContain('button "Sign in" ∈ "Login" β†’ button*=Sign in') - }) -}) - -// --------------------------------------------------------------------------- -// serializeMobileSnapshot -// --------------------------------------------------------------------------- - -function mobileEl( - tagName: string, - attrs: JSONElement['attributes'], - children: JSONElement[] = [] -): JSONElement { - return { tagName, attributes: attrs, children, path: '' } -} - -describe('serializeMobileSnapshot', () => { - it('produces a platform header with device and viewport', () => { - const root = mobileEl('hierarchy', {}) - const out = serializeMobileSnapshot(root, { - platform: 'android', - deviceName: 'Pixel 7', - viewport: { width: 412, height: 915 } - }) - expect(out).toMatch('[android β€” Pixel 7 (412Γ—915)]') - }) - - it('renders interactive Android element with accessibility-id locator', () => { - const root = mobileEl('hierarchy', {}, [ - mobileEl('android.widget.Button', { - clickable: 'true', - 'content-desc': 'Skip', - text: '' - }) - ]) - const out = serializeMobileSnapshot(root, { platform: 'android' }) - expect(out).toContain('button "Skip" β†’ ~Skip') - }) - - it('falls back to resource-id when no content-desc', () => { - const root = mobileEl('hierarchy', {}, [ - mobileEl('android.widget.EditText', { - clickable: 'true', - 'content-desc': '', - 'resource-id': 'com.example:id/search', - text: '' - }) - ]) - const out = serializeMobileSnapshot(root, { platform: 'android' }) - expect(out).toContain('textbox "search" β†’ id:com.example:id/search') - }) - - it('renders ∈ ancestor context when element has no identity', () => { - const root = mobileEl('hierarchy', {}, [ - mobileEl( - 'android.widget.LinearLayout', - { 'content-desc': 'Search section' }, - [ - mobileEl('android.widget.EditText', { - clickable: 'true', - 'content-desc': '', - 'resource-id': 'com.example:id/search', - text: '' - }) - ] - ) - ]) - const out = serializeMobileSnapshot(root, { platform: 'android' }) - expect(out).toContain( - 'textbox "search" ∈ "Search section" β†’ id:com.example:id/search' - ) - }) - - it('renders iOS element with accessibility-id', () => { - const root = mobileEl('XCUIElementTypeApplication', {}, [ - mobileEl('XCUIElementTypeButton', { - accessible: 'true', - name: 'Accept All Cookies', - label: 'Accept All Cookies' - }) - ]) - const out = serializeMobileSnapshot(root, { platform: 'ios' }) - expect(out).toContain('button "Accept All Cookies" β†’ ~Accept All Cookies') - }) - - it('simplifies iOS XCUIElementType prefix', () => { - const root = mobileEl('XCUIElementTypeApplication', {}, [ - mobileEl('XCUIElementTypeScrollView', {}) - ]) - const out = serializeMobileSnapshot(root, { platform: 'ios' }) - expect(out).toContain('ScrollView') - expect(out).not.toContain('XCUIElementType') - }) - - it('shows container without selector', () => { - const root = mobileEl('hierarchy', {}, [ - mobileEl('android.widget.FrameLayout', { 'content-desc': '' }) - ]) - const out = serializeMobileSnapshot(root, { platform: 'android' }) - expect(out).toContain('FrameLayout') - expect(out).not.toContain('β†’') - }) -}) - -// --------------------------------------------------------------------------- -// buildSnapshot -// --------------------------------------------------------------------------- - -function snapNode(overrides: Partial<SnapshotNode>): SnapshotNode { - return { - role: 'button', - name: '', - selector: '', - depth: 0, - isInteractive: false, - tagName: 'button', - ...overrides - } -} - -describe('buildSnapshot', () => { - it('returns empty elements map for empty nodes', () => { - const result = buildSnapshot('[Page]', []) - expect(result.text).toBe('[Page]') - expect(result.elements).toEqual({}) - }) - - it('renders structural nodes without eN IDs', () => { - const nodes = [ - snapNode({ - role: 'navigation', - depth: 0, - name: 'Main', - isInteractive: false, - tagName: 'nav' - }) - ] - const result = buildSnapshot('[Page]', nodes) - expect(result.text).toContain('navigation "Main"') - expect(result.text).not.toContain('e1') - expect(result.text).not.toContain('β†’') - expect(result.elements).toEqual({}) - }) - - it('assigns e1 to first interactive element', () => { - const nodes = [ - snapNode({ - role: 'button', - depth: 0, - name: 'Submit', - selector: 'button*=Submit', - isInteractive: true, - tagName: 'button' - }) - ] - const result = buildSnapshot('[Page]', nodes) - expect(result.text).toContain('e1 button "Submit" β†’ button*=Submit') - expect(result.elements).toEqual({ - e1: { - selector: 'button*=Submit', - tagName: 'button', - role: 'button', - text: 'Submit' - } - }) - }) - - it('skips eN for non-interactive nodes and continues numbering', () => { - const nodes = [ - snapNode({ - role: 'navigation', - depth: 0, - name: 'Nav', - isInteractive: false, - tagName: 'nav' - }), - snapNode({ - role: 'link', - depth: 1, - name: 'Home', - selector: 'a*=Home', - isInteractive: true, - tagName: 'a' - }), - snapNode({ - role: 'button', - depth: 0, - name: 'Submit', - selector: 'button*=Submit', - isInteractive: true, - tagName: 'button' - }) - ] - const result = buildSnapshot('[Page]', nodes) - expect(result.text).toContain('navigation "Nav"') - // link at depth 1 has "Nav" as its structural ancestor β†’ ∈ context - expect(result.text).toContain('e1 link "Home" ∈ "Nav" β†’ a*=Home') - // button at depth 0 also gets ∈ "Nav" β€” Nav is a same-depth structural sibling - expect(result.text).toContain( - 'e2 button "Submit" ∈ "Nav" β†’ button*=Submit' - ) - expect(Object.keys(result.elements)).toEqual(['e1', 'e2']) - }) - - it('renders heading with level suffix', () => { - const nodes = [ - snapNode({ - role: 'heading', - depth: 0, - name: 'Welcome', - level: 2, - isInteractive: false, - tagName: 'h2' - }) - ] - const result = buildSnapshot('[Page]', nodes) - expect(result.text).toContain('heading[2] "Welcome"') - }) - - it('renders ∈ ancestor context for interactive nodes', () => { - const nodes = [ - snapNode({ - role: 'form', - depth: 0, - name: 'Login', - isInteractive: false, - tagName: 'form' - }), - snapNode({ - role: 'textbox', - depth: 1, - name: 'Email', - selector: '#email', - isInteractive: true, - tagName: 'input' - }) - ] - const result = buildSnapshot('[Page]', nodes) - expect(result.text).toContain('e1 textbox "Email" ∈ "Login" β†’ #email') - }) - - it('omits ∈ context when same-depth sibling is interactive', () => { - const nodes = [ - snapNode({ - role: 'button', - depth: 0, - name: 'Cancel', - selector: 'button*=Cancel', - isInteractive: true, - tagName: 'button' - }), - snapNode({ - role: 'button', - depth: 0, - name: 'Submit', - selector: 'button*=Submit', - isInteractive: true, - tagName: 'button' - }) - ] - const result = buildSnapshot('[Page]', nodes) - // Second button should NOT have ∈ "Cancel" context (same-depth interactive isn't context) - expect(result.text).toContain('e2 button "Submit" β†’ button*=Submit') - expect(result.text).not.toContain('∈ "Cancel"') - }) - - it('appends .instance(N) for duplicate selectors', () => { - const nodes = [ - snapNode({ - role: 'button', - depth: 0, - name: 'Add', - selector: 'button*=Add', - isInteractive: true, - tagName: 'button' - }), - snapNode({ - role: 'button', - depth: 0, - name: 'Add', - selector: 'button*=Add', - isInteractive: true, - tagName: 'button' - }) - ] - const result = buildSnapshot('[Page]', nodes) - expect(result.text).toContain('button*=Add.instance(0)') - expect(result.text).toContain('button*=Add.instance(1)') - // Elements map stores the raw selector without .instance(N) - expect(result.elements['e1']!.selector).toBe('button*=Add') - expect(result.elements['e2']!.selector).toBe('button*=Add') - }) - - it('handles interactive node with no name but context ancestor', () => { - const nodes = [ - snapNode({ - role: 'form', - depth: 0, - name: 'Search', - isInteractive: false, - tagName: 'form' - }), - snapNode({ - role: 'textbox', - depth: 1, - name: '', - selector: '#q', - isInteractive: true, - tagName: 'input' - }) - ] - const result = buildSnapshot('[Page]', nodes) - expect(result.text).toContain('e1 textbox ∈ "Search" β†’ #q') - expect(result.elements['e1']!.text).toBe('') - }) - - it('indents according to depth', () => { - const nodes = [ - snapNode({ - role: 'main', - depth: 0, - name: '', - isInteractive: false, - tagName: 'main' - }), - snapNode({ - role: 'button', - depth: 1, - name: 'Click', - selector: '#btn', - isInteractive: true, - tagName: 'button' - }) - ] - const lines = buildSnapshot('[Page]', nodes).text.split('\n') - expect(lines[1]).toMatch(/^ main/) - expect(lines[2]).toMatch(/^ e1/) - }) -}) - -// --------------------------------------------------------------------------- -// accessibilityNodesToSnapshotNodes -// --------------------------------------------------------------------------- - -describe('accessibilityNodesToSnapshotNodes', () => { - it('converts interactive node and derives tagName from selector', () => { - const input = [ - node({ - role: 'button', - depth: 0, - name: 'Submit', - selector: 'button*=Submit' - }) - ] - const result = accessibilityNodesToSnapshotNodes(input) - expect(result).toHaveLength(1) - expect(result[0]).toMatchObject({ - role: 'button', - name: 'Submit', - selector: 'button*=Submit', - isInteractive: true, - tagName: 'button' - }) - }) - - it('filters out off-screen nodes when inViewportOnly is true', () => { - const input = [ - node({ - role: 'button', - depth: 0, - name: 'Submit', - selector: 'button*=Submit', - isInViewport: false - }) - ] - const result = accessibilityNodesToSnapshotNodes(input, { - inViewportOnly: true - }) - expect(result).toHaveLength(0) - }) - - it('keeps off-screen nodes when inViewportOnly is false', () => { - const input = [ - node({ - role: 'button', - depth: 0, - name: 'Submit', - selector: 'button*=Submit', - isInViewport: false - }) - ] - const result = accessibilityNodesToSnapshotNodes(input, { - inViewportOnly: false - }) - expect(result).toHaveLength(1) - }) - - it('sets isInteractive false for structural roles', () => { - const input = [node({ role: 'navigation', depth: 0, name: 'Nav' })] - const result = accessibilityNodesToSnapshotNodes(input) - expect(result[0]!.isInteractive).toBe(false) - expect(result[0]!.tagName).toBe('navigation') // fallback to role - }) - - it('suppresses statictext echoed by interactive parent', () => { - const input = [ - node({ - role: 'button', - depth: 0, - name: 'Submit', - selector: 'button*=Submit' - }), - node({ role: 'statictext', depth: 1, name: 'Submit' }) - ] - const result = accessibilityNodesToSnapshotNodes(input) - expect(result).toHaveLength(1) // statictext suppressed - expect(result[0]!.role).toBe('button') - }) - - it('derives tagName from link selector', () => { - const input = [ - node({ role: 'link', depth: 0, name: 'Home', selector: 'a*=Home' }) - ] - const result = accessibilityNodesToSnapshotNodes(input) - expect(result[0]!.tagName).toBe('a') - }) - - it('derives tagName from the xpath the capture emits for a text match', () => { - const input = [ - node({ - role: 'link', - depth: 0, - name: 'Home', - selector: '//a[contains(., "Home")]' - }), - node({ - role: 'button', - depth: 0, - name: 'Go', - selector: '//my-button[contains(., "Go")]' - }) - ] - const result = accessibilityNodesToSnapshotNodes(input) - expect(result.map((n) => n.tagName)).toEqual(['a', 'my-button']) - }) - - it('falls back to role for selectorless tag extraction', () => { - const input = [ - node({ role: 'textbox', depth: 0, name: 'Email', selector: '#email' }) - ] - const result = accessibilityNodesToSnapshotNodes(input) - // #email doesn't start with a tag prefix β†’ falls back to role - expect(result[0]!.tagName).toBe('textbox') - }) -}) - -// --------------------------------------------------------------------------- -// jsonElementToSnapshotNodes -// --------------------------------------------------------------------------- - -describe('jsonElementToSnapshotNodes', () => { - it('flattens a simple tree', () => { - const root = mobileEl('hierarchy', {}, [ - mobileEl('android.widget.Button', { - clickable: 'true', - 'content-desc': 'Submit', - text: '' - }) - ]) - const result = jsonElementToSnapshotNodes(root, 'android') - // Root hierarchy element + one button = 2 nodes - expect(result.length).toBeGreaterThanOrEqual(2) - const button = result.find((n) => n.role === 'button') - expect(button).toBeDefined() - expect(button).toMatchObject({ - role: 'button', - name: 'Submit', - isInteractive: true, - tagName: 'android.widget.Button' - }) - }) - - it('includes structural containers', () => { - const root = mobileEl('hierarchy', {}, [ - mobileEl( - 'android.widget.LinearLayout', - { - 'content-desc': '' - }, - [ - mobileEl('android.widget.Button', { - clickable: 'true', - 'content-desc': 'OK', - text: '' - }) - ] - ) - ]) - const result = jsonElementToSnapshotNodes(root, 'android') - // LinearLayout is not in INTERACTIVE_ROLES, not clickable β†’ structural - expect(result.length).toBeGreaterThanOrEqual(2) - const structNode = result.find((n) => n.role === 'LinearLayout') - expect(structNode).toBeDefined() - expect(structNode!.isInteractive).toBe(false) - }) - - it('suppresses tag-only-interactive children of explicit parents', () => { - const root = mobileEl('hierarchy', {}, [ - mobileEl( - 'android.widget.LinearLayout', - { - clickable: 'true', - 'content-desc': 'Row' - }, - [ - // TextView is in ANDROID_INTERACTABLE_TAGS (tag-interactive), - // but not explicitly clickable β†’ suppressed by suppressTagOnlyChildren - mobileEl('android.widget.TextView', { - clickable: 'false', - 'content-desc': '', - text: 'Label' - }) - ] - ) - ]) - const result = jsonElementToSnapshotNodes(root, 'android') - const textView = result.find((n) => n.role === 'statictext') - expect(textView).toBeDefined() - expect(textView!.isInteractive).toBe(false) // suppressed - }) - - it('propagates tagName from the mobile element', () => { - const root = mobileEl('hierarchy', {}, [ - mobileEl('android.widget.EditText', { - clickable: 'true', - 'content-desc': '', - 'resource-id': 'com.example:id/email', - text: '' - }) - ]) - const result = jsonElementToSnapshotNodes(root, 'android') - const editText = result.find((n) => n.role === 'textbox') - expect(editText).toBeDefined() - expect(editText!.tagName).toBe('android.widget.EditText') - }) -}) diff --git a/packages/elements/tsconfig.json b/packages/elements/tsconfig.json index 3bcc9638..89949f1c 100644 --- a/packages/elements/tsconfig.json +++ b/packages/elements/tsconfig.json @@ -10,7 +10,7 @@ "allowImportingTsExtensions": false, "declaration": true, "skipLibCheck": true, - "types": ["node", "@wdio/globals/types"] + "types": ["node", "webdriverio"] }, "include": ["src/**/*"] } diff --git a/packages/nightwatch-devtools/bin/show-trace.mjs b/packages/nightwatch-devtools/bin/show-trace.mjs new file mode 100755 index 00000000..83cac9cb --- /dev/null +++ b/packages/nightwatch-devtools/bin/show-trace.mjs @@ -0,0 +1,4 @@ +#!/usr/bin/env node +import { runShowTraceCli } from '@wdio/devtools-backend/show-trace' + +void runShowTraceCli(process.argv.slice(2)) diff --git a/packages/nightwatch-devtools/package.json b/packages/nightwatch-devtools/package.json index d7d160db..f30be557 100644 --- a/packages/nightwatch-devtools/package.json +++ b/packages/nightwatch-devtools/package.json @@ -53,12 +53,12 @@ "dependencies": { "@wdio/devtools-backend": "workspace:*", "@wdio/devtools-script": "workspace:*", - "@wdio/logger": "^10.0.0", + "@wdio/logger": "^10.1.0", "@xmldom/xmldom": "^0.9.12", "fluent-ffmpeg": "^2.1.3", "import-meta-resolve": "^4.2.0", "stacktrace-parser": "^0.1.11", - "webdriverio": "^10.0.2", + "webdriverio": "^10.1.0", "ws": "^8.22.0", "xpath": "^0.0.34", "yazl": "^3.3.1" diff --git a/packages/selenium-devtools/bin/show-trace.mjs b/packages/selenium-devtools/bin/show-trace.mjs new file mode 100755 index 00000000..83cac9cb --- /dev/null +++ b/packages/selenium-devtools/bin/show-trace.mjs @@ -0,0 +1,4 @@ +#!/usr/bin/env node +import { runShowTraceCli } from '@wdio/devtools-backend/show-trace' + +void runShowTraceCli(process.argv.slice(2)) diff --git a/packages/selenium-devtools/package.json b/packages/selenium-devtools/package.json index e9feb001..df7fe42e 100644 --- a/packages/selenium-devtools/package.json +++ b/packages/selenium-devtools/package.json @@ -53,10 +53,10 @@ "dependencies": { "@wdio/devtools-backend": "workspace:*", "@wdio/devtools-script": "workspace:*", - "@wdio/logger": "^10.0.0", + "@wdio/logger": "^10.1.0", "@xmldom/xmldom": "^0.9.12", "stacktrace-parser": "^0.1.11", - "webdriverio": "^10.0.2", + "webdriverio": "^10.1.0", "ws": "^8.22.0", "xpath": "^0.0.34", "yazl": "^3.3.1" diff --git a/packages/service/bin/show-trace.mjs b/packages/service/bin/show-trace.mjs new file mode 100755 index 00000000..83cac9cb --- /dev/null +++ b/packages/service/bin/show-trace.mjs @@ -0,0 +1,4 @@ +#!/usr/bin/env node +import { runShowTraceCli } from '@wdio/devtools-backend/show-trace' + +void runShowTraceCli(process.argv.slice(2)) diff --git a/packages/service/package.json b/packages/service/package.json index 2e0c0bd2..8a3392d5 100644 --- a/packages/service/package.json +++ b/packages/service/package.json @@ -64,26 +64,26 @@ "@types/fluent-ffmpeg": "^2.1.28", "@types/stack-trace": "^0.0.33", "@types/ws": "^8.18.2", - "@wdio/allure-reporter": "^10.0.1", + "@wdio/allure-reporter": "^10.1.0", "@wdio/devtools-core": "workspace:^", "@wdio/devtools-shared": "workspace:^", - "@wdio/globals": "10.0.2", - "@wdio/logger": "10.0.0", + "@wdio/globals": "10.1.0", + "@wdio/logger": "10.1.0", "@wdio/protocols": "10.0.2", - "@wdio/reporter": "10.0.1", - "@wdio/types": "10.0.1", + "@wdio/reporter": "10.1.0", + "@wdio/types": "10.1.0", "typescript": "6.0.3", "vite": "^8.3.2", "vite-plugin-dts": "^5.1.1", - "webdriverio": "^10.0.2" + "webdriverio": "^10.1.0" }, "peerDependencies": { - "@wdio/allure-reporter": "^9.0.0 || ^10.0.0", - "@wdio/logger": "^9.18.0 || ^10.0.0", - "@wdio/protocols": "^9.30.1 || ^10.0.0", - "@wdio/reporter": "^9.19.1 || ^10.0.0", - "@wdio/types": "^9.19.1 || ^10.0.0", - "webdriverio": "^9.19.1 || ^10.0.0" + "@wdio/allure-reporter": "^10.0.0", + "@wdio/logger": "^10.0.0", + "@wdio/protocols": "^10.0.0", + "@wdio/reporter": "^10.0.0", + "@wdio/types": "^10.0.0", + "webdriverio": "^10.0.0" }, "peerDependenciesMeta": { "@wdio/allure-reporter": { diff --git a/packages/service/src/index.ts b/packages/service/src/index.ts index 07ee2321..c55d9029 100644 --- a/packages/service/src/index.ts +++ b/packages/service/src/index.ts @@ -52,6 +52,7 @@ import { ScreencastLifecycle } from './screencast-lifecycle.js' import { attachBidiListeners } from './bidi-listeners.js' import { parse } from 'stack-trace' import { type ServiceOptions, TraceType } from './types.js' +import type { GetSnapshotOptions, GetSnapshotResult } from '@wdio/elements' import { CONTEXT_CHANGE_COMMANDS, INTERNAL_COMMANDS, @@ -294,17 +295,21 @@ export default class DevToolsHookService implements Services.ServiceInstance { * @wdio/elements' getSnapshot() directly β€” no trace-mode overhead, * no screenshot round-trip, no page-settling. * - * Returns { text, elements } β€” see @wdio/elements SnapshotResult. + * Returns { text, refs } β€” see @wdio/elements GetSnapshotResult. */ browser.addCommand( 'getSnapshot', - async (options?: { inViewportOnly?: boolean }) => { + async (options?: GetSnapshotOptions): Promise<GetSnapshotResult> => { try { const { getSnapshot } = await import('@wdio/elements') - return await getSnapshot(browser, options ?? { inViewportOnly: true }) + // Viewport-only keeps the tree small enough for an agent loop to call repeatedly. + return await getSnapshot(browser, { + ...options, + viewport: options?.viewport ?? true + }) } catch (err) { log.warn(`getSnapshot failed: ${errorMessage(err)}`) - return { text: '[Snapshot unavailable]', elements: {} } + return { text: '[Snapshot unavailable]', refs: [] } } } ) diff --git a/packages/service/src/types.ts b/packages/service/src/types.ts index 1263df01..bc358e1a 100644 --- a/packages/service/src/types.ts +++ b/packages/service/src/types.ts @@ -4,7 +4,7 @@ // @wdio/devtools-service/types. New code should import directly from // @wdio/devtools-shared. -import type { SnapshotResult } from '@wdio/devtools-core/element-types' +import type { GetSnapshotOptions, GetSnapshotResult } from '@wdio/elements' export { TraceType, @@ -77,7 +77,7 @@ declare namespace WebdriverIO { getPuppeteer?: () => Promise<unknown> // Runtime DOM snapshot for agent auto-healing. Added by // @wdio/devtools-service in the before hook. - getSnapshot(options?: { inViewportOnly?: boolean }): Promise<SnapshotResult> + getSnapshot(options?: GetSnapshotOptions): Promise<GetSnapshotResult> } } diff --git a/packages/shared/src/device.ts b/packages/shared/src/device.ts index 006abb92..6b1cf800 100644 --- a/packages/shared/src/device.ts +++ b/packages/shared/src/device.ts @@ -56,7 +56,7 @@ function capString( * so a request-shaped bag's `firstMatch` array is deliberately not scanned: the * server merges `alwaysMatch` with the ONE entry it chose, and reading a * browser out of any entry would claim one the session never got. */ -function deepCapString( +export function deepCapString( caps: Record<string, unknown>, key: string ): string | undefined { diff --git a/packages/shared/src/locator-dialect.ts b/packages/shared/src/locator-dialect.ts index 262057f5..f50d07ad 100644 --- a/packages/shared/src/locator-dialect.ts +++ b/packages/shared/src/locator-dialect.ts @@ -65,12 +65,6 @@ export function isXPathLocator(locator: string): boolean { return /^\(*\.{0,2}\//.test(locator) } -/** Tag name an XPath locator is scoped to, for a consumer that reports the tag - * it matched. Undefined for CSS and for a tag-less expression (`//*[…]`). */ -export function xpathLocatorTag(locator: string): string | undefined { - return /^\/\/([a-z][a-z0-9-]*)\[/.exec(locator)?.[1] -} - /** WebdriverIO's text-locator forms β€” `tag*=Contains`, `tag=Exact`, tag optional. */ const TEXT_LOCATOR_RE = /^([a-z][a-z0-9-]*)?(\*?)=(.+)$/i diff --git a/packages/shared/src/snapshot-format.ts b/packages/shared/src/snapshot-format.ts index feeb8651..6a5b87d6 100644 --- a/packages/shared/src/snapshot-format.ts +++ b/packages/shared/src/snapshot-format.ts @@ -62,8 +62,7 @@ export const INTERACTIVE_ROLES = new Set([ ]) /** The fields of a node this module's helpers read. Deliberately narrower than - * `AccessibilityNode` so core's mobile `SnapshotNode` satisfies it too β€” both - * snapshot pipelines share these helpers. */ + * `AccessibilityNode` so the web and mobile serializers' nodes both satisfy it. */ export interface SnapshotFormatNode { role: string name: string diff --git a/packages/shared/tests/device.test.ts b/packages/shared/tests/device.test.ts index daf28c69..7842fe69 100644 --- a/packages/shared/tests/device.test.ts +++ b/packages/shared/tests/device.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest' import { + deepCapString, deviceFromCapabilities, deviceLabel, isNativeAppSession, @@ -254,3 +255,21 @@ describe('isNativeAppSession', () => { expect(isNativeAppSession({})).toBe(false) }) }) + +describe('deepCapString', () => { + it('prefers a top-level key over a vendor bag', () => { + expect(deepCapString({ k: 'top', 'v:options': { k: 'nested' } }, 'k')).toBe( + 'top' + ) + }) + + it('reads one level of vendor options', () => { + expect(deepCapString({ 'v:options': { k: 'nested' } }, 'k')).toBe('nested') + }) + + it('does not descend further or into arrays', () => { + expect( + deepCapString({ a: { b: { k: 'deep' } }, c: [{ k: 'arr' }] }, 'k') + ).toBeUndefined() + }) +}) diff --git a/packages/shared/tests/locator-dialect.test.ts b/packages/shared/tests/locator-dialect.test.ts index 5ce40eee..4ae47698 100644 --- a/packages/shared/tests/locator-dialect.test.ts +++ b/packages/shared/tests/locator-dialect.test.ts @@ -8,8 +8,7 @@ import { describe, it, expect } from 'vitest' import { isXPathLocator, locatorDialect, - locatorsMatch, - xpathLocatorTag + locatorsMatch } from '../src/locator-dialect.js' import { TEST_RUNNER_IDS, isTestRunnerId } from '../src/types.js' @@ -133,19 +132,6 @@ describe('isXPathLocator', () => { }) }) -describe('xpathLocatorTag', () => { - it('reads the tag the capture scoped its text match to', () => { - expect(xpathLocatorTag('//a[contains(., "Logout")]')).toBe('a') - expect(xpathLocatorTag('//my-button[contains(., "Go")]')).toBe('my-button') - }) - - it('has no tag to report for CSS or a tag-less expression', () => { - expect(xpathLocatorTag('//*[@text="Logout"]')).toBeUndefined() - expect(xpathLocatorTag('#username')).toBeUndefined() - expect(xpathLocatorTag('a*=Logout')).toBeUndefined() - }) -}) - // The exporter matches a command's locator against the captured element records // to stamp an input point. Once the capture emitted portable XPath, a `===` match // stopped recognising a test that locates by WebdriverIO text syntax. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1b820a83..a4cd4e33 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,8 +14,8 @@ importers: .: dependencies: '@wdio/cli': - specifier: 10.0.2 - version: 10.0.2(@types/node@26.6.4)(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(yauzl@2.10.0) + specifier: 10.1.0 + version: 10.1.0(@types/node@26.6.4)(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(yauzl@2.10.0) devDependencies: '@changesets/cli': specifier: ^3.0.3 @@ -42,8 +42,8 @@ importers: specifier: ^5.0.2 version: 5.0.3(vitest@5.0.3) '@wdio/allure-reporter': - specifier: ^10.0.1 - version: 10.0.1 + specifier: ^10.1.0 + version: 10.1.0 autoprefixer: specifier: ^10.6.1 version: 10.6.1(postcss@8.5.28) @@ -102,8 +102,8 @@ importers: specifier: ^5.0.2 version: 5.0.3(@types/node@26.6.4)(@vitest/coverage-v8@5.0.3)(happy-dom@20.14.5)(jsdom@24.1.3)(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) webdriverio: - specifier: ^10.0.2 - version: 10.0.2(yauzl@2.10.0) + specifier: ^10.1.0 + version: 10.1.0(yauzl@2.10.0) ws: specifier: ^8.22.0 version: 8.22.0 @@ -133,32 +133,32 @@ importers: examples/wdio: devDependencies: '@wdio/cli': - specifier: 10.0.2 - version: 10.0.2(@types/node@26.6.4)(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(yauzl@2.10.0) + specifier: 10.1.0 + version: 10.1.0(@types/node@26.6.4)(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(yauzl@2.10.0) '@wdio/cucumber-framework': - specifier: 10.0.1 - version: 10.0.1(yauzl@2.10.0) + specifier: 10.1.0 + version: 10.1.0(yauzl@2.10.0) '@wdio/devtools-service': specifier: workspace:* version: link:../../packages/service '@wdio/globals': - specifier: 10.0.2 - version: 10.0.2(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(webdriverio@10.0.2(yauzl@2.10.0)) + specifier: 10.1.0 + version: 10.1.0(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(webdriverio@10.1.0(yauzl@2.10.0)) '@wdio/local-runner': - specifier: 10.0.2 - version: 10.0.2(tsx@4.23.15)(webdriverio@10.0.2(yauzl@2.10.0))(yauzl@2.10.0) + specifier: 10.1.0 + version: 10.1.0(tsx@4.23.15)(webdriverio@10.1.0(yauzl@2.10.0))(yauzl@2.10.0) '@wdio/mocha-framework': - specifier: 10.0.1 - version: 10.0.1(yauzl@2.10.0) + specifier: 10.1.0 + version: 10.1.0(yauzl@2.10.0) '@wdio/spec-reporter': - specifier: 10.0.1 - version: 10.0.1 + specifier: 10.1.0 + version: 10.1.0 '@wdio/types': - specifier: 10.0.1 - version: 10.0.1 + specifier: 10.1.0 + version: 10.1.0 expect-webdriverio: specifier: ^8.0.0 - version: 8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)) + version: 8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)) ts-node: specifier: ^10.9.2 version: 10.9.2(@swc/core@1.16.13)(@swc/wasm@1.16.13)(@types/node@26.6.4)(typescript@6.0.3) @@ -196,23 +196,23 @@ importers: specifier: ^4.3.3 version: 4.3.3 '@wdio/browser-runner': - specifier: ^10.0.2 - version: 10.0.2(@types/node@26.6.4)(esbuild@0.28.2)(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(jiti@2.7.0)(magicast@0.5.5)(rollup@4.64.0)(tsx@4.23.15)(webdriver@10.0.2(yauzl@2.10.0))(webdriverio@10.0.2(yauzl@2.10.0))(yaml@2.9.1)(yauzl@2.10.0) + specifier: ^10.1.0 + version: 10.1.0(@types/node@26.6.4)(esbuild@0.28.2)(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(jiti@2.7.0)(magicast@0.5.5)(rollup@4.64.0)(tsx@4.23.15)(webdriver@10.1.0(yauzl@2.10.0))(webdriverio@10.1.0(yauzl@2.10.0))(yaml@2.9.1)(yauzl@2.10.0) '@wdio/devtools-shared': specifier: workspace:^ version: link:../shared '@wdio/globals': - specifier: ^10.0.2 - version: 10.0.2(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(webdriverio@10.0.2(yauzl@2.10.0)) + specifier: ^10.1.0 + version: 10.1.0(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(webdriverio@10.1.0(yauzl@2.10.0)) '@wdio/mocha-framework': - specifier: ^10.0.1 - version: 10.0.1(yauzl@2.10.0) + specifier: ^10.1.0 + version: 10.1.0(yauzl@2.10.0) '@wdio/protocols': specifier: 10.0.2 version: 10.0.2 '@wdio/reporter': - specifier: 10.0.1 - version: 10.0.1 + specifier: 10.1.0 + version: 10.1.0 autoprefixer: specifier: ^10.6.1 version: 10.6.1(postcss@8.5.28) @@ -221,7 +221,7 @@ importers: version: 6.0.2 expect-webdriverio: specifier: ^8.0.0 - version: 8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)) + version: 8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)) lit: specifier: ^3.3.3 version: 3.3.3 @@ -280,8 +280,8 @@ importers: specifier: workspace:^ version: link:../script '@wdio/logger': - specifier: 10.0.0 - version: 10.0.0 + specifier: 10.1.0 + version: 10.1.0 fastify: specifier: ^5.12.5 version: 5.12.5 @@ -314,8 +314,8 @@ importers: specifier: ^8.18.2 version: 8.18.2 '@wdio/cli': - specifier: ^10.0.2 - version: 10.0.2(@types/node@26.6.4)(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(yauzl@2.10.0) + specifier: ^10.1.0 + version: 10.1.0(@types/node@26.6.4)(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(yauzl@2.10.0) '@wdio/devtools-shared': specifier: workspace:^ version: link:../shared @@ -344,8 +344,8 @@ importers: specifier: ^8.18.2 version: 8.18.2 '@wdio/cli': - specifier: 10.0.2 - version: 10.0.2(@types/node@26.6.4)(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(yauzl@2.10.0) + specifier: 10.1.0 + version: 10.1.0(@types/node@26.6.4)(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(yauzl@2.10.0) '@wdio/devtools-service': specifier: workspace:^ version: link:../service @@ -353,14 +353,14 @@ importers: specifier: workspace:^ version: link:../shared '@wdio/globals': - specifier: 10.0.2 - version: 10.0.2(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(webdriverio@10.0.2(yauzl@2.10.0)) + specifier: 10.1.0 + version: 10.1.0(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(webdriverio@10.1.0(yauzl@2.10.0)) '@wdio/local-runner': - specifier: 10.0.2 - version: 10.0.2(tsx@4.23.15)(webdriverio@10.0.2(yauzl@2.10.0))(yauzl@2.10.0) + specifier: 10.1.0 + version: 10.1.0(tsx@4.23.15)(webdriverio@10.1.0(yauzl@2.10.0))(yauzl@2.10.0) '@wdio/mocha-framework': - specifier: 10.0.1 - version: 10.0.1(yauzl@2.10.0) + specifier: 10.1.0 + version: 10.1.0(yauzl@2.10.0) '@wdio/nightwatch-devtools': specifier: workspace:^ version: link:../nightwatch-devtools @@ -368,11 +368,11 @@ importers: specifier: workspace:^ version: link:../selenium-devtools '@wdio/spec-reporter': - specifier: 10.0.1 - version: 10.0.1 + specifier: 10.1.0 + version: 10.1.0 expect-webdriverio: specifier: ^8.0.0 - version: 8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)) + version: 8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)) nightwatch: specifier: ^3.16.0 version: 3.16.0(@cucumber/cucumber@13.2.1) @@ -380,8 +380,8 @@ importers: specifier: ^4.50.0 version: 4.50.0 webdriverio: - specifier: ^10.0.2 - version: 10.0.2(yauzl@2.10.0) + specifier: ^10.1.0 + version: 10.1.0(yauzl@2.10.0) ws: specifier: ^8.22.0 version: 8.22.0 @@ -415,6 +415,9 @@ importers: packages/elements: dependencies: + '@wdio/snapshot': + specifier: ^10.0.2 + version: 10.1.0(yauzl@2.10.0) '@xmldom/xmldom': specifier: ^0.9.12 version: 0.9.12 @@ -431,9 +434,12 @@ importers: '@wdio/devtools-core': specifier: workspace:^ version: link:../core + '@wdio/devtools-shared': + specifier: workspace:^ + version: link:../shared '@wdio/globals': - specifier: 10.0.2 - version: 10.0.2(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(webdriverio@10.0.2(yauzl@2.10.0)) + specifier: 10.1.0 + version: 10.1.0(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(webdriverio@10.1.0(yauzl@2.10.0)) tsup: specifier: ^8.5.1 version: 8.5.1(@microsoft/api-extractor@7.59.3(@types/node@26.6.4))(@swc/core@1.16.13)(jiti@2.7.0)(postcss@8.5.28)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.1) @@ -444,8 +450,8 @@ importers: specifier: ^5.0.2 version: 5.0.3(@types/node@26.6.4)(@vitest/coverage-v8@5.0.3)(happy-dom@20.14.5)(jsdom@24.1.3)(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) webdriverio: - specifier: ^10.0.2 - version: 10.0.2(yauzl@2.10.0) + specifier: ^10.1.0 + version: 10.1.0(yauzl@2.10.0) packages/nightwatch-devtools: dependencies: @@ -456,8 +462,8 @@ importers: specifier: workspace:* version: link:../script '@wdio/logger': - specifier: ^10.0.0 - version: 10.0.0 + specifier: ^10.1.0 + version: 10.1.0 '@xmldom/xmldom': specifier: ^0.9.12 version: 0.9.12 @@ -471,8 +477,8 @@ importers: specifier: ^0.1.11 version: 0.1.11 webdriverio: - specifier: ^10.0.2 - version: 10.0.2(yauzl@2.10.0) + specifier: ^10.1.0 + version: 10.1.0(yauzl@2.10.0) ws: specifier: ^8.22.0 version: 8.22.0 @@ -532,8 +538,8 @@ importers: specifier: workspace:* version: link:../script '@wdio/logger': - specifier: ^10.0.0 - version: 10.0.0 + specifier: ^10.1.0 + version: 10.1.0 '@xmldom/xmldom': specifier: ^0.9.12 version: 0.9.12 @@ -541,8 +547,8 @@ importers: specifier: ^0.1.11 version: 0.1.11 webdriverio: - specifier: ^10.0.2 - version: 10.0.2(yauzl@2.10.0) + specifier: ^10.1.0 + version: 10.1.0(yauzl@2.10.0) ws: specifier: ^8.22.0 version: 8.22.0 @@ -661,8 +667,8 @@ importers: specifier: ^8.18.2 version: 8.18.2 '@wdio/allure-reporter': - specifier: ^10.0.1 - version: 10.0.1 + specifier: ^10.1.0 + version: 10.1.0 '@wdio/devtools-core': specifier: workspace:^ version: link:../core @@ -670,20 +676,20 @@ importers: specifier: workspace:^ version: link:../shared '@wdio/globals': - specifier: 10.0.2 - version: 10.0.2(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(webdriverio@10.0.2(yauzl@2.10.0)) + specifier: 10.1.0 + version: 10.1.0(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(webdriverio@10.1.0(yauzl@2.10.0)) '@wdio/logger': - specifier: 10.0.0 - version: 10.0.0 + specifier: 10.1.0 + version: 10.1.0 '@wdio/protocols': specifier: 10.0.2 version: 10.0.2 '@wdio/reporter': - specifier: 10.0.1 - version: 10.0.1 + specifier: 10.1.0 + version: 10.1.0 '@wdio/types': - specifier: 10.0.1 - version: 10.0.1 + specifier: 10.1.0 + version: 10.1.0 typescript: specifier: 6.0.3 version: 6.0.3 @@ -694,8 +700,8 @@ importers: specifier: ^5.1.1 version: 5.1.2(@microsoft/api-extractor@7.59.3(@types/node@26.6.4))(esbuild@0.28.2)(rolldown@1.2.12)(rollup@4.64.0)(typescript@6.0.3)(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) webdriverio: - specifier: ^10.0.2 - version: 10.0.2(yauzl@2.10.0) + specifier: ^10.1.0 + version: 10.1.0(yauzl@2.10.0) packages/shared: {} @@ -1593,134 +1599,134 @@ packages: '@iconify/utils@3.1.7': resolution: {integrity: sha512-JZHlwdID+dy+lTgbYC8NEC4zeugqeYsc6jewvzb4c58kHauJn+X7rNwQjxz5p2qSjqaEeQoLkCIQ9v/H4PK0/w==} - '@inquirer/ansi@1.0.2': - resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} - engines: {node: '>=18'} + '@inquirer/ansi@2.0.9': + resolution: {integrity: sha512-0Ywt3S8tqM6TWUcsRlBFQ1x+X3/o8kktX0ZiKAnByYb9GFDknnOhse1PVtfiD2BXPI8ar+BWx9PV9R0lQIcygw==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - '@inquirer/checkbox@4.3.2': - resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==} - engines: {node: '>=18'} + '@inquirer/checkbox@5.2.7': + resolution: {integrity: sha512-/+QmGE/9bvE/EobaZDnzYe+T+QWoJrnmxwBQNtoi2OVSUR9d1znYsNyEoUrOZvFSxDYttrhzRIpXpaLkN+iIsg==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': 26.6.4 peerDependenciesMeta: '@types/node': optional: true - '@inquirer/confirm@5.1.21': - resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} - engines: {node: '>=18'} + '@inquirer/confirm@6.3.4': + resolution: {integrity: sha512-ZwnaZZDa1zxsyVrN32s447ydMnKcw7e8WWNT+R+Qsu0zAn8Rs6yi9d1B80Kob1Ul2cfUi7t8JD2t4/K7uEZpqA==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': 26.6.4 peerDependenciesMeta: '@types/node': optional: true - '@inquirer/core@10.3.2': - resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} - engines: {node: '>=18'} + '@inquirer/core@12.0.5': + resolution: {integrity: sha512-c0ZSnO9oVk/IlEGoZK3u8b3IZQeu9I6jUkXJSQnQEVRXsjKvtAq3AGqFL2LgfJhlzMZne08pZHWRWasIcI3Rew==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': 26.6.4 peerDependenciesMeta: '@types/node': optional: true - '@inquirer/editor@4.2.23': - resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==} - engines: {node: '>=18'} + '@inquirer/editor@5.3.5': + resolution: {integrity: sha512-6lU3/pPx5z3lHWejFW061MV4qZooBQYv/+EeGhNOPiP/i+hrYsHfxxBnnDGsAfg8YdLUd69YckoeOjtr3QuAUg==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': 26.6.4 peerDependenciesMeta: '@types/node': optional: true - '@inquirer/expand@4.0.23': - resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==} - engines: {node: '>=18'} + '@inquirer/expand@5.1.7': + resolution: {integrity: sha512-eiJ31YFCaB6fLoJCqLIn8S6eqUyME6vwr8KcP5h8cxmA+bV9RRVPO+kywoxb7G63HduDXV6sN/SM7o2R+ahEcQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': 26.6.4 peerDependenciesMeta: '@types/node': optional: true - '@inquirer/external-editor@1.0.3': - resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} - engines: {node: '>=18'} + '@inquirer/external-editor@3.0.6': + resolution: {integrity: sha512-rWmw6WG8JZ7LMn/srXEylYGhL6EXXJeROE7/4x4GREh6NgzqJBDbIgpNGsYoLPfobeb4VZtEYzPGnT5EFNYhiQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': 26.6.4 peerDependenciesMeta: '@types/node': optional: true - '@inquirer/figures@1.0.15': - resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} - engines: {node: '>=18'} + '@inquirer/figures@2.0.9': + resolution: {integrity: sha512-EAWgUTGQ/Umgga51dE3B2PUHbufuXarDfg86uVgoSgNHNNQnyFKcOrQLWVqYMghuSyHh8+2HUH0Js9cTC1WAdg==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - '@inquirer/input@4.3.1': - resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==} - engines: {node: '>=18'} + '@inquirer/input@5.1.8': + resolution: {integrity: sha512-psOSTgkL8y/OtgJJYbqJ0oISr2QBE0U1Ro/qQdA/EKjeJiwiUTQgQmq8o4ESNzVOWthIeh3YLD7BCUR9dKnR5g==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': 26.6.4 peerDependenciesMeta: '@types/node': optional: true - '@inquirer/number@3.0.23': - resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==} - engines: {node: '>=18'} + '@inquirer/number@4.2.5': + resolution: {integrity: sha512-lEy7LWsdF5qHx5QjHZqabUqM9P7i5uTMCt8GRzqxmwXXKbapKJDA+ucVflVVPAyj4snD5DTAD4L+sct85XOlOQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': 26.6.4 peerDependenciesMeta: '@types/node': optional: true - '@inquirer/password@4.0.23': - resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==} - engines: {node: '>=18'} + '@inquirer/password@5.2.4': + resolution: {integrity: sha512-T7ir3fflSSVCYEVqNyMBq+pIMsilQRtbZcD5gxn6Ewsin5TJWBxrGBdXveWtmeXVAeoInfhS+BhBUZaL4sFSDg==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': 26.6.4 peerDependenciesMeta: '@types/node': optional: true - '@inquirer/prompts@7.10.1': - resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==} - engines: {node: '>=18'} + '@inquirer/prompts@8.7.4': + resolution: {integrity: sha512-SAJt+QhY5rOJAIgZBw9TrHWfgrp6wsb9cqRCyqax+Hl6EiFfRXmD9EsIWkST8yq/dQ8H46Is2Sr/JG7Ls/LQ+Q==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': 26.6.4 peerDependenciesMeta: '@types/node': optional: true - '@inquirer/rawlist@4.1.11': - resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==} - engines: {node: '>=18'} + '@inquirer/rawlist@5.3.7': + resolution: {integrity: sha512-XveEe8v3BHj9ec00n+9i8FHjWhXjS6+jCTizYvXCqKUKtgkrq9xid8S5j3mYGW96qfxG3mwNoud3m3v8GDk9Pw==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': 26.6.4 peerDependenciesMeta: '@types/node': optional: true - '@inquirer/search@3.2.2': - resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==} - engines: {node: '>=18'} + '@inquirer/search@4.3.5': + resolution: {integrity: sha512-kIUecMugEN2YTvTmff+uYz0nAE0f9RFNDVZknfrh264vAQM9P8tnsXiUp7z8XbGuNIBEtFMJhvc9QquawpC46A==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': 26.6.4 peerDependenciesMeta: '@types/node': optional: true - '@inquirer/select@4.4.2': - resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==} - engines: {node: '>=18'} + '@inquirer/select@5.2.7': + resolution: {integrity: sha512-pRDWO4dTqSAvFQdO8yclKMtXNDm9K9HmvWB5UZmT3clw2OlOBNXveHzhyFmO/0d0yJMqlPcNITus1Jtpm6t8VQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': 26.6.4 peerDependenciesMeta: '@types/node': optional: true - '@inquirer/type@3.0.10': - resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} - engines: {node: '>=18'} + '@inquirer/type@4.2.0': + resolution: {integrity: sha512-2rnHX8RPo4glJYqnFc/v3nQeIhDcjyRRyaT7MGcfL/8xv/8K03SXYoA2tX06WVSKywWOE/ncbG3dtuzLjR5TCQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': 26.6.4 peerDependenciesMeta: @@ -1955,42 +1961,49 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@napi-rs/nice-linux-arm64-musl@1.1.1': resolution: {integrity: sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@napi-rs/nice-linux-ppc64-gnu@1.1.1': resolution: {integrity: sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==} engines: {node: '>= 10'} cpu: [ppc64] os: [linux] + libc: [glibc] '@napi-rs/nice-linux-riscv64-gnu@1.1.1': resolution: {integrity: sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] + libc: [glibc] '@napi-rs/nice-linux-s390x-gnu@1.1.1': resolution: {integrity: sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==} engines: {node: '>= 10'} cpu: [s390x] os: [linux] + libc: [glibc] '@napi-rs/nice-linux-x64-gnu@1.1.1': resolution: {integrity: sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@napi-rs/nice-linux-x64-musl@1.1.1': resolution: {integrity: sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@napi-rs/nice-openharmony-arm64@1.1.1': resolution: {integrity: sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==} @@ -2744,9 +2757,6 @@ packages: '@types/babel__generator@7.27.0': resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - '@types/babel__generator@7.6.8': - resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} - '@types/babel__template@7.4.4': resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} @@ -2801,8 +2811,8 @@ packages: '@types/shell-quote@1.7.5': resolution: {integrity: sha512-+UE8GAGRPbJVQDdxi16dgadcBfQ+KG2vgZhV1+3A1XmHbmwcdwhCUwIdy+d3pAGrbvgRoVSjeI9vOWyq376Yzw==} - '@types/sinonjs__fake-timers@8.1.5': - resolution: {integrity: sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==} + '@types/sinonjs__fake-timers@15.0.1': + resolution: {integrity: sha512-Ko2tjWJq8oozHzHV+reuvS5KYIRAokHnGbDwGh/J64LntgpbuylF74ipEL24HCyRjf9FOlBiBHWBR1RlVKsI1w==} '@types/split2@4.2.3': resolution: {integrity: sha512-59OXIlfUsi2k++H6CHgUQKEb2HKRokUA39HY1i1dS8/AIcqVjtAAFdf8u+HxTWK/4FUHMJQlKSZ4I6irCBJ1Zw==} @@ -2819,9 +2829,6 @@ packages: '@types/whatwg-mimetype@3.0.2': resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} - '@types/which@2.0.2': - resolution: {integrity: sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==} - '@types/ws@8.18.2': resolution: {integrity: sha512-67MQl+fpWKVTT1NYdnmo3U4sc/xPo/zQBncVnI74qmQa0z/b+1g6iYqNmGCPbxO+zz2aklb08a0oHfegiVd0/w==} @@ -2935,51 +2942,61 @@ packages: resolution: {integrity: sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==} cpu: [arm64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-arm64-musl@1.12.2': resolution: {integrity: sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==} cpu: [arm64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': resolution: {integrity: sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==} cpu: [loong64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-loong64-musl@1.12.2': resolution: {integrity: sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==} cpu: [loong64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': resolution: {integrity: sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==} cpu: [ppc64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': resolution: {integrity: sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==} cpu: [riscv64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': resolution: {integrity: sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==} cpu: [riscv64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': resolution: {integrity: sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==} cpu: [s390x] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-gnu@1.12.2': resolution: {integrity: sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==} cpu: [x64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-musl@1.12.2': resolution: {integrity: sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==} cpu: [x64] os: [linux] + libc: [musl] '@unrs/resolver-binding-openharmony-arm64@1.12.2': resolution: {integrity: sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==} @@ -3055,60 +3072,56 @@ packages: '@volar/typescript@2.4.28': resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} - '@wdio/allure-reporter@10.0.1': - resolution: {integrity: sha512-Unxlc1THjU8V3DDRqcFMWvFvZVdaeYUrNgQO4RlZvLF+ygio7mOkYjfz7SGmrrCsy7xye5Elqn4VCw/ic0pstQ==} + '@wdio/allure-reporter@10.1.0': + resolution: {integrity: sha512-+GRmFuEwVB3O5sNvbuA20qpteSE8Ub86G5FRu+yPoWRFgxu9aRhI0ju5FvgDw5r3FdqKYmzNRfRDM+jWpTxu1g==} engines: {node: '>=22.19.0'} - '@wdio/browser-runner@10.0.2': - resolution: {integrity: sha512-IJQZ725cBPQDFp3spmycFyOiBj76H0+7vB128us3+wpX2rjLG7UcFJZXfYLubquDa8ybMCZojzoIifHoiJH9ww==} + '@wdio/browser-runner@10.1.0': + resolution: {integrity: sha512-h6chh9SRc6gpJC/oJCooyxeTPtfOeln1+3qxXapQoEd8u0MrNp2oAHge4/b6o9pb2Jn0YqZatZFzctoiU5fPHg==} engines: {node: '>=22.19.0'} peerDependencies: - expect-webdriverio: ^8.0.0-0 || ^8.0.0-alpha.3 + expect-webdriverio: ^8.0.0 webdriver: ^10.0.0-0 || ^10.0.0 webdriverio: ^10.0.0-0 || ^10.0.0 - '@wdio/cli@10.0.2': - resolution: {integrity: sha512-t67EIII06oAtzCyy9RYNgmChzSnwY91Vw5NW8QwJg2p8ZT2cvDYrtytEYO/x3jZQK3uJ/mba2GlQQP4SHJK+Uw==} + '@wdio/cli@10.1.0': + resolution: {integrity: sha512-63cAdy/+lu2Z/2FdHA/8rRoV2NyiYg+pVRdi2pUADQZ20yzUQCjmu6clk+fWZ9sk3SeayUyMkm/8pvcO3hcoHA==} engines: {node: '>=22.19.0'} hasBin: true - '@wdio/config@10.0.1': - resolution: {integrity: sha512-n6elHE4ItKAtr4lwAaWIh/sAFuEFhyesLM27i5l9IWBJEK6VECdt0Pigj/4vUD2tliOoBtsWxphSW4oiNFXotg==} + '@wdio/config@10.1.0': + resolution: {integrity: sha512-V4G0uIhLTlSJRKLfr0ypu3SJLL90+LCuo9niBgqTmpNpJz4K3nwK2Mz//JuAKmz/OVXPb1HxJlrm2snfSOI2WQ==} engines: {node: '>=22.19.0'} - '@wdio/cucumber-framework@10.0.1': - resolution: {integrity: sha512-bcN2wlpUG/qtZ01TNPgrAnq8bWZKYp6C0qZglBz+PqBjzKQYGJ8fKt/bkHiuf6X93JqL3zqgzwG7mau5v5f/1w==} + '@wdio/cucumber-framework@10.1.0': + resolution: {integrity: sha512-HwtVd16xq/UoiirijGkZ8co/qw72MTgioaYKFGmuuvexCz5B6L9NcrK03TS358pJjVqYJYu3pxJ9GGLxvNBv+g==} engines: {node: '>=22.19.0 <23 || >=24 <25 || >=26'} - '@wdio/display-server@10.0.1': - resolution: {integrity: sha512-DMXpSCUpk/3KArcTFNlyEPI6O7EzeW9b3C4m54yZSlwaXFtix0P96c6ofiuvZ6bf/6bVd7s2GAxGk3yhmK8giw==} + '@wdio/display-server@10.1.0': + resolution: {integrity: sha512-RxtgqUPj58HIZypiZDwiWvp0e2u1eiojlSHdLkN5Z+iC5lexG0W8BHum4ujlbzhX3yclOUdBw7PR1IbpCd8cKg==} engines: {node: '>=22.19.0'} - '@wdio/dot-reporter@10.0.1': - resolution: {integrity: sha512-R0wuXuj4+f1yeXWnDyFqVPnJQzHrnepLH8ynS47wb87BVbtX9aVsbT9jctfplnfGHKySLm525w3/ajTj//anFg==} + '@wdio/dot-reporter@10.1.0': + resolution: {integrity: sha512-zE4A0GRTCoBJycdDnaZWPybf+v3Q8tCOW5Vva1YlHHA8LZ/nAVer8bI5Vo1hN2Hhcq7XIIrZbJK5vW/ZmTdQuw==} engines: {node: '>=22.19.0'} - '@wdio/globals@10.0.2': - resolution: {integrity: sha512-gQgKy2Yo99E9CIiHJgKDKrRPU3sYR92kZGStROArQvZqVcLsdPQZ3Ktf6L3cRyes1Vee/H82L/FG24vrB3C+mQ==} + '@wdio/globals@10.1.0': + resolution: {integrity: sha512-Y6FkkZz6jzMqIwI8R7BPj8bHuyRosxLZLGWRCHQFrU5mesjkW2NzYuPR7xwOPVmlaFJYUdzS1/EUYLr1BjpbSw==} engines: {node: '>=22.19.0'} peerDependencies: - expect-webdriverio: ^8.0.0-0 || ^8.0.0-alpha.3 + expect-webdriverio: ^8.0.0 webdriverio: ^10.0.0-0 || ^10.0.0 - '@wdio/local-runner@10.0.2': - resolution: {integrity: sha512-w3mamc9/CWttRYE+sLXYwHl7sDi2nxt7R8RpY41gT5sK2ol/UQ+96TaG4fO3KsotmLhNe15wfP/Z2umgeEx+Tg==} + '@wdio/local-runner@10.1.0': + resolution: {integrity: sha512-icWS+muUOAZzzW4SIThv36vpdyDiqZt2si/v1EK+h6g+D0lTMnTCN/Q+EmOk0iRwy8/d8JxmOcBty6Wdby8NxQ==} engines: {node: '>=22.19.0'} - '@wdio/logger@10.0.0': - resolution: {integrity: sha512-kUIw0ZzMs1mvXOaLEcjrM1nqNXY1reaJKReKNcjDSnfhnfUIb0Q5pAsxiMeil2uR0WsSUPzn0r3D9v//7vTOkA==} + '@wdio/logger@10.1.0': + resolution: {integrity: sha512-zZn9TMaxzTAHOGX5fLTs9E8Gw436l6xSFh+wZyXfRpgnzgeS5W/U0I6pBAjsvMn8rr5HAJC8Vy+WhiUxmbKsvQ==} engines: {node: '>=22.19.0'} - '@wdio/logger@9.29.1': - resolution: {integrity: sha512-0ZAEIo6PNyMIJPlOGkIgyOJUjcd0pC8/QHlVAAe1c91/IcjZ1X+k0yidXHaboJdN7dq1XPUacmhRdtua0U5EZg==} - engines: {node: '>=18.20.0'} - - '@wdio/mocha-framework@10.0.1': - resolution: {integrity: sha512-OZ++XMxtJnCmRZ2EA+ElzMxLXJNo27H9vvm3wWdFTFOFGuu5jWOlb6x090BVeX0c7jXYYjpAu0aXqix+dBItxQ==} + '@wdio/mocha-framework@10.1.0': + resolution: {integrity: sha512-KmdqVqMEc415ish7OnSaOYDr/wMBgxu5jqQ4s3aYwc5zsejeseBoUE5/6EmEBIOZk6nAtij3GkIQ6QeL6TRihw==} engines: {node: '>=22.19.0'} '@wdio/protocols@10.0.2': @@ -3119,26 +3132,26 @@ packages: resolution: {integrity: sha512-wAC9ksdWWv2E3Sj86eNKxB3IUt0gEyw9rgDGAWjk/GWgi6K3e+/n3erGNweI9JMJyC/+RNe0qHgVPQpRJMRVpg==} engines: {node: '>=22.19.0'} - '@wdio/reporter@10.0.1': - resolution: {integrity: sha512-A917SeniucyosspqazR9tGH6t9JaecU5SRP3VzRGyIo0JBEKV6walJU1VBauMH+7n043huzgiQvNJ414Vi8dmQ==} + '@wdio/reporter@10.1.0': + resolution: {integrity: sha512-VijtnGZHgwKFRzWwfGQSTF5WCxtwZLMstTQurKgXFUUh6rJi5ORkfL2515q5/7hbHm9ziMbAeBrfUdiDJCk1dQ==} engines: {node: '>=22.19.0'} - '@wdio/runner@10.0.2': - resolution: {integrity: sha512-+BnWawcWrqQh9RoKhqtnlJ3onRDpahu5BuJx1ESrWvR/+MDdlOx617Mk5Pvw69+vpDpMUdox9XqFMAt3H3hL7Q==} + '@wdio/runner@10.1.0': + resolution: {integrity: sha512-QMy/sgHuysjwLMu2J1qToLomXTIM63bxMlhuGyqaApShQvSc+9/qPoAZvLkwZy40Sn9IvMcaJChaBlF9vL0IJA==} engines: {node: '>=22.19.0'} peerDependencies: - expect-webdriverio: ^8.0.0-0 || ^8.0.0-alpha.3 + expect-webdriverio: ^8.0.0 webdriverio: ^10.0.0-0 || ^10.0.0 - '@wdio/session@10.0.2': - resolution: {integrity: sha512-Ttu2425dZ+r5whjScFRWVkAHAyhg/5nheN/bkTWPf2gluJb4/na2NM7bElOZ4IZFgwFgM5gFkE+9o5WwSVJfSQ==} + '@wdio/session@10.1.0': + resolution: {integrity: sha512-jn25P/1gQqehBEJkq/kUQsT+f5oyM54iNXxhxOjh7wX9BK15RcrgvEYjBhFAk5TrPj1emIkmM4seKqRB/YuKEQ==} engines: {node: '>=22.19.0'} hasBin: true peerDependencies: '@wdio/electron-service': '*' - '@wdio/visual-service': '*' + '@wdio/visual-service': ^10.0.0 || ^11.0.0 appium: ^3.0.0 - expect-webdriverio: '*' + expect-webdriverio: ^8.0.0 tsx: '*' peerDependenciesMeta: '@wdio/electron-service': @@ -3152,28 +3165,28 @@ packages: tsx: optional: true - '@wdio/snapshot@10.0.2': - resolution: {integrity: sha512-eN5DJEr4bQKGOMkA3x4FglMJxe9U91QUGXuChHjFAnzV9OcNQcfVNIsK3uIB3wJ0tnUlzqQ27Dbm8vP+2bA38w==} + '@wdio/snapshot@10.1.0': + resolution: {integrity: sha512-U4IitLvKGltDxtv0NoPPPBZRh3UKpsYms6mMdqGJhIC6riB9zG+faYxv/yk5J1CcPd25FMS0KkPfNpwTeE86rw==} engines: {node: '>=22.19.0'} - '@wdio/spec-reporter@10.0.1': - resolution: {integrity: sha512-zu4PQ7T95KQ/b3/coHQ3RLK5ffQDrpdXkxsfcTXU9Zd+l9K1GzTyJEgXCE7zY1l+INbrBqhM17aUmQvaBZH+JA==} + '@wdio/spec-reporter@10.1.0': + resolution: {integrity: sha512-3Ei+XqpJIsZ2tOwHZDtEw9e5T68X9jqnJ29WDPEUym8sB/XxRYAOUsxOV4EKtxy9LrDZ7yG1vNW/RKa5iNZAOg==} engines: {node: '>=22.19.0'} - '@wdio/types@10.0.1': - resolution: {integrity: sha512-HGP9lAYXCsLAXzugfT4khCh7tYByWOMIxZHCG+tUvgmpwNzi6lfIsxyIlWownXK1wYJUpk6tkDBX/iXwN+q0lg==} + '@wdio/types@10.1.0': + resolution: {integrity: sha512-MxGhIjP74w2xaIhqtzBfrtzDc41qyb9cMqvHgdIDC7MbaREJxpUd/paAg8qmouIph7hBp8MruXap/BPKlVXmVA==} engines: {node: '>=22.19.0'} - '@wdio/utils@10.0.1': - resolution: {integrity: sha512-aYvTtF+7IYsvkFdXdu32Q2vexEaXYK79R1wLTnAXrT2Q7fp0oCDL0UgBx8Jgo5Tn98ZLWx4JlUeZsDRAIkV4Zw==} + '@wdio/utils@10.1.0': + resolution: {integrity: sha512-BABJY+L4JidOD2bfQe3icuRZ0jQeUimTwUEe66I4BHVGWwaa5QBeVU+JZmdNQLjMA9q+Nk385aL96Mb1/PbKYw==} engines: {node: '>=22.19.0'} '@xmldom/xmldom@0.9.12': resolution: {integrity: sha512-5AXjrcMClTryPe9LgZrygpB1lj7s0S9E0+W+AHaVKAVyHanafK86iPSvG5xHVSp/jC+VH1UXu0TAEmY279xH7A==} engines: {node: '>=14.6'} - '@zip.js/zip.js@2.20.0': - resolution: {integrity: sha512-ws8m/tIfbt10L7E9PZj4h0vePKBodxpF13z9JzXdNw1e9ZMFdqnS7ppcK7vXPfN7vwSv2TuRTP7cO2OetdndvA==} + '@zip.js/zip.js@2.24.0': + resolution: {integrity: sha512-WlaVKzdqBK+RF3bdiXZWbdCnvGB6PdO4IHC1mn/2Yfl3bASgqUNegnU3+PNg61iecwoPfUi5BgLUPqBukXpyWw==} engines: {bun: '>=0.7.0', deno: '>=1.0.0', node: '>=18.0.0'} abort-controller@3.0.0: @@ -3206,6 +3219,10 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + agent-base@9.0.0: + resolution: {integrity: sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==} + engines: {node: '>= 20'} + ajv-draft-04@1.0.0: resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} peerDependencies: @@ -3627,9 +3644,9 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - chalk@5.6.2: - resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + chalk@6.0.1: + resolution: {integrity: sha512-/Ce6KNm3vIbWdMlNna6RVIZ/ICQxnJxCicet5LBKK9ZffBkqzDw0xh9EiKSljdRtiIQ1S1z4YgcscUUGzNCWrA==} + engines: {node: '>=22'} change-case@5.4.4: resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} @@ -3744,10 +3761,6 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} - commander@14.0.3: - resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} - engines: {node: '>=20'} - commander@15.0.0: resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} engines: {node: '>=22.12.0'} @@ -3830,8 +3843,8 @@ packages: create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - create-wdio@10.0.2: - resolution: {integrity: sha512-d3Z+a46mOhPVogOzqTatXoI5k+a2cYNpkvhLjbJaiteapxyGALBfM7XQO1po+NTIu1WTaVT0pM1eAoMkw14CNQ==} + create-wdio@10.1.0: + resolution: {integrity: sha512-tFlgNLoSDG1S2U9dpJqkv8tWHuT0cre5kNKGHEhjG6o9hyaTFa6aawO7U5aFxAk5Ts4rV63sNDiGMCoj2cifEw==} engines: {node: '>=22.19.0'} hasBin: true @@ -4048,6 +4061,11 @@ packages: resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} + dotenv@18.0.8: + resolution: {integrity: sha512-2KDeoFoK/zRtcnbunCDlLG5VWVMcyqeQc6iK65o231nfNAcuGrKoqUQfJFUtBI+QlShk5HKIHxwebBtUl3rEfA==} + engines: {node: '>=12'} + hasBin: true + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -4061,20 +4079,23 @@ packages: easy-table@1.2.0: resolution: {integrity: sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==} - edge-paths@3.0.5: - resolution: {integrity: sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==} - engines: {node: '>=14.0.0'} - - edgedriver@7.0.0: - resolution: {integrity: sha512-4sJLhorcBSfzaqMN41q2VI9KVW9Qcpo7CHbUcBUDWeQ7uHiWnRWayV1KZOQr9jllSBOHD2aXzhUWrC2yCt+PRA==} - engines: {node: '>=20.0.0'} + edgedriver@8.0.0: + resolution: {integrity: sha512-h4twAKTFILvpjrxfeN1gslvnggztA6Cgb4iHQdLzEq3TivaHHlf6qEETpCgU7+iw9JIWjcveeckrDlbcY28a/A==} + engines: {node: '>=22.19.0'} hasBin: true + peerDependencies: + '@wdio/logger': ^9.29.1 || ^10.0.0 ejs@3.1.10: resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} engines: {node: '>=0.10.0'} hasBin: true + ejs@7.0.2: + resolution: {integrity: sha512-LcDSEP6Oclb9sTiSyG0MpG0RuKvLDRxCOOt+2sIk+kdk1rMkFU8SRnT0qaNt5zvU0LOV1YXXOvIoZL/sKwabvw==} + engines: {node: '>=0.12.18'} + hasBin: true + electron-to-chromium@1.5.443: resolution: {integrity: sha512-TDJG36L9A3CWWwZ97HKaE+Iz1sW80pNp6sAU0owzCIV3Zc9eVyRqZK8Vz6NKuMIU8WjP0pIkoqCa0VRf/yFD0Q==} @@ -4402,10 +4423,6 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint-visitor-keys@4.2.1: - resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint-visitor-keys@5.0.1: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} @@ -4420,10 +4437,6 @@ packages: jiti: optional: true - espree@10.4.0: - resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - espree@11.2.0: resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} @@ -4466,17 +4479,17 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} + execa@10.2.0: + resolution: {integrity: sha512-j1pFOVxaybMVCTNHSBuISL2KQcDS3KIE1wBmUp4n2X+1FgaQI2ZDJVy9TYxDyMCzYojRIMh9O8X/UoWZtxTJdw==} + engines: {node: '>=22'} + execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} - execa@9.6.1: - resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} - engines: {node: ^18.19.0 || >=20.5.0} - - exit-hook@4.0.0: - resolution: {integrity: sha512-Fqs7ChZm72y40wKjOFXBKg7nJZvQJmewP5/7LtePDdnah/+FH9Hp5sgMujSCMPXlxOAW2//1jrW9pnsY7o20vQ==} - engines: {node: '>=18'} + exit-hook@5.1.0: + resolution: {integrity: sha512-INjr2xyxHo7bhAqf5ong++GZPPnpcuBcaXUKt03yf7Fie9yWD7FapL4teOU0+awQazGs5ucBh7xWs/AD+6nhog==} + engines: {node: '>=20'} exit-x@0.2.2: resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} @@ -4604,10 +4617,6 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - find-up@6.3.0: - resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - fix-dts-default-cjs-exports@1.0.1: resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} @@ -4666,10 +4675,12 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - geckodriver@7.0.0: - resolution: {integrity: sha512-RypjU7cNcyjWK3ruEriCkWMRa9nroCT3y2qwkPynGzKTK1wG0UCWubb4AfVDTXzG9BhzRTwg29DoeK7PCRnK1w==} - engines: {node: '>=20.0.0'} + geckodriver@8.0.0: + resolution: {integrity: sha512-2jGCA6deI5MAjODxmHljPqvaUccGbeeqMUHXlW4k3FNDp4YDpxSI+P5QG+w5KIsnCeuGEfTTNi2euKqHI1eD6Q==} + engines: {node: '>=22.19.0'} hasBin: true + peerDependencies: + '@wdio/logger': ^9.18.0 || ^10.0.0 generator-function@2.0.1: resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} @@ -4848,14 +4859,6 @@ packages: hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - hosted-git-info@7.0.2: - resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} - engines: {node: ^16.14.0 || >=18.0.0} - - hosted-git-info@8.1.0: - resolution: {integrity: sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==} - engines: {node: ^18.17.0 || >=20.5.0} - hosted-git-info@9.0.3: resolution: {integrity: sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==} engines: {node: ^20.17.0 || >=22.9.0} @@ -4892,6 +4895,10 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} + https-proxy-agent@9.1.0: + resolution: {integrity: sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==} + engines: {node: '>= 20'} + human-id@4.2.1: resolution: {integrity: sha512-zPGsiS+dWoTZtZ4AtpA9Y+BdSFSNWvnouNlWNoUFyAM6xHOHmdCvqO3k8AIbdamCOv4gUFUVNPf6rJFfc4UiJw==} hasBin: true @@ -4984,9 +4991,9 @@ packages: resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - inquirer@12.11.1: - resolution: {integrity: sha512-9VF7mrY+3OmsAfjH3yKz/pLbJ5z22E23hENKw3/LNSaA/sAt3v49bDRY+Ygct1xwuKT+U+cBfTzjCPySna69Qw==} - engines: {node: '>=18'} + inquirer@14.2.4: + resolution: {integrity: sha512-xPVejWqfkjG9OxSirMqu3pdzGIGsma68j2S+nEOuuwMbU3pRTHnYs9d8my+1M6OMlqr8XZPwCPonZ2DKMwQDLg==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': 26.6.4 peerDependenciesMeta: @@ -5192,10 +5199,6 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - isexe@4.0.0: - resolution: {integrity: sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==} - engines: {node: '>=20'} - istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -5395,10 +5398,6 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - json-parse-even-better-errors@3.0.2: - resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - json-schema-ref-resolver@3.0.0: resolution: {integrity: sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A==} @@ -5625,10 +5624,6 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - lines-and-columns@2.0.4: - resolution: {integrity: sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - lit-element@4.2.2: resolution: {integrity: sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==} @@ -5665,10 +5660,6 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - locate-path@7.2.0: - resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - lodash.clonedeep@4.5.0: resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} @@ -5875,9 +5866,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - mute-stream@2.0.0: - resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} - engines: {node: ^18.17.0 || >=20.5.0} + mute-stream@3.0.0: + resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} + engines: {node: ^20.17.0 || >=22.9.0} mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -5936,17 +5927,13 @@ packages: engines: {node: '>=10'} hasBin: true + non-error@0.1.0: + resolution: {integrity: sha512-TMB1uHiGsHRGv1uYclfhivcnf0/PdFp2pNqRxXjncaAsjYMoisaQJI+SSZCqRq+VliwRTC8tsMQfmrWjDMhkPQ==} + engines: {node: '>=20'} + normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} - normalize-package-data@6.0.2: - resolution: {integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==} - engines: {node: ^16.14.0 || >=18.0.0} - - normalize-package-data@7.0.1: - resolution: {integrity: sha512-linxNAT6M0ebEYZOx2tO6vBEFsVgnPpv+AVjk0wJHfaUIbq31Jm3T6vvZaarnOeWDh8ShnwXuaAyM7WT3RzErA==} - engines: {node: ^18.17.0 || >=20.5.0} - normalize-package-data@8.0.0: resolution: {integrity: sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ==} engines: {node: ^20.17.0 || >=22.9.0} @@ -6052,10 +6039,6 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - p-limit@4.0.0: - resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -6064,10 +6047,6 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - p-locate@6.0.0: - resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -6097,10 +6076,6 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} - parse-json@7.1.1: - resolution: {integrity: sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==} - engines: {node: '>=16'} - parse-json@8.3.0: resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} engines: {node: '>=18'} @@ -6125,10 +6100,6 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-exists@5.0.0: - resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -6327,6 +6298,15 @@ packages: property-expr@2.0.6: resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==} + proxy-agent-negotiate@1.1.0: + resolution: {integrity: sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==} + engines: {node: '>= 20'} + peerDependencies: + kerberos: ^2.0.0 + peerDependenciesMeta: + kerberos: + optional: true + psl@1.15.0: resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} @@ -6382,10 +6362,6 @@ packages: resolution: {integrity: sha512-Q5hMVBYur/eQNWDdbF4/Wqqr9Bjvtrw2kjGxxBbKLbx8bVCL8gcArjTy8zDUuLGQicftpMuU0riQNcAsbtOVsw==} engines: {node: '>=20'} - read-pkg-up@10.1.0: - resolution: {integrity: sha512-aNtBq4jR8NawpKJQldrQcSW9y/d+KWH4v24HWkHljOZ7H0av+YTGANBzRh9A5pw7v/bLVsLVPpOhJ7gHNVy8lA==} - engines: {node: '>=16'} - read-pkg@10.1.0: resolution: {integrity: sha512-I8g2lArQiP78ll51UeMZojewtYgIRCKCWqZEgOO8c/uefTI+XDXvCSXu3+YNUaTNvZzobrL5+SqHjBrByRRTdg==} engines: {node: '>=20'} @@ -6394,10 +6370,6 @@ packages: resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==} engines: {node: '>=4'} - read-pkg@8.1.0: - resolution: {integrity: sha512-PORM8AgzXeskHO/WEv312k9U03B8K9JSiWF/8N9sUuFjBa+9SF2u6K7VClzXwDXab51jCd8Nd36CNM+zR97ScQ==} - engines: {node: '>=16'} - readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -6540,12 +6512,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - rxjs@7.8.2: - resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - - safaridriver@2.0.0: - resolution: {integrity: sha512-LL7Ufa9p1cltLmw0WGIbM6FFXibWMoM9NjJuS5QFiAAtEnEwkwMxaXy1BRKCBZKSZ+brs9eYd3LHHiJfIgjmZg==} - engines: {node: '>=18.0.0'} + safaridriver@3.0.0: + resolution: {integrity: sha512-NJSsR0tgn5j4fhg7vj4kD5mQ+t2ZRH3GX1jdUYraEjej9j8ZtBXEe4WZh2/89i7S9+GO3cZKWhUisWb7gyjRwA==} + engines: {node: '>=22.19.0'} safe-array-concat@1.1.4: resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} @@ -6632,9 +6601,9 @@ packages: engines: {node: '>=10'} hasBin: true - serialize-error@12.0.0: - resolution: {integrity: sha512-ZYkZLAvKTKQXWuh5XpBw7CdbSzagarX39WyZ2H07CDLC5/KfsRGlIXV8d4+tfqX1M7916mRqR1QfNHSij+c9Pw==} - engines: {node: '>=18'} + serialize-error@13.0.2: + resolution: {integrity: sha512-G+YKwp9I6IvWMe5RlwqxdmTPIcq/G8HK/sU51gdV1XAJznYkRSTB0ph+zB9AfSxG0fx6xrqYA6i9HeIcHFTXow==} + engines: {node: '>=20'} serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} @@ -6986,6 +6955,10 @@ packages: resolution: {integrity: sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==} engines: {node: '>=18'} + test-exclude@8.0.0: + resolution: {integrity: sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ==} + engines: {node: 20 || >=22} + text-decoder@1.2.7: resolution: {integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==} @@ -7141,10 +7114,6 @@ packages: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} - type-fest@3.13.1: - resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} - engines: {node: '>=14.16'} - type-fest@4.26.0: resolution: {integrity: sha512-OduNjVJsFbifKb57UqZ2EMP1i4u64Xwow3NYXUtBbD4vIwJdQd4+xl8YDou1dlm4DVrtwT/7Ky8z8WyCULVfxw==} engines: {node: '>=16'} @@ -7153,6 +7122,10 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} + type-fest@5.10.0: + resolution: {integrity: sha512-NoSdpq/WEiAg5sjmBkmV/hfxv6HJH4NqPNrqjtSO5CwRmpsDfaf4begxW34KdJykH/l1yHtwBWQkCRdoXO8mPA==} + engines: {node: '>=20'} + type-fest@5.8.0: resolution: {integrity: sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA==} engines: {node: '>=20'} @@ -7390,8 +7363,8 @@ packages: vite: optional: true - vite-plugin-istanbul@7.2.1: - resolution: {integrity: sha512-DSPi4ulvYsjnP44sTI5oriNosbM0E6m3uoCxjdxboTtVzxSkFwcDy3/JnSYKebjr+ZToJwVLTms+2CM0rmbbzQ==} + vite-plugin-istanbul@9.0.1: + resolution: {integrity: sha512-zgcdcqa4r3urX+xqhMQG2uLR2s6IdklQW+acBEtLw6fvUWhuvXswYqxjHAZZ5HCfHEgRs7RH7qIZCklTLRsKLg==} peerDependencies: vite: ^8.0.7 @@ -7512,12 +7485,12 @@ packages: wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - webdriver@10.0.2: - resolution: {integrity: sha512-q2eKiapaOyCH2QfVykBjrYznQiL4gjmGakTYVzQqq3Ycqpd2VPOMSkmbxGHFo8+CpO628QwvpxgKvAxA3hpDaA==} + webdriver@10.1.0: + resolution: {integrity: sha512-W3lNUfcjsD5T62U7HackcsfKefrBoUect9PkyObhuByjPFjR+JwmkWAjbFYHlATpZwFZN5d5h28VBanG4BUe4g==} engines: {node: '>=22.19.0'} - webdriverio@10.0.2: - resolution: {integrity: sha512-o+T+DXwsn2e0niAmz9PWUMDwE/8R06euZ4O85faB6fGG9X/uVOom8sloIH+SYc1tI0fjcI34sU9hptrQj9fDdQ==} + webdriverio@10.1.0: + resolution: {integrity: sha512-RDfW0GkHFM/ItdKEw8YvmLgcb5szUlJOKEVUoRgIeeQQ4+a7UMVavC6TVK438wNI32IHu0R1MoMrSW/6DRWYmQ==} engines: {node: '>=22.19.0'} peerDependencies: puppeteer-core: '>=24 <26' @@ -7561,6 +7534,11 @@ packages: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} + which-command@0.1.0: + resolution: {integrity: sha512-XZyoF5/5hZtXitIwzrU4NKK+Wtbb9aB9CezUEw2Q0wlYK8NUYQxC1rRXgNueYLtBAJwXIb+/tFVk4dozciNJMA==} + engines: {node: '>=22'} + hasBin: true + which-typed-array@1.1.21: resolution: {integrity: sha512-zbRA8cVm6io/d5W8uIe2hblzN76/Wm3v/yiythQvr+dpBWeqhPSWIDNj4zOyHi4zKbMK6DN34Xsr9jPHJERAEw==} engines: {node: '>= 0.4'} @@ -7574,11 +7552,6 @@ packages: engines: {node: '>= 8'} hasBin: true - which@6.0.1: - resolution: {integrity: sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==} - engines: {node: ^20.17.0 || >=22.9.0} - hasBin: true - why-is-node-running@3.2.1: resolution: {integrity: sha512-Tb2FUhB4vUsGQlfSquQLYkApkuPAFQXGFzxWKHHumVz2dK+X1RUm/HnID4+TfIGYJ1kTcwOaCk/buYCEJr6YjQ==} engines: {node: '>=20.11'} @@ -7598,10 +7571,6 @@ packages: workerpool@6.5.1: resolution: {integrity: sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==} - wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} - wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -7709,14 +7678,6 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yocto-queue@1.2.2: - resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} - engines: {node: '>=12.20'} - - yoctocolors-cjs@2.1.3: - resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} - engines: {node: '>=18'} - yoctocolors@2.2.0: resolution: {integrity: sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==} engines: {node: '>=18'} @@ -8614,128 +8575,122 @@ snapshots: '@iconify/types': 2.0.0 import-meta-resolve: 4.2.0 - '@inquirer/ansi@1.0.2': {} + '@inquirer/ansi@2.0.9': {} - '@inquirer/checkbox@4.3.2(@types/node@26.6.4)': + '@inquirer/checkbox@5.2.7(@types/node@26.6.4)': dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@26.6.4) - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@26.6.4) - yoctocolors-cjs: 2.1.3 + '@inquirer/ansi': 2.0.9 + '@inquirer/core': 12.0.5(@types/node@26.6.4) + '@inquirer/figures': 2.0.9 + '@inquirer/type': 4.2.0(@types/node@26.6.4) optionalDependencies: '@types/node': 26.6.4 - '@inquirer/confirm@5.1.21(@types/node@26.6.4)': + '@inquirer/confirm@6.3.4(@types/node@26.6.4)': dependencies: - '@inquirer/core': 10.3.2(@types/node@26.6.4) - '@inquirer/type': 3.0.10(@types/node@26.6.4) + '@inquirer/core': 12.0.5(@types/node@26.6.4) + '@inquirer/type': 4.2.0(@types/node@26.6.4) optionalDependencies: '@types/node': 26.6.4 - '@inquirer/core@10.3.2(@types/node@26.6.4)': + '@inquirer/core@12.0.5(@types/node@26.6.4)': dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@26.6.4) + '@inquirer/ansi': 2.0.9 + '@inquirer/figures': 2.0.9 + '@inquirer/type': 4.2.0(@types/node@26.6.4) cli-width: 4.1.0 - mute-stream: 2.0.0 + fast-wrap-ansi: 0.2.2 + mute-stream: 3.0.0 signal-exit: 4.1.0 - wrap-ansi: 6.2.0 - yoctocolors-cjs: 2.1.3 optionalDependencies: '@types/node': 26.6.4 - '@inquirer/editor@4.2.23(@types/node@26.6.4)': + '@inquirer/editor@5.3.5(@types/node@26.6.4)': dependencies: - '@inquirer/core': 10.3.2(@types/node@26.6.4) - '@inquirer/external-editor': 1.0.3(@types/node@26.6.4) - '@inquirer/type': 3.0.10(@types/node@26.6.4) + '@inquirer/core': 12.0.5(@types/node@26.6.4) + '@inquirer/external-editor': 3.0.6(@types/node@26.6.4) + '@inquirer/type': 4.2.0(@types/node@26.6.4) optionalDependencies: '@types/node': 26.6.4 - '@inquirer/expand@4.0.23(@types/node@26.6.4)': + '@inquirer/expand@5.1.7(@types/node@26.6.4)': dependencies: - '@inquirer/core': 10.3.2(@types/node@26.6.4) - '@inquirer/type': 3.0.10(@types/node@26.6.4) - yoctocolors-cjs: 2.1.3 + '@inquirer/core': 12.0.5(@types/node@26.6.4) + '@inquirer/type': 4.2.0(@types/node@26.6.4) optionalDependencies: '@types/node': 26.6.4 - '@inquirer/external-editor@1.0.3(@types/node@26.6.4)': + '@inquirer/external-editor@3.0.6(@types/node@26.6.4)': dependencies: chardet: 2.2.0 iconv-lite: 0.7.3 optionalDependencies: '@types/node': 26.6.4 - '@inquirer/figures@1.0.15': {} + '@inquirer/figures@2.0.9': {} - '@inquirer/input@4.3.1(@types/node@26.6.4)': + '@inquirer/input@5.1.8(@types/node@26.6.4)': dependencies: - '@inquirer/core': 10.3.2(@types/node@26.6.4) - '@inquirer/type': 3.0.10(@types/node@26.6.4) + '@inquirer/core': 12.0.5(@types/node@26.6.4) + '@inquirer/type': 4.2.0(@types/node@26.6.4) optionalDependencies: '@types/node': 26.6.4 - '@inquirer/number@3.0.23(@types/node@26.6.4)': + '@inquirer/number@4.2.5(@types/node@26.6.4)': dependencies: - '@inquirer/core': 10.3.2(@types/node@26.6.4) - '@inquirer/type': 3.0.10(@types/node@26.6.4) + '@inquirer/core': 12.0.5(@types/node@26.6.4) + '@inquirer/type': 4.2.0(@types/node@26.6.4) optionalDependencies: '@types/node': 26.6.4 - '@inquirer/password@4.0.23(@types/node@26.6.4)': + '@inquirer/password@5.2.4(@types/node@26.6.4)': dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@26.6.4) - '@inquirer/type': 3.0.10(@types/node@26.6.4) + '@inquirer/ansi': 2.0.9 + '@inquirer/core': 12.0.5(@types/node@26.6.4) + '@inquirer/type': 4.2.0(@types/node@26.6.4) optionalDependencies: '@types/node': 26.6.4 - '@inquirer/prompts@7.10.1(@types/node@26.6.4)': - dependencies: - '@inquirer/checkbox': 4.3.2(@types/node@26.6.4) - '@inquirer/confirm': 5.1.21(@types/node@26.6.4) - '@inquirer/editor': 4.2.23(@types/node@26.6.4) - '@inquirer/expand': 4.0.23(@types/node@26.6.4) - '@inquirer/input': 4.3.1(@types/node@26.6.4) - '@inquirer/number': 3.0.23(@types/node@26.6.4) - '@inquirer/password': 4.0.23(@types/node@26.6.4) - '@inquirer/rawlist': 4.1.11(@types/node@26.6.4) - '@inquirer/search': 3.2.2(@types/node@26.6.4) - '@inquirer/select': 4.4.2(@types/node@26.6.4) + '@inquirer/prompts@8.7.4(@types/node@26.6.4)': + dependencies: + '@inquirer/checkbox': 5.2.7(@types/node@26.6.4) + '@inquirer/confirm': 6.3.4(@types/node@26.6.4) + '@inquirer/editor': 5.3.5(@types/node@26.6.4) + '@inquirer/expand': 5.1.7(@types/node@26.6.4) + '@inquirer/input': 5.1.8(@types/node@26.6.4) + '@inquirer/number': 4.2.5(@types/node@26.6.4) + '@inquirer/password': 5.2.4(@types/node@26.6.4) + '@inquirer/rawlist': 5.3.7(@types/node@26.6.4) + '@inquirer/search': 4.3.5(@types/node@26.6.4) + '@inquirer/select': 5.2.7(@types/node@26.6.4) optionalDependencies: '@types/node': 26.6.4 - '@inquirer/rawlist@4.1.11(@types/node@26.6.4)': + '@inquirer/rawlist@5.3.7(@types/node@26.6.4)': dependencies: - '@inquirer/core': 10.3.2(@types/node@26.6.4) - '@inquirer/type': 3.0.10(@types/node@26.6.4) - yoctocolors-cjs: 2.1.3 + '@inquirer/core': 12.0.5(@types/node@26.6.4) + '@inquirer/type': 4.2.0(@types/node@26.6.4) optionalDependencies: '@types/node': 26.6.4 - '@inquirer/search@3.2.2(@types/node@26.6.4)': + '@inquirer/search@4.3.5(@types/node@26.6.4)': dependencies: - '@inquirer/core': 10.3.2(@types/node@26.6.4) - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@26.6.4) - yoctocolors-cjs: 2.1.3 + '@inquirer/core': 12.0.5(@types/node@26.6.4) + '@inquirer/figures': 2.0.9 + '@inquirer/type': 4.2.0(@types/node@26.6.4) optionalDependencies: '@types/node': 26.6.4 - '@inquirer/select@4.4.2(@types/node@26.6.4)': + '@inquirer/select@5.2.7(@types/node@26.6.4)': dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@26.6.4) - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@26.6.4) - yoctocolors-cjs: 2.1.3 + '@inquirer/ansi': 2.0.9 + '@inquirer/core': 12.0.5(@types/node@26.6.4) + '@inquirer/figures': 2.0.9 + '@inquirer/type': 4.2.0(@types/node@26.6.4) optionalDependencies: '@types/node': 26.6.4 - '@inquirer/type@3.0.10(@types/node@26.6.4)': + '@inquirer/type@4.2.0(@types/node@26.6.4)': optionalDependencies: '@types/node': 26.6.4 @@ -9654,10 +9609,6 @@ snapshots: dependencies: '@babel/types': 7.29.8 - '@types/babel__generator@7.6.8': - dependencies: - '@babel/types': 7.29.8 - '@types/babel__template@7.4.4': dependencies: '@babel/parser': 7.29.9 @@ -9713,7 +9664,7 @@ snapshots: '@types/shell-quote@1.7.5': {} - '@types/sinonjs__fake-timers@8.1.5': {} + '@types/sinonjs__fake-timers@15.0.1': {} '@types/split2@4.2.3': dependencies: @@ -9727,8 +9678,6 @@ snapshots: '@types/whatwg-mimetype@3.0.2': {} - '@types/which@2.0.2': {} - '@types/ws@8.18.2': dependencies: '@types/node': 26.6.4 @@ -9964,11 +9913,11 @@ snapshots: path-browserify: 1.0.1 vscode-uri: 3.2.0 - '@wdio/allure-reporter@10.0.1': + '@wdio/allure-reporter@10.1.0': dependencies: '@types/node': 26.6.4 - '@wdio/reporter': 10.0.1 - '@wdio/types': 10.0.1 + '@wdio/reporter': 10.1.0 + '@wdio/types': 10.1.0 allure-js-commons: 3.13.0 csv-stringify: 6.9.0 html-entities: 2.6.0 @@ -9976,21 +9925,21 @@ snapshots: transitivePeerDependencies: - allure-playwright - '@wdio/browser-runner@10.0.2(@types/node@26.6.4)(esbuild@0.28.2)(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(jiti@2.7.0)(magicast@0.5.5)(rollup@4.64.0)(tsx@4.23.15)(webdriver@10.0.2(yauzl@2.10.0))(webdriverio@10.0.2(yauzl@2.10.0))(yaml@2.9.1)(yauzl@2.10.0)': + '@wdio/browser-runner@10.1.0(@types/node@26.6.4)(esbuild@0.28.2)(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(jiti@2.7.0)(magicast@0.5.5)(rollup@4.64.0)(tsx@4.23.15)(webdriver@10.1.0(yauzl@2.10.0))(webdriverio@10.1.0(yauzl@2.10.0))(yaml@2.9.1)(yauzl@2.10.0)': dependencies: '@originjs/vite-plugin-commonjs': 1.0.3 '@vitest/spy': 5.0.3 - '@wdio/globals': 10.0.2(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(webdriverio@10.0.2(yauzl@2.10.0)) - '@wdio/local-runner': 10.0.2(tsx@4.23.15)(webdriverio@10.0.2(yauzl@2.10.0))(yauzl@2.10.0) - '@wdio/logger': 10.0.0 - '@wdio/mocha-framework': 10.0.1(yauzl@2.10.0) + '@wdio/globals': 10.1.0(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(webdriverio@10.1.0(yauzl@2.10.0)) + '@wdio/local-runner': 10.1.0(tsx@4.23.15)(webdriverio@10.1.0(yauzl@2.10.0))(yauzl@2.10.0) + '@wdio/logger': 10.1.0 + '@wdio/mocha-framework': 10.1.0(yauzl@2.10.0) '@wdio/protocols': 10.0.2 - '@wdio/runner': 10.0.2(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(tsx@4.23.15)(webdriverio@10.0.2(yauzl@2.10.0))(yauzl@2.10.0) - '@wdio/types': 10.0.1 - '@wdio/utils': 10.0.1(yauzl@2.10.0) + '@wdio/runner': 10.1.0(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(tsx@4.23.15)(webdriverio@10.1.0(yauzl@2.10.0))(yauzl@2.10.0) + '@wdio/types': 10.1.0 + '@wdio/utils': 10.1.0(yauzl@2.10.0) deepmerge-ts: 8.0.2 expect: 30.5.2 - expect-webdriverio: 8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)) + expect-webdriverio: 8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)) get-port: 7.2.0 import-meta-resolve: 4.2.0 istanbul-lib-coverage: 3.2.2 @@ -10003,10 +9952,10 @@ snapshots: safe-stringify: 1.3.0 source-map-support: 0.5.21 vite: 8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1) - vite-plugin-istanbul: 7.2.1(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + vite-plugin-istanbul: 9.0.1(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) vite-plugin-top-level-await: 1.6.0(rollup@4.64.0)(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) - webdriver: 10.0.2(yauzl@2.10.0) - webdriverio: 10.0.2(yauzl@2.10.0) + webdriver: 10.1.0(yauzl@2.10.0) + webdriverio: 10.1.0(yauzl@2.10.0) optionalDependencies: '@nuxt/kit': 3.21.11(magicast@0.5.5) '@stencil/core': 4.45.1 @@ -10023,6 +9972,7 @@ snapshots: - bufferutil - esbuild - jiti + - kerberos - less - magicast - proxy-agent @@ -10040,28 +9990,28 @@ snapshots: - yaml - yauzl - '@wdio/cli@10.0.2(@types/node@26.6.4)(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(yauzl@2.10.0)': + '@wdio/cli@10.1.0(@types/node@26.6.4)(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(yauzl@2.10.0)': dependencies: '@vitest/snapshot': 5.0.3 - '@wdio/config': 10.0.1(yauzl@2.10.0) - '@wdio/globals': 10.0.2(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(webdriverio@10.0.2(yauzl@2.10.0)) - '@wdio/logger': 10.0.0 + '@wdio/config': 10.1.0(yauzl@2.10.0) + '@wdio/globals': 10.1.0(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(webdriverio@10.1.0(yauzl@2.10.0)) + '@wdio/logger': 10.1.0 '@wdio/protocols': 10.0.2 - '@wdio/session': 10.0.2(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(tsx@4.23.15)(yauzl@2.10.0) - '@wdio/types': 10.0.1 - '@wdio/utils': 10.0.1(yauzl@2.10.0) + '@wdio/session': 10.1.0(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(tsx@4.23.15)(yauzl@2.10.0) + '@wdio/types': 10.1.0 + '@wdio/utils': 10.1.0(yauzl@2.10.0) async-exit-hook: 2.0.1 - chalk: 5.6.2 - chokidar: 4.0.3 - create-wdio: 10.0.2(@types/node@26.6.4) - dotenv: 17.4.2 + chalk: 6.0.1 + chokidar: 5.0.0 + create-wdio: 10.1.0(@types/node@26.6.4) + dotenv: 18.0.8 import-meta-resolve: 4.2.0 lodash.flattendeep: 4.4.0 lodash.pickby: 4.6.0 lodash.union: 4.6.0 - read-pkg-up: 10.1.0 + read-package-up: 12.0.0 tsx: 4.23.15 - webdriverio: 10.0.2(yauzl@2.10.0) + webdriverio: 10.1.0(yauzl@2.10.0) yargs: 18.2.0 transitivePeerDependencies: - '@types/node' @@ -10072,6 +10022,7 @@ snapshots: - bare-buffer - bufferutil - expect-webdriverio + - kerberos - proxy-agent - puppeteer-core - react-native-b4a @@ -10079,13 +10030,13 @@ snapshots: - utf-8-validate - yauzl - '@wdio/config@10.0.1(yauzl@2.10.0)': + '@wdio/config@10.1.0(yauzl@2.10.0)': dependencies: - '@wdio/logger': 10.0.0 - '@wdio/types': 10.0.1 - '@wdio/utils': 10.0.1(yauzl@2.10.0) + '@wdio/logger': 10.1.0 + '@wdio/types': 10.1.0 + '@wdio/utils': 10.1.0(yauzl@2.10.0) deepmerge-ts: 8.0.2 - glob: 10.5.0 + glob: 13.0.6 import-meta-resolve: 4.2.0 jiti: 2.7.0 transitivePeerDependencies: @@ -10093,16 +10044,16 @@ snapshots: - supports-color - yauzl - '@wdio/cucumber-framework@10.0.1(yauzl@2.10.0)': + '@wdio/cucumber-framework@10.1.0(yauzl@2.10.0)': dependencies: '@cucumber/cucumber': 13.2.1 '@cucumber/gherkin': 42.0.1 '@cucumber/messages': 34.2.1 '@types/node': 26.6.4 - '@wdio/logger': 10.0.0 - '@wdio/types': 10.0.1 - '@wdio/utils': 10.0.1(yauzl@2.10.0) - glob: 10.5.0 + '@wdio/logger': 10.1.0 + '@wdio/types': 10.1.0 + '@wdio/utils': 10.1.0(yauzl@2.10.0) + glob: 13.0.6 import-meta-resolve: 4.2.0 is-glob: 4.0.3 transitivePeerDependencies: @@ -10110,33 +10061,33 @@ snapshots: - supports-color - yauzl - '@wdio/display-server@10.0.1': + '@wdio/display-server@10.1.0': dependencies: - '@wdio/logger': 10.0.0 - '@wdio/types': 10.0.1 + '@wdio/logger': 10.1.0 + '@wdio/types': 10.1.0 - '@wdio/dot-reporter@10.0.1': + '@wdio/dot-reporter@10.1.0': dependencies: - '@wdio/reporter': 10.0.1 - '@wdio/types': 10.0.1 - chalk: 5.6.2 + '@wdio/reporter': 10.1.0 + '@wdio/types': 10.1.0 + chalk: 6.0.1 - '@wdio/globals@10.0.2(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(webdriverio@10.0.2(yauzl@2.10.0))': + '@wdio/globals@10.1.0(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(webdriverio@10.1.0(yauzl@2.10.0))': dependencies: - expect-webdriverio: 8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)) - webdriverio: 10.0.2(yauzl@2.10.0) + expect-webdriverio: 8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)) + webdriverio: 10.1.0(yauzl@2.10.0) - '@wdio/local-runner@10.0.2(tsx@4.23.15)(webdriverio@10.0.2(yauzl@2.10.0))(yauzl@2.10.0)': + '@wdio/local-runner@10.1.0(tsx@4.23.15)(webdriverio@10.1.0(yauzl@2.10.0))(yauzl@2.10.0)': dependencies: '@types/node': 26.6.4 '@types/split2': 4.2.3 - '@wdio/display-server': 10.0.1 - '@wdio/logger': 10.0.0 + '@wdio/display-server': 10.1.0 + '@wdio/logger': 10.1.0 '@wdio/repl': 10.0.0 - '@wdio/runner': 10.0.2(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(tsx@4.23.15)(webdriverio@10.0.2(yauzl@2.10.0))(yauzl@2.10.0) - '@wdio/types': 10.0.1 - exit-hook: 4.0.0 - expect-webdriverio: 8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)) + '@wdio/runner': 10.1.0(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(tsx@4.23.15)(webdriverio@10.1.0(yauzl@2.10.0))(yauzl@2.10.0) + '@wdio/types': 10.1.0 + exit-hook: 5.1.0 + expect-webdriverio: 8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)) split2: 4.2.0 stream-buffers: 3.0.3 transitivePeerDependencies: @@ -10146,6 +10097,7 @@ snapshots: - bare-abort-controller - bare-buffer - bufferutil + - kerberos - proxy-agent - puppeteer-core - react-native-b4a @@ -10155,29 +10107,21 @@ snapshots: - webdriverio - yauzl - '@wdio/logger@10.0.0': - dependencies: - chalk: 5.6.2 - loglevel: 1.9.2 - loglevel-plugin-prefix: 0.8.4 - safe-regex2: 5.1.1 - strip-ansi: 7.2.0 - - '@wdio/logger@9.29.1': + '@wdio/logger@10.1.0': dependencies: - chalk: 5.6.2 + chalk: 6.0.1 loglevel: 1.9.2 loglevel-plugin-prefix: 0.8.4 safe-regex2: 5.1.1 strip-ansi: 7.2.0 - '@wdio/mocha-framework@10.0.1(yauzl@2.10.0)': + '@wdio/mocha-framework@10.1.0(yauzl@2.10.0)': dependencies: '@types/mocha': 10.0.10 '@types/node': 26.6.4 - '@wdio/logger': 10.0.0 - '@wdio/types': 10.0.1 - '@wdio/utils': 10.0.1(yauzl@2.10.0) + '@wdio/logger': 10.1.0 + '@wdio/types': 10.1.0 + '@wdio/utils': 10.1.0(yauzl@2.10.0) mocha: 12.0.3 transitivePeerDependencies: - proxy-agent @@ -10190,27 +10134,27 @@ snapshots: dependencies: '@types/node': 26.6.4 - '@wdio/reporter@10.0.1': + '@wdio/reporter@10.1.0': dependencies: '@types/node': 26.6.4 - '@wdio/types': 10.0.1 - diff: 8.0.4 + '@wdio/types': 10.1.0 + diff: 9.0.0 object-inspect: 1.13.4 - '@wdio/runner@10.0.2(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(tsx@4.23.15)(webdriverio@10.0.2(yauzl@2.10.0))(yauzl@2.10.0)': + '@wdio/runner@10.1.0(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(tsx@4.23.15)(webdriverio@10.1.0(yauzl@2.10.0))(yauzl@2.10.0)': dependencies: '@types/node': 26.6.4 - '@wdio/config': 10.0.1(yauzl@2.10.0) - '@wdio/dot-reporter': 10.0.1 - '@wdio/globals': 10.0.2(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(webdriverio@10.0.2(yauzl@2.10.0)) - '@wdio/logger': 10.0.0 - '@wdio/session': 10.0.2(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(tsx@4.23.15)(yauzl@2.10.0) - '@wdio/types': 10.0.1 - '@wdio/utils': 10.0.1(yauzl@2.10.0) + '@wdio/config': 10.1.0(yauzl@2.10.0) + '@wdio/dot-reporter': 10.1.0 + '@wdio/globals': 10.1.0(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(webdriverio@10.1.0(yauzl@2.10.0)) + '@wdio/logger': 10.1.0 + '@wdio/session': 10.1.0(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(tsx@4.23.15)(yauzl@2.10.0) + '@wdio/types': 10.1.0 + '@wdio/utils': 10.1.0(yauzl@2.10.0) deepmerge-ts: 8.0.2 - expect-webdriverio: 8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)) - webdriver: 10.0.2(yauzl@2.10.0) - webdriverio: 10.0.2(yauzl@2.10.0) + expect-webdriverio: 8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)) + webdriver: 10.1.0(yauzl@2.10.0) + webdriverio: 10.1.0(yauzl@2.10.0) transitivePeerDependencies: - '@wdio/electron-service' - '@wdio/visual-service' @@ -10218,6 +10162,7 @@ snapshots: - bare-abort-controller - bare-buffer - bufferutil + - kerberos - proxy-agent - puppeteer-core - react-native-b4a @@ -10226,29 +10171,30 @@ snapshots: - utf-8-validate - yauzl - '@wdio/session@10.0.2(expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)))(tsx@4.23.15)(yauzl@2.10.0)': + '@wdio/session@10.1.0(expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)))(tsx@4.23.15)(yauzl@2.10.0)': dependencies: '@types/node': 26.6.4 - '@wdio/config': 10.0.1(yauzl@2.10.0) - '@wdio/display-server': 10.0.1 - '@wdio/logger': 10.0.0 - '@wdio/snapshot': 10.0.2(yauzl@2.10.0) - '@wdio/types': 10.0.1 - '@wdio/utils': 10.0.1(yauzl@2.10.0) + '@wdio/config': 10.1.0(yauzl@2.10.0) + '@wdio/display-server': 10.1.0 + '@wdio/logger': 10.1.0 + '@wdio/snapshot': 10.1.0(yauzl@2.10.0) + '@wdio/types': 10.1.0 + '@wdio/utils': 10.1.0(yauzl@2.10.0) acorn: 8.18.0 get-port: 7.2.0 image-size: 2.0.4 picomatch: 4.0.7 semver: 7.8.5 - webdriverio: 10.0.2(yauzl@2.10.0) + webdriverio: 10.1.0(yauzl@2.10.0) yargs: 18.2.0 optionalDependencies: - expect-webdriverio: 8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)) + expect-webdriverio: 8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)) tsx: 4.23.15 transitivePeerDependencies: - bare-abort-controller - bare-buffer - bufferutil + - kerberos - proxy-agent - puppeteer-core - react-native-b4a @@ -10256,14 +10202,15 @@ snapshots: - utf-8-validate - yauzl - '@wdio/snapshot@10.0.2(yauzl@2.10.0)': + '@wdio/snapshot@10.1.0(yauzl@2.10.0)': dependencies: - '@wdio/utils': 10.0.1(yauzl@2.10.0) - webdriverio: 10.0.2(yauzl@2.10.0) + '@wdio/utils': 10.1.0(yauzl@2.10.0) + webdriverio: 10.1.0(yauzl@2.10.0) transitivePeerDependencies: - bare-abort-controller - bare-buffer - bufferutil + - kerberos - proxy-agent - puppeteer-core - react-native-b4a @@ -10271,35 +10218,35 @@ snapshots: - utf-8-validate - yauzl - '@wdio/spec-reporter@10.0.1': + '@wdio/spec-reporter@10.1.0': dependencies: - '@wdio/reporter': 10.0.1 - '@wdio/types': 10.0.1 - chalk: 5.6.2 + '@wdio/reporter': 10.1.0 + '@wdio/types': 10.1.0 + chalk: 6.0.1 easy-table: 1.2.0 pretty-ms: 9.3.1 - '@wdio/types@10.0.1': + '@wdio/types@10.1.0': dependencies: '@types/node': 26.6.4 - '@wdio/utils@10.0.1(yauzl@2.10.0)': + '@wdio/utils@10.1.0(yauzl@2.10.0)': dependencies: '@puppeteer/browsers': 3.2.4(yauzl@2.10.0) '@types/split2': 4.2.3 - '@wdio/logger': 10.0.0 - '@wdio/types': 10.0.1 + '@wdio/logger': 10.1.0 + '@wdio/types': 10.1.0 aria-query: 5.3.2 decamelize: 6.0.1 deepmerge-ts: 8.0.2 - edgedriver: 7.0.0 + edgedriver: 8.0.0(@wdio/logger@10.1.0) electron-to-chromium: 1.5.443 - geckodriver: 7.0.0 + geckodriver: 8.0.0(@wdio/logger@10.1.0) get-port: 7.2.0 import-meta-resolve: 4.2.0 locate-app: 2.5.0 mitt: 3.0.1 - safaridriver: 2.0.0 + safaridriver: 3.0.0 split2: 4.2.0 wait-port: 1.1.0 transitivePeerDependencies: @@ -10309,7 +10256,7 @@ snapshots: '@xmldom/xmldom@0.9.12': {} - '@zip.js/zip.js@2.20.0': {} + '@zip.js/zip.js@2.24.0': {} abort-controller@3.0.0: dependencies: @@ -10331,6 +10278,8 @@ snapshots: agent-base@7.1.4: {} + agent-base@9.0.0: {} + ajv-draft-04@1.0.0(ajv@8.20.0): optionalDependencies: ajv: 8.20.0 @@ -10824,7 +10773,7 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 - chalk@5.6.2: {} + chalk@6.0.1: {} change-case@5.4.4: {} @@ -10958,8 +10907,6 @@ snapshots: dependencies: delayed-stream: 1.0.0 - commander@14.0.3: {} - commander@15.0.0: {} commander@4.1.1: {} @@ -11029,19 +10976,19 @@ snapshots: create-require@1.1.1: {} - create-wdio@10.0.2(@types/node@26.6.4): + create-wdio@10.1.0(@types/node@26.6.4): dependencies: - chalk: 5.6.2 - commander: 14.0.3 + chalk: 6.0.1 + commander: 15.0.0 cross-spawn: 7.0.6 - ejs: 3.1.10 - execa: 9.6.1 + ejs: 7.0.2 + execa: 10.2.0 import-meta-resolve: 4.2.0 - inquirer: 12.11.1(@types/node@26.6.4) - normalize-package-data: 7.0.1 - read-pkg-up: 10.1.0 + inquirer: 14.2.4(@types/node@26.6.4) + normalize-package-data: 8.0.0 + read-package-up: 12.0.0 semver: 7.8.5 - type-fest: 4.41.0 + type-fest: 5.10.0 yargs: 18.2.0 transitivePeerDependencies: - '@types/node' @@ -11256,7 +11203,10 @@ snapshots: dotenv@16.3.1: {} - dotenv@17.4.2: {} + dotenv@17.4.2: + optional: true + + dotenv@18.0.8: {} dunder-proto@1.0.1: dependencies: @@ -11279,27 +11229,19 @@ snapshots: optionalDependencies: wcwidth: 1.0.1 - edge-paths@3.0.5: + edgedriver@8.0.0(@wdio/logger@10.1.0): dependencies: - '@types/which': 2.0.2 - which: 2.0.2 - - edgedriver@7.0.0: - dependencies: - '@wdio/logger': 9.29.1 - '@zip.js/zip.js': 2.20.0 + '@wdio/logger': 10.1.0 + '@zip.js/zip.js': 2.24.0 decamelize: 6.0.1 - edge-paths: 3.0.5 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - which: 6.0.1 - transitivePeerDependencies: - - supports-color + undici: 8.11.2 ejs@3.1.10: dependencies: jake: 10.9.4 + ejs@7.0.2: {} + electron-to-chromium@1.5.443: {} emittery@0.13.1: {} @@ -11697,8 +11639,6 @@ snapshots: eslint-visitor-keys@3.4.3: {} - eslint-visitor-keys@4.2.1: {} - eslint-visitor-keys@5.0.1: {} eslint@10.12.0(jiti@2.7.0): @@ -11738,12 +11678,6 @@ snapshots: transitivePeerDependencies: - supports-color - espree@10.4.0: - dependencies: - acorn: 8.18.0 - acorn-jsx: 5.3.2(acorn@8.18.0) - eslint-visitor-keys: 4.2.1 - espree@11.2.0: dependencies: acorn: 8.18.0 @@ -11780,22 +11714,9 @@ snapshots: events@3.3.0: {} - execa@5.1.1: - dependencies: - cross-spawn: 7.0.6 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - - execa@9.6.1: + execa@10.2.0: dependencies: '@sindresorhus/merge-streams': 4.0.0 - cross-spawn: 7.0.6 figures: 6.1.0 get-stream: 9.0.1 human-signals: 8.0.1 @@ -11805,21 +11726,34 @@ snapshots: pretty-ms: 9.3.1 signal-exit: 4.1.0 strip-final-newline: 4.0.0 + which-command: 0.1.0 yoctocolors: 2.2.0 - exit-hook@4.0.0: {} + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + exit-hook@5.1.0: {} exit-x@0.2.2: {} expect-type@1.4.0: {} - expect-webdriverio@8.0.0(@wdio/types@10.0.1)(webdriverio@10.0.2(yauzl@2.10.0)): + expect-webdriverio@8.0.0(@wdio/types@10.1.0)(webdriverio@10.1.0(yauzl@2.10.0)): dependencies: '@vitest/snapshot': 5.0.3 - '@wdio/types': 10.0.1 + '@wdio/types': 10.1.0 expect: 30.5.2 jest-matcher-utils: 30.5.2 - webdriverio: 10.0.2(yauzl@2.10.0) + webdriverio: 10.1.0(yauzl@2.10.0) expect@30.5.2: dependencies: @@ -11954,11 +11888,6 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - find-up@6.3.0: - dependencies: - locate-path: 7.2.0 - path-exists: 5.0.0 - fix-dts-default-cjs-exports@1.0.1: dependencies: magic-string: 0.30.21 @@ -12025,16 +11954,13 @@ snapshots: functions-have-names@1.2.3: {} - geckodriver@7.0.0: + geckodriver@8.0.0(@wdio/logger@10.1.0): dependencies: - '@wdio/logger': 9.29.1 - '@zip.js/zip.js': 2.20.0 + '@wdio/logger': 10.1.0 + '@zip.js/zip.js': 2.24.0 decamelize: 6.0.1 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 modern-tar: 0.8.5 - transitivePeerDependencies: - - supports-color + undici: 8.11.2 generator-function@2.0.1: {} @@ -12220,14 +12146,6 @@ snapshots: hosted-git-info@2.8.9: {} - hosted-git-info@7.0.2: - dependencies: - lru-cache: 10.4.3 - - hosted-git-info@8.1.0: - dependencies: - lru-cache: 10.4.3 - hosted-git-info@9.0.3: dependencies: lru-cache: 11.5.3 @@ -12273,6 +12191,15 @@ snapshots: transitivePeerDependencies: - supports-color + https-proxy-agent@9.1.0: + dependencies: + agent-base: 9.0.0 + debug: 4.4.3 + proxy-agent-negotiate: 1.1.0 + transitivePeerDependencies: + - kerberos + - supports-color + human-id@4.2.1: {} human-signals@2.1.0: {} @@ -12337,15 +12264,14 @@ snapshots: ini@4.1.1: {} - inquirer@12.11.1(@types/node@26.6.4): + inquirer@14.2.4(@types/node@26.6.4): dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@26.6.4) - '@inquirer/prompts': 7.10.1(@types/node@26.6.4) - '@inquirer/type': 3.0.10(@types/node@26.6.4) - mute-stream: 2.0.0 + '@inquirer/ansi': 2.0.9 + '@inquirer/core': 12.0.5(@types/node@26.6.4) + '@inquirer/prompts': 8.7.4(@types/node@26.6.4) + '@inquirer/type': 4.2.0(@types/node@26.6.4) + mute-stream: 3.0.0 run-async: 4.0.6 - rxjs: 7.8.2 optionalDependencies: '@types/node': 26.6.4 @@ -12527,8 +12453,6 @@ snapshots: isexe@2.0.0: {} - isexe@4.0.0: {} - istanbul-lib-coverage@3.2.2: {} istanbul-lib-instrument@6.0.3: @@ -12941,8 +12865,6 @@ snapshots: json-parse-even-better-errors@2.3.1: {} - json-parse-even-better-errors@3.0.2: {} - json-schema-ref-resolver@3.0.0: dependencies: dequal: 2.0.3 @@ -13120,8 +13042,6 @@ snapshots: lines-and-columns@1.2.4: {} - lines-and-columns@2.0.4: {} - lit-element@4.2.2: dependencies: '@lit-labs/ssr-dom-shim': 1.6.0 @@ -13169,10 +13089,6 @@ snapshots: dependencies: p-locate: 5.0.0 - locate-path@7.2.0: - dependencies: - p-locate: 6.0.0 - lodash.clonedeep@4.5.0: {} lodash.defaults@4.2.0: {} @@ -13379,7 +13295,7 @@ snapshots: ms@2.1.3: {} - mute-stream@2.0.0: {} + mute-stream@3.0.0: {} mz@2.7.0: dependencies: @@ -13469,6 +13385,8 @@ snapshots: touch: 3.1.1 undefsafe: 2.0.5 + non-error@0.1.0: {} + normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 @@ -13476,18 +13394,6 @@ snapshots: semver: 5.7.2 validate-npm-package-license: 3.0.4 - normalize-package-data@6.0.2: - dependencies: - hosted-git-info: 7.0.2 - semver: 7.8.5 - validate-npm-package-license: 3.0.4 - - normalize-package-data@7.0.1: - dependencies: - hosted-git-info: 8.1.0 - semver: 7.8.5 - validate-npm-package-license: 3.0.4 - normalize-package-data@8.0.0: dependencies: hosted-git-info: 9.0.3 @@ -13626,10 +13532,6 @@ snapshots: dependencies: yocto-queue: 0.1.0 - p-limit@4.0.0: - dependencies: - yocto-queue: 1.2.2 - p-locate@4.1.0: dependencies: p-limit: 2.3.0 @@ -13638,10 +13540,6 @@ snapshots: dependencies: p-limit: 3.1.0 - p-locate@6.0.0: - dependencies: - p-limit: 4.0.0 - p-try@2.2.0: {} package-json-from-dist@1.0.1: {} @@ -13670,14 +13568,6 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - parse-json@7.1.1: - dependencies: - '@babel/code-frame': 7.29.7 - error-ex: 1.3.4 - json-parse-even-better-errors: 3.0.2 - lines-and-columns: 2.0.4 - type-fest: 3.13.1 - parse-json@8.3.0: dependencies: '@babel/code-frame': 7.29.7 @@ -13703,8 +13593,6 @@ snapshots: path-exists@4.0.0: {} - path-exists@5.0.0: {} - path-is-absolute@1.0.1: {} path-key@2.0.1: {} @@ -13884,6 +13772,8 @@ snapshots: property-expr@2.0.6: {} + proxy-agent-negotiate@1.1.0: {} + psl@1.15.0: dependencies: punycode: 2.3.1 @@ -13932,12 +13822,6 @@ snapshots: read-pkg: 10.1.0 type-fest: 5.8.0 - read-pkg-up@10.1.0: - dependencies: - find-up: 6.3.0 - read-pkg: 8.1.0 - type-fest: 4.41.0 - read-pkg@10.1.0: dependencies: '@types/normalize-package-data': 2.4.4 @@ -13952,13 +13836,6 @@ snapshots: normalize-package-data: 2.5.0 path-type: 3.0.0 - read-pkg@8.1.0: - dependencies: - '@types/normalize-package-data': 2.4.4 - normalize-package-data: 6.0.2 - parse-json: 7.1.1 - type-fest: 4.41.0 - readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -14151,11 +14028,7 @@ snapshots: dependencies: queue-microtask: 1.2.3 - rxjs@7.8.2: - dependencies: - tslib: 2.8.1 - - safaridriver@2.0.0: {} + safaridriver@3.0.0: {} safe-array-concat@1.1.4: dependencies: @@ -14239,9 +14112,10 @@ snapshots: semver@7.8.5: {} - serialize-error@12.0.0: + serialize-error@13.0.2: dependencies: - type-fest: 4.41.0 + non-error: 0.1.0 + type-fest: 5.8.0 serialize-javascript@6.0.2: dependencies: @@ -14648,6 +14522,12 @@ snapshots: glob: 10.5.0 minimatch: 10.2.6 + test-exclude@8.0.0: + dependencies: + '@istanbuljs/schema': 0.1.6 + glob: 13.0.6 + minimatch: 10.2.6 + text-decoder@1.2.7: dependencies: b4a: 1.9.0 @@ -14802,12 +14682,14 @@ snapshots: type-fest@2.19.0: {} - type-fest@3.13.1: {} - type-fest@4.26.0: {} type-fest@4.41.0: {} + type-fest@5.10.0: + dependencies: + tagged-tag: 1.0.0 + type-fest@5.8.0: dependencies: tagged-tag: 1.0.0 @@ -15060,16 +14942,16 @@ snapshots: - typescript - webpack - vite-plugin-istanbul@7.2.1(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)): + vite-plugin-istanbul@9.0.1(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)): dependencies: '@babel/generator': 7.29.8 '@istanbuljs/load-nyc-config': 1.1.0 - '@types/babel__generator': 7.6.8 - espree: 10.4.0 + '@types/babel__generator': 7.27.0 + espree: 11.2.0 istanbul-lib-instrument: 6.0.3 picocolors: 1.1.1 source-map: 0.7.6 - test-exclude: 7.0.2 + test-exclude: 8.0.0 vite: 8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1) transitivePeerDependencies: - supports-color @@ -15151,36 +15033,37 @@ snapshots: dependencies: defaults: 1.0.4 - webdriver@10.0.2(yauzl@2.10.0): + webdriver@10.1.0(yauzl@2.10.0): dependencies: '@types/node': 26.6.4 '@types/ws': 8.18.2 - '@wdio/config': 10.0.1(yauzl@2.10.0) - '@wdio/logger': 10.0.0 + '@wdio/config': 10.1.0(yauzl@2.10.0) + '@wdio/logger': 10.1.0 '@wdio/protocols': 10.0.2 - '@wdio/types': 10.0.1 - '@wdio/utils': 10.0.1(yauzl@2.10.0) + '@wdio/types': 10.1.0 + '@wdio/utils': 10.1.0(yauzl@2.10.0) deepmerge-ts: 8.0.2 - https-proxy-agent: 7.0.6 + https-proxy-agent: 9.1.0 undici: 8.11.2 ws: 8.22.0 transitivePeerDependencies: - bufferutil + - kerberos - proxy-agent - supports-color - utf-8-validate - yauzl - webdriverio@10.0.2(yauzl@2.10.0): + webdriverio@10.1.0(yauzl@2.10.0): dependencies: '@types/node': 26.6.4 - '@types/sinonjs__fake-timers': 8.1.5 - '@wdio/config': 10.0.1(yauzl@2.10.0) - '@wdio/logger': 10.0.0 + '@types/sinonjs__fake-timers': 15.0.1 + '@wdio/config': 10.1.0(yauzl@2.10.0) + '@wdio/logger': 10.1.0 '@wdio/protocols': 10.0.2 '@wdio/repl': 10.0.0 - '@wdio/types': 10.0.1 - '@wdio/utils': 10.0.1(yauzl@2.10.0) + '@wdio/types': 10.1.0 + '@wdio/utils': 10.1.0(yauzl@2.10.0) archiver: 8.0.0 aria-query: 5.3.2 cheerio: 1.2.0 @@ -15193,13 +15076,14 @@ snapshots: lodash.clonedeep: 4.5.0 query-selector-shadow-dom: 1.0.1 rgb2hex: 0.2.5 - serialize-error: 12.0.0 + serialize-error: 13.0.2 urlpattern-polyfill: 10.1.0 - webdriver: 10.0.2(yauzl@2.10.0) + webdriver: 10.1.0(yauzl@2.10.0) transitivePeerDependencies: - bare-abort-controller - bare-buffer - bufferutil + - kerberos - proxy-agent - react-native-b4a - supports-color @@ -15254,6 +15138,8 @@ snapshots: is-weakmap: 2.0.2 is-weakset: 2.0.4 + which-command@0.1.0: {} + which-typed-array@1.1.21: dependencies: available-typed-arrays: 1.0.7 @@ -15272,10 +15158,6 @@ snapshots: dependencies: isexe: 2.0.0 - which@6.0.1: - dependencies: - isexe: 4.0.0 - why-is-node-running@3.2.1: {} widest-line@3.1.0: @@ -15288,12 +15170,6 @@ snapshots: workerpool@6.5.1: {} - wrap-ansi@6.2.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -15397,10 +15273,6 @@ snapshots: yocto-queue@0.1.0: {} - yocto-queue@1.2.2: {} - - yoctocolors-cjs@2.1.3: {} - yoctocolors@2.2.0: {} yup@1.7.1: