Repository navigation
feat(conformance): judge failed tests, call sites and per-test rows - #466
Merged
Merged
Conversation
The suite checked how the stream is built but not three things a user sees: a failed test with nothing red, a call site pointing away from the spec, and a test with no rows. Each broke in the Selenium adapter unnoticed. Three rules now judge them per adapter, on the scenario tests and their attribution: every reported test has rows, every failed test (or one designed to fail) has a failed action by shared's commandFailure, and every callSource names a line of the spec the runner executed, which each adapter's launch now declares. An unmapped poll's error does not explain a failure, since a passing wait's polls error too. The call-site rule reads a call source with the dashboard's own parser, now in shared, so it cannot pass a call site the Source tab would not resolve. Python's timed-out WebDriverWait (#461) and Nightwatch's same-millisecond replace overwriting the failed assertion (#458) are scoped gaps. Closes #454
4 of 17 tasks
Contributor
[Medium impact] The PR appears safe to merge; no actionable new defects were found. SummaryAdds three conformance checks for missing test rows, failed tests without a failed action, and call sites outside the scenario file.
Diagram%%{init: {'theme': 'neutral'}}%%
flowchart LR
Launch[Adapter launch] --> Spec[Read scenario file]
Launch --> Run[Run scenario]
Run --> Frames[Recorded rows and tests]
Frames --> Checks[Check test rows and failures]
Frames --> Sites[Check call sites]
Spec --> Sites
Checks --> Judge[Apply scoped known gaps]
Sites --> Judge
Judge --> Report[Run report]
Reviews (2) · Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." · Reviewed by Greptile |
3 of 17 tasks
…-rules # Conflicts: # packages/conformance/src/allowlist.ts
This was referenced Oct 27, 2026
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 #454.
The conformance suite checked how the event stream is built, but not three things a user sees in the dashboard:
All three broke in the Selenium adapter (fixed in #453) without any check noticing. This PR adds a rule for each, judged per adapter on the scenario tests and attribution from #465:
every-test-has-rowstests-end-as-designed.failed-test-has-error-rowcommandFailure. An unmapped poll's error does not count, since a passing wait's polls error too.call-site-names-the-scenariocallSourcenames a line inside the spec the runner executed. DevTools' ownpackages/, any other file,unknown:0and an out-of-range line all fail.Each adapter's launch now declares its
scenarioFile, and the harness reads it before cleanup, so the Python copy is still readable.Proof that the rules guard #453. On this branch I reverted every source file #453 changed (core, shared, trace, selenium-devtools), rebuilt, and ran the conformance suite. Selenium failed in all three BiDi modes, and the cross-adapter agreement check failed too. WebdriverIO, Nightwatch and Python stayed green. The three new rules caught all three of #453's bugs:
failed-test-has-error-row: the timed-out wait left its failed test with no failed action (once per mode).call-site-names-the-scenario: a poll row namedunknown:0(once per mode).tests-end-as-designedandone-row-per-browser-action: the first test lost its rows.The run also flagged
every-document-anchored,row-replays-its-page,every-browser-request-listedandadapters-agree-on-actions/-snapshots/-requests, all from the lost first test. With #453 restored, the suite passed 15/15 in two runs.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 Source tab row is now "✅ tested" for all four adapters, since
call-site-names-the-scenarioholds with no gap.failed-test-has-error-rowalso backs the Errors row for WebdriverIO and Selenium.every-test-has-rowsis listed inINTERNAL_RULES, because it is a precondition of every per-test view rather than a feature.Notes for reviewers
mainonce those merge.failed-test-has-error-row, each matched to its one test by a newfailureUnexplainedmatcher:WebDriverWaitleaves no row (Python: a WebDriverWait leaves no row, so a timed-out wait shows nothing red #461). It fires every run, so the gap is never stale.replaceCommandoverwrites the failed assertion row (Nightwatch: a late screenshot replace can overwrite an assertion row stamped in the same millisecond #458). This is a race, so the gap is markedtimingDependent.parseCallSourcemoved fromapptoshared, and the app re-exports it. The rule therefore reads a call source exactly the way the Source tab does, rather than through a second parser that had already drifted (it convertedfile://URLs and the app does not). The conversion to a path stays in the rule, where the comparison is against files on disk.app, and its change is a move with no behaviour change.🤖 Generated with Claude Code