@@ -7,7 +7,7 @@ import { resolve } from 'import-meta-resolve'
77import { SevereServiceError } from 'webdriverio'
88import type { WebDriverCommands } from '@wdio/protocols'
99
10- import { PAGE_TRANSITION_COMMANDS } from './constants.js'
10+ import { PAGE_TRANSITION_COMMANDS , LOCATOR_COMMANDS } from './constants.js'
1111import { isNativeMobile } from './mobile.js'
1212import {
1313 CAPTURE_PERFORMANCE_SCRIPT ,
@@ -30,6 +30,11 @@ export class SessionCapturer extends SessionCapturerBase {
3030 readonly startWallTime = Date . now ( )
3131 /** Last find-element selector — carried forward to the next element command. */
3232 #lastSelector: string | undefined
33+ /** Selector resolved during the current assertion. Unlike #lastSelector this
34+ * updates on EVERY locator command (even below the top-level boundary), so
35+ * it captures the element `expect($('#flash'))` resolves inside the matcher.
36+ * Cleared at each matcher start so a value assertion inherits nothing. */
37+ #lastResolvedSelector: string | undefined
3338 /** Collapses internal command retries onto a single entry (see #captureOrReplace). */
3439 #retryTracker = new RetryTracker ( )
3540 #pendingNetworkRequests = new Map <
@@ -55,6 +60,21 @@ export class SessionCapturer extends SessionCapturerBase {
5560 */
5661 resetLastSelector ( ) : void {
5762 this . #lastSelector = undefined
63+ this . #lastResolvedSelector = undefined
64+ }
65+
66+ /** Record the selector of an element-resolution command, ungated by the
67+ * top-level filter — the service calls this for every locator command so an
68+ * assertion can recover the element expect() resolved internally. */
69+ noteResolvedSelector ( selector : string ) : void {
70+ this . #lastResolvedSelector = selector
71+ }
72+
73+ /** Clear the resolved selector at a matcher's start, so only an element
74+ * resolved DURING this matcher (an element assertion) is attributed to it —
75+ * a value assertion (`expect(x).toBe(y)`) resolves nothing and stays blank. */
76+ beginAssertionSelector ( ) : void {
77+ this . #lastResolvedSelector = undefined
5878 }
5979
6080 protected override onWsError ( err : unknown ) : void {
@@ -146,12 +166,7 @@ export class SessionCapturer extends SessionCapturerBase {
146166 // Track last find-element selector so element commands (click, setValue, …)
147167 // carry a human-readable selector in trace events even though WDIO doesn't
148168 // pass it in their args.
149- if (
150- cmd === '$' ||
151- cmd === '$$' ||
152- cmd === 'findElement' ||
153- cmd === 'findElements'
154- ) {
169+ if ( LOCATOR_COMMANDS . includes ( cmd ) ) {
155170 const sel = args [ 0 ]
156171 if ( typeof sel === 'string' && sel . length > 0 ) {
157172 this . #lastSelector = sel
@@ -253,8 +268,12 @@ export class SessionCapturer extends SessionCapturerBase {
253268 }
254269
255270 /** Ingest an assertion entry (node:assert capture or synthesized expect
256- * failure) through the same retry-collapsing path driver commands use. */
271+ * failure) through the same retry-collapsing path driver commands use. A
272+ * fresh (unfolded) expect row still carries the element it targeted. */
257273 captureAssertCommand ( entry : CommandLog ) : void {
274+ if ( ! entry . selector ) {
275+ entry . selector = this . #lastResolvedSelector
276+ }
258277 this . #captureOrReplace( entry )
259278 }
260279
@@ -296,10 +315,10 @@ export class SessionCapturer extends SessionCapturerBase {
296315 callSource : entry . callSource ?? last . callSource ,
297316 screenshot : entry . screenshot ?? last . screenshot ,
298317 error : entry . error ?? last . error ,
299- // The matcher's `args` become the expected value on fold, so the read's
300- // locator is the only record of which element the assertion targeted —
301- // carry it so the player's overlay can box e.g. `#flash`.
302- selector : entry . selector ?? last . selector ?? this . #lastSelector
318+ // The matcher's `args` become the expected value on fold, so record which
319+ // element the assertion targeted — the selector expect() resolved during
320+ // this matcher — so the player's overlay can box e.g. `#flash`.
321+ selector : entry . selector ?? this . #lastResolvedSelector
303322 }
304323 log [ log . length - 1 ] = merged
305324 this . sendReplaceCommand ( last . timestamp , merged )
0 commit comments