Repository navigation
Name a node:assert target from value provenance in the WDIO service - #484
Merged
Merged
Conversation
The service stamped every node:assert row with the last element any locator resolved, so an assertion on the page title boxed the heading read before it. node:assert takes values, so only provenance can say which element (if any) a value came from: the service now feeds core's value registry from each row it logs (element commands with their selector, driver-level reads with none) and resolves assert targets from the raw args, as Selenium and Nightwatch already do. The last-resolved fallback stays for expect matcher rows, which resolve their own element. getTitle was internal only because the snapshot probe calls it from inside a hook with the spec on the stack, which also hid the user's own call. The probe now marks its title reads in flight and the hooks skip those, so the user's getTitle is a Page.getTitle row like in the other adapters. Removes the conformance gaps for #481 now that the service passes page-level-assertion-names-no-element.
Contributor
[Medium impact] The PR appears safe to merge; no new actionable issue remains. SummaryThe service now uses remembered command results to choose targets for
All three previous threads were rechecked and are addressed. None supplied a comment number. Diagram%%{init: {'theme': 'neutral'}}%%
flowchart LR
Read[Captured command result] --> Registry[Remember value and target]
Registry --> Assert[node:assert arguments]
Assert --> Row[Assertion row target]
Boundary[Test or scenario starts] --> Clear[Clear remembered values]
Clear --> Registry
Matcher[WebdriverIO matcher] --> Separate[Separate matcher capture path]
Reviews (4) · Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." · Reviewed by Greptile |
2 of 18 tasks
…t-target The base merged main, which fixed #459 and dropped the nightwatchSkipped gap and its Known debt bullet. This branch fixes #481 and drops the serviceAssertTarget gap and its bullet. Both removals are kept, so KNOWN_DEBT and the conformance debt list carry neither entry; the base's other changes come through unchanged. With both gaps gone nothing in the allowlist names the page-title test any more, so its index is dropped.
A node:assert row looked its operands up in a value registry that lived for the whole run, so a later test's assert.ok(true) boxed an element an earlier test had read true from. The registry is now cleared whenever a test or scenario starts: core exports clearReadValues, which the service calls from resetStack, Selenium from startTest and startScenario, and Nightwatch from resetTestTracking. Nightwatch's plugin hook fires once per module on the BDD interface, so its proxy also clears when the running `it` changes, before each record and each lookup. Python clears its own registry at pytest_runtest_logstart. The service told its own snapshot title probe apart from the user's getTitle by counting probes in flight. Core's probe timeout abandons a getTitle that is still running, which left the count positive and hid a user getTitle issued in that window. The probe now runs inside an AsyncLocalStorage context, and WDIO awaits a command's hooks within that command, so the hooks see the context for the probe's call and nothing else.
The service took an element read's value as the element's only when ACTION_MAP classed the command Element, and ACTION_MAP leaves out getHTML, getComputedRole, getComputedLabel, isStable and isEqual, so an assertion on their value lost its element. They are listed in the service, every other WDIO element command is listed as returning nothing an assertion compares, and a test fails when the installed WebdriverIO ships an element command in neither list.
vishnuv688
changed the base branch from
feat/479-conformance-timings-targets
to
main
October 28, 2026 19:40
4 of 13 tasks
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 #481.
In the WebdriverIO service, a
node:assertrow took the last element any locator had resolved. Soassert.notEqual(await browser.getTitle(), 'Secure Area')after$('h2').getText()boxedh2. The user's ownbrowser.getTitle()also had no row, becausegetTitlewas inINTERNAL_COMMANDS.rememberReadValue) from every rowSessionCapturer.afterCommandlogs. A command that ACTION_MAP classesElementrecords the selector the row resolved. Every other read, such asgetTitle, records the "no element" sentinel.wireAssertCapturepassesresolveAssertTargetFromArgstopatchNodeAssert, as Selenium and Nightwatch already do. Anode:assertrow with no known producer now names nothing instead of the last resolved element.captureMatcherCommand). Those rows resolve their own element inside the matcher. Folding is unchanged.getTitlewas internal because the snapshot probe calls it from inside a hook, with the spec frame on the stack. That made the probe look like a user call, and listing it as internal hid the user's call too.action-snapshot.tsnow counts its own title reads while they are in flight, and both hooks skip agetTitlethat arrives during one (isServiceProbe). Without that guard, the probe'safterCommandtakes the user's stack frame and logs the probe's result as the user's row; a unit test covers this.devtools-serviceknown gaps for WebdriverIO service: an assertion on the page title boxes the last element touched #481 frompackages/conformance/src/allowlist.ts, along with theirKNOWN_DEBTentry and the CLAUDE.md bullet. The value-provenance, handle-selector and matcher-folding Known debt entries now describe the service's current behaviour.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 behaviourNo feature cell changes.
pnpm docs:capabilities --checkpasses.Notes for reviewers
Stacked on #483. The base is
feat/479-conformance-timings-targets. Retarget this PR tomainafter #483 merges.Proof:
packages/service/srcchange and rebuilt, keeping the gaps removed. Conformance failed 6 tests:page-level-assertion-names-no-element("assert.notEqual on the page title names h2") in all three modes, and the agreement check ("devtools-service shows [Assert.notEqual h2], selenium-devtools shows [Page.getTitle, Assert.notEqual]").packages/service/tests/assert-target.test.tsfail without the fix and pass with it: the title-vs-heading collision, and an assert on anh2read that still namesh2after a later#logoutclick. A third test intrace-action-capture.test.tscovers the snapshot probe re-entering the hooks during the user'sgetTitle.Behaviour changes worth knowing:
expect(browser).toHaveTitle()now folds into the visiblegetTitleread, liketoHaveTextdoes withgetText. Before, it produced a fresh row.getUrlis still internal, sotoHaveUrlstill produces a fresh row.Checks:
pnpm build, fullpnpm test(3049 passed),pnpm lint(0 errors),pnpm typecheck,pnpm docs:capabilities --check, and the dist leak grep forpackages/service(no matches).Not verified in a real browser. All verification was unit tests plus the conformance suite against its fake WebDriver server. To check by hand, add a title assertion to the WDIO example spec, for example:
Then run
pnpm demo:wdio. The Actions list should show aPage.getTitlerow, and theassert.notEqualrow should box no element.Screenshots / recordings
N/A (no UI change).
🤖 Generated with Claude Code