Skip to content

fix(nightwatch-devtools): read the performance log off the command queue - #472

Merged
vishnuv688 merged 2 commits into
mainfrom
fix/nightwatch-perf-log-off-queue
Oct 27, 2026
Merged

vishnuv688 merged 2 commits into
mainfrom
fix/nightwatch-perf-log-off-queue

Conversation

@vishnuv688

Copy link
Copy Markdown
Member

What & why

Follow-up to #467. That PR moved the post-navigation performance read off Nightwatch's command queue, because a queued command issued while the test's own command was running made that command's await resolve early (setValue returned before it finished typing; #457). The no-BiDi network fallback had the same problem in a second place: SessionCapturer.captureNetworkFromPerformanceLogs still read Chrome's performance log with browser.getLog('performance'), which is also a queued command.

It runs while a test command is in flight. The read happens at the end of captureTrace, after the collector drain, and captureTrace is called from:

  • browserProxy.ts drainOutgoingPage, fire-and-forget (.catch(() => {})) from the command callback of every DOM-mutating command. By the time its HTTP drain has returned, the test has usually started its next command.
  • session.ts anchorAfterNavigation, after a pollUntilReady loop of 150 ms timer ticks.
  • the navigation proxy's injectAndCapture, chained off the navigation's thenable.

Nightwatch makes a command issued then a child of the running one. In Nightwatch 3.16.0, lib/core/queue.js add() creates the new node with parent: this.currentNode, so a getLog issued while the test's setValue is running becomes a child of that setValue. getLog itself (lib/api/client-commands/getLog.js) is a queued ClientCommand that calls sessionLog, so this is the same path #467 removed for browser.execute.

Fix. The log is now read over the raw WebDriver transport (helpers/webdriverHttp.ts webdriverPost) with POST /session/:id/se/log and { type: 'performance' }. That is the route selenium-webdriver maps GET_LOG to (lib/http.js), and Nightwatch's transport calls selenium-webdriver's driver.manage().logs().get(type) (method-mappings.js getLogContents), so the driver receives the same request it did before. The core transport already unwraps value and resolves null on a W3C error or a transport failure, so the local unwrapDriverValue helper and the error-message filtering are no longer needed. The perfLogsRequested gate stays: over HTTP a refused log type resolves null quietly, but the gate still saves one round trip per command on a session that asked for no log, and null is no more distinguishable from an empty log than getLog's undefined was.

Dead code. captureBrowserLogs was not called anywhere: git grep captureBrowserLogs across the repo found only its definition and its own tests in nightwatch-devtools. (Selenium's method with the same name is a separate, live method.) The method, its tests, unwrapDriverValue and the mapChromeBrowserLogs import are deleted.

CLAUDE.md's perfLogsRequested entry and the parser's doc comment are updated to describe the HTTP read.

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

No capability changes. pnpm docs:capabilities --check passes.

Notes for reviewers

  • Regression test: reads the log over the WebDriver transport, never the command queue in packages/nightwatch-devtools/tests/session.test.ts. A local driver stub records each request, and the mock browser's getLog would return the same entries. The test asserts that the stub received exactly POST /session/sess-perf/se/log with body {"type":"performance"}, that browser.getLog was never called, and that the entry was parsed into a network row. With session.ts reverted to main, this test fails, and so do the three captureTrace tests that now serve the log from the stub.
  • The other perf-log tests serve the log over HTTP as well. A W3C invalid argument error body now resolves with no rows, which replaces the old thrown-error test.
  • Checks: pnpm build, pnpm test (227 files, 3015 tests), pnpm lint (0 errors), pnpm typecheck, pnpm docs:capabilities --check, and the conformance suite (15/15) run twice. All passed.
  • Not verified in a real browser. CI cannot run the examples. To check by hand, set bidi: false in examples/nightwatch/nightwatch.conf.cjs (it already requests goog:loggingPrefs: { performance: 'ALL' }) and run:
    pnpm demo:nightwatch
    
    Then confirm that the Network tab fills and that a login's setValue finishes typing before the submit click.

Screenshots / recordings

N/A, no UI change.

🤖 Generated with Claude Code

The no-BiDi network fallback read Chrome's performance log with
browser.getLog, a queued Nightwatch command. That read runs inside
captureTrace, which is reached from the fire-and-forget drain after a
DOM-mutating command and from the navigation poll's timers, so it is
issued while the test's next command is in flight. Nightwatch's queue
adds a command issued then as a child of the running node, and
finishing it resolves that command's await early: the same hazard that
made setValue return before it finished typing when the performance
timings were read with browser.execute. The log now goes over the raw
WebDriver transport, POST /session/:id/se/log, the route
selenium-webdriver (and so Nightwatch) sends for getLog. The
perfLogsRequested gate stays: it still saves a round trip per command
on a session that asked for no log.

captureBrowserLogs had no caller anywhere in the repo, so it is deleted
with the unwrapDriverValue helper only it and the old read used.
@vishnuv688 vishnuv688 self-assigned this Oct 27, 2026
@greptile-apps

greptile-apps Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; the previous connection-settings issue is addressed.

Summary

The PR reads Chrome performance logs through the direct WebDriver transport instead of Nightwatch's command queue.

  • Nightwatch reads performance logs without joining the test command queue.
  • Direct WebDriver calls follow Nightwatch's secure connection settings.
  • The unused Nightwatch browser-log reader is gone.

Reviews (2) · Last reviewed commit: "fix(nightwatch-devtools): use Nightwatch..." · Reviewed by Greptile

…er calls

Direct WebDriver calls built their address from host, port and path
prefix only, so against an https or authenticated grid every one of them
(drains, snapshot probes, screenshots, the performance log, the Appium
executor) went out as plain http without credentials and failed. They
now follow Nightwatch's own rules: https when webdriver.ssl is set or
the port is 443, and basic auth from username and access_key.
@vishnuv688
vishnuv688 merged commit 9a49911 into main Oct 27, 2026
12 checks passed
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.

1 participant