Skip to content

fix(nightwatch-devtools): give captured command rows a stable id for replaceCommand - #470

Closed
hoanle0126 wants to merge 1 commit into
webdriverio:mainfrom
hoanle0126:fix/nightwatch-row-ids-458
Closed

hoanle0126 wants to merge 1 commit into
webdriverio:mainfrom
hoanle0126:fix/nightwatch-row-ids-458

Conversation

@hoanle0126

Copy link
Copy Markdown
Contributor

What & why

Fixes #458.

In @wdio/nightwatch-devtools, SessionCapturer.captureCommand stamped only the internal _id field (which sendCommand and sendReplaceCommand strip before sending upstream) and left the public id field undefined. When a command like getText completed in the same millisecond as a following node:assert row, getText's asynchronous screenshot update (sendReplaceCommand(ts, entry)) fell back to lastIndexOf(oldTimestamp) in @wdio/devtools-shared's replaceCommandIndex and overwrote the node:assert row instead of updating getText in place.

  • Stamp id: commandId on rows in SessionCapturer.captureCommand (matching captureAssertCommand and @wdio/selenium-devtools) and preserve the superseded row's id across SessionCapturer.replaceCommand.
  • Guard BrowserProxy.attachScreenshot with this.sessionCapturer.commandsLog.includes(entry) so an in-flight screenshot from a retried attempt does not overwrite a replacement row.

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

@greptile-apps

greptile-apps Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The changes affect command-row updates and screenshots in Nightwatch captures.

Fix public ID reuse across Nightwatch reruns before merging.

Findings

  1. P1 Reruns overwrite earlier commands ▶

Summary

Adds public IDs to captured Nightwatch commands, preserves them across retries, and drops screenshots for superseded rows.

  • Nightwatch command rows keep one public id across retries.
  • Late screenshots are skipped after a retry replaces their command row.

Reviews (1) · Last reviewed commit: "fix(nightwatch-devtools): give captured ..." · Reviewed by Greptile

const commandId = this.commandCounter++
const commandLogEntry: CommandLog & { _id?: number } = {
_id: commandId,
id: commandId,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Reruns overwrite earlier commands

id: commandId repeats when the UI starts a Nightwatch rerun in a new process. The backend keeps earlier commands, but the new capturer starts its counter at zero. When the rerun sends a screenshot or retry update, replaceCommandIndex picks the first earlier command with that id, even when its timestamp differs. This overwrites the earlier command and leaves the new command unchanged.

Give public IDs a unique range across capturers, or limit replacement matching to the originating capturer.

@vishnuv688

Copy link
Copy Markdown
Member

Thanks for this! I had been working on #458 locally too, and I've raised the fix as #473.

Your diagnosis and the core of the fix match what I ended up with: a public id on Nightwatch driver rows, kept across a retry, and dropping a late screenshot for a row a retry already replaced.

#473 goes one step further on the concern Greptile raised here, which turned out to be real. When a test is rerun from the dashboard, the backend keeps the parent run's rows (so Preserve & Rerun still has data), and Nightwatch test_workers share one dashboard. Since every process's counter started at 0, a replace from one process could match another process's row with the same id. Selenium rows and Nightwatch's own assertion rows already had that exposure, so #473 starts the counter at a random base per capturer in core, which covers all of them. It also removes the conformance suite's two #458 gaps (the suite passed 10 of 10 runs without them).

I'll close this one in favour of #473. Thanks again, it made the bug quick to pin down.

@vishnuv688

Copy link
Copy Markdown
Member

Closing as fixed by #473, which is now merged. Thanks again for pinning this down, @hoanle0126!

@vishnuv688 vishnuv688 closed this Oct 27, 2026
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.

Nightwatch: a late screenshot replace can overwrite an assertion row stamped in the same millisecond

2 participants