Skip to content

Capture the native element tree per action in Selenium and Nightwatch - #569

Open
vishnuv688 wants to merge 4 commits into
mainfrom
fix/563-native-page-source
Open

vishnuv688 wants to merge 4 commits into
mainfrom
fix/563-native-page-source

Conversation

@vishnuv688

Copy link
Copy Markdown
Member

What & why

Closes #563. Part of the #516 follow-ups.

On a native Appium session, Selenium and Nightwatch trace actions carried a screenshot and nothing else: no element list, no locators, an empty A11y tab. The WebdriverIO service reads the app's page source on every native capture; the other two JS adapters never did. #516 measured the difference on this machine: a native WDIO trace has the element tree on every action, a Selenium or Nightwatch one has none.

Both adapters now pass a page-source reader and the session's platform to core's captureActionSnapshot, which already builds the native snapshot text and element locators from it for the service. The read stays out of the user's command stream:

  • Selenium calls the unpatched getPageSource, stashed before the driver is wrapped, so it fires no onCommand and renders no row.
  • Nightwatch reads GET /session/:id/source over the raw WebDriver transport, the same path its screenshot probe uses, so it never enters Nightwatch's queue.

Platform comes from the session capabilities (platformName, flat or under appium:options/bstack:options) through core's new nativeAppOf, exposed on the capturer as nativeApp.

A hybrid app in a webview answers /source with HTML. That source is now recognised and skipped (screenshot only, as before), so a webview action neither prints xmldom parse errors nor records a tag skeleton as the native tree.

Type of change

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Polish (an improvement to an existing feature)
  • Breaking change (existing behavior changes for users)
  • Documentation
  • Internal (build, CI, dependencies, tooling)

Packages touched

  • shared (types and contracts)
  • core (framework-agnostic capture/reporting)
  • elements (published element/snapshot API — @wdio/elements)
  • service (WebdriverIO adapter)
  • nightwatch-devtools (Nightwatch adapter)
  • selenium-devtools (Selenium adapter)
  • selenium-devtools-py (Selenium Python adapter)
  • backend (server)
  • app (UI)
  • script (page-injected runtime)
  • trace (Trace mode)

Capability matrix

  • packages/conformance/src/features.ts updated, and tables regenerated with pnpm docs:capabilities, if this adds or changes user-facing behaviour

New mobile row native-element-tree: WebdriverIO, Selenium and Nightwatch supported; Python unsupported (it takes no per-action snapshot on a native app, only the row screenshot). The docs-site tables follow in a webdriverio PR.

Notes for reviewers

  • Why both adapters in one PR rather than core: the capture itself is core's (captureActionSnapshot, fromPageSource, nativeAppOf); what lands in each adapter is only how it reads the source without touching its own command pipeline, which is framework glue.
  • Cost is trace mode only, and only for commands that already take a capture (reads and waits do not, per skipsCapture). Trace mode: measure where per-action capture time goes, per platform #516 measured the page source as 87% of an iOS capture; it shows as the pageSource probe under DEVTOOLS_CAPTURE_TIMING=1.
  • Residuals shared with the service: every probe has its own 4 s ceiling from issue, so on a very heavy iOS tree a slow source can push the screenshot past its ceiling; and Mac2/tvOS sessions are read as Android, since no platform name maps them.
  • Python's native page source is a separate follow-up.
  • An independent review found nothing blocking; its one medium finding (webview HTML) is fixed here.

Testing

  • pnpm build, pnpm typecheck, pnpm test (4077 passed, 1 skipped), pnpm lint, pnpm docs:capabilities --check are green.
  • Selenium tests/action-snapshot.test.ts and Nightwatch tests/native-session.test.ts: native captures read the source and produce [android]/[ios] snapshot text and elements; Selenium's original getPageSource fires no onCommand while the patched one does. Core: the webview HTML case keeps the screenshot, records no tree and logs nothing. All fail without the change.

Needs checking by hand

  1. DEVTOOLS_MODE=trace pnpm demo:selenium:mobile and DEVTOOLS_MODE=trace pnpm demo:nightwatch:mobile (Android emulator, Appium running): open the trace, pick an action, and the A11y tab shows the app's tree with elements highlighted on hover.
  2. The same with DEVTOOLS_MOBILE_PLATFORM=ios.

Screenshots / recordings

None.

🤖 Generated with Claude Code

vishnuv688 and others added 4 commits November 10, 2026 17:08
On a native Appium session both adapters handed core's per-action capture
a screenshot reader and nothing else, so their native traces carried no
element list, accessibility tree or locators, while the WebdriverIO
service built all three from the app's page source. Both now pass a
page-source reader: Selenium through the unpatched driver original, so the
read is never recorded as a getPageSource row of the user's, and Nightwatch
over the raw WebDriver transport, as its other probes do, since a queued
command issued from the command hook cannot resolve.

The platform the XML is read by comes from core's SessionCapturer.nativeApp,
derived from the session capabilities, so an iOS source is no longer parsed
as Android. Passing the reader also marks the capture native in the
capture timing report and times its pageSource probe. The Nightwatch
navigation recapture loses its native flag: it only runs for a session
with a document, so the flag was always false there.

The page source is the costly half of a native capture (about half on
Android, 87% on iOS in the capture-timing measurements), which CLAUDE.md
and the READMEs now state. The Python adapter still captures a screenshot
alone on a native app, and its README no longer claims otherwise.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Selenium and Nightwatch now build a native app's element list and
accessibility tree from its page source, as the WebdriverIO service does,
and the matrix had no row saying which adapters do. The new row cites each
adapter's own test, and marks Python unsupported because its native capture
is a screenshot alone.

Four long reasons move to capability-reasons.ts and the three identical
Cucumber step rerun cells share one constant, which keeps features.ts under
the file-size cap with the new row in it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A hybrid app in a webview answers /source with HTML. Parsed as XML it
printed xmldom errors on every action and recorded an empty tag skeleton
as the native tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vishnuv688 vishnuv688 self-assigned this Nov 10, 2026
@vercel

vercel Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
devtools Ready Ready Preview Nov 10, 2026 12:14pm UTC

Request Review

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Selenium and Nightwatch: native traces have no element or accessibility tree

1 participant