Repository navigation
Python: take no screenshot for a read in trace mode - #568
Open
vishnuv688 wants to merge 9 commits into
Open
vishnuv688 wants to merge 9 commits into
vishnuv688 wants to merge 9 commits into
Conversation
The Python adapter reaches Appium's is_displayed() as the isElementDisplayed wire command, and the context, activity, keyboard, lock and app-state queries under their own names. None of them is in READ_ONLY_COMMANDS, so the deny-list gate captured after each one as if it could have changed the screen. They join the list, and the wire schema and Python contract are regenerated from it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only the element-tree read followed the JS adapters' page-changing gate; the screenshot was still taken after every command, so reads, waits and lookups were most of a Python trace's capture cost (42 captures on the Android Clock flow where WebdriverIO takes 8, 44% of wall time). Trace mode now takes the screenshot only when the command takes the capture, and a read's row shows the capture before it, as in the JS adapters. Live mode keeps a screenshot per row, the dashboard's only picture of a native app. A native app's capture is now recorded as a screenshot-only action snapshot, so the end-of-test capture can supersede a stale one there too; before, the reads after a click carried their own screenshots and hid that gap. The gate is mirrored by a new captureGate section in mirror-vectors.json, run against core's TestCapture.queue and shared's skipsCapture on one side and the Python hook's classification, atom scripts included, on the other. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dited Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…wait polls Without a pushed CDP screencast the per-command screenshots are the filmstrip, so skipping a read's screenshot also dropped the frames that showed a page loading under a WebDriverWait, which the default trace used to have. A command that takes no capture now still takes a filmstrip-only screenshot when a non-push recorder is live: every poll a wait issues, and any other read once the JS adapters' 200 ms poll interval (shared SCREENCAST_DEFAULTS, generated into _contract.py) has passed since the last frame. Those shots go to the recorder alone, with no row screenshot, action snapshot or timing record. The end-of-test capture also reaches the recorder, so the filmstrip ends on the state the test ended on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Python trace-mode note on "Screenshot on every command row" described a difference that is not one: every adapter's live rows carry a screenshot, and none of the JS adapters' trace captures follow reads either, so the cells go back to their earlier, uniform wording and the tables are regenerated. The Appium reads added to READ_ONLY_COMMANDS change which command the WDIO service treats as the last screen change, so @wdio/devtools-service gets a patch changeset saying so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ait polls still take Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… them The Python filmstrip cell said browsers without CDP take one frame per command, and the screenshot-switch cell that every row takes a screenshot. Neither holds in trace mode any more: frames come from page-changing commands plus wait polls and paced reads, and read rows carry no screenshot. Python gets its own wording for both, true in live and trace mode alike. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…m new docstrings A poll that raises takes no frame, as before, so the docs now say a wait's commands that return. The changes fragment also states the end-of-test capture now runs on native apps, at one more screenshot per test ending on reads. The docstrings added in this branch are cut to one line, per the comment rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vishnuv688
marked this pull request as ready for review
November 10, 2026 12:46
4 of 13 tasks
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Closes #562. Part of the #516 follow-ups.
The JS adapters take a per-action capture only for commands that can change the page; the Python adapter already applied that to its element-tree read, but still took a screenshot for every command. In #516 that was 42 screenshots for an Android flow the JS adapters capture 8 times, 44% of the run's wall time.
In trace mode the Python adapter now takes the screenshot (and action snapshot) only when core's rule says the command captures: page-changing commands, and each test's first mapped command even when it reads. Live mode is unchanged (every row still gets a screenshot).
The filmstrip keeps its frames. On a native app or a browser without a CDP screencast, Python's filmstrip is built from these screenshots, so a command that takes no capture still adds a filmstrip-only frame (no row screenshot, no snapshot) when it is a
WebDriverWaitpoll that returns, or a read at least 200 ms after the last frame (the JS recorder's poll interval, generated from sharedSCREENCAST_DEFAULTS). The end-of-test capture is the filmstrip's last frame, now on native apps too. With a CDP screencast live, nothing extra is taken. A sharedcaptureGatemirror-vector section (40 cases) runs against core'sTestCapture.queueand Python's gate, so the two cannot drift. Appium's element and session reads (isElementDisplayed,getContexts,getCurrentActivity, ...) are added to sharedREAD_ONLY_COMMANDS.Type of change
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.tsupdated, and tables regenerated withpnpm docs:capabilities, if this adds or changes user-facing behaviourThe Python filmstrip cell and its "Turn off per-command screenshots" reason now say what trace mode takes; tables regenerated. The docs-site tables follow in a webdriverio PR.
Notes for reviewers
Testing
pnpm build,pnpm typecheck,pnpm test(4104 passed, 1 skipped),pnpm lint,pnpm docs:capabilities --checkare green; Python 931 passed (the twotest_instrumentation.pyfailures also fail on main).tests/test_capture_gate.pydrives the real patchedexecuteandWebDriverWaitwith a fake recorder: wait-poll frames, the 200 ms read frame and the final frame fail without the fix.Needs checking:
DEVTOOLS_MODE=trace DEVTOOLS_CAPTURE_TIMING=1 pnpm demo:python:pytestandpnpm demo:python:mobile(withPYTHONPATHset to the worktree'ssrc): the capture count drops from 42 toward the JS adapters' 8-15, read rows show the previous capture, the filmstrip still shows the page loading during waits, and its last frame is the final screen.Screenshots / recordings
None.
🤖 Generated with Claude Code