Skip to content

WDIO service deadlocks a mobile-web Appium session: beforeCommand awaits page commands inside the command hook #374

Description

@vishnuv688

The WDIO service's beforeCommand awaits page-side commands from inside the hook that wraps the command being issued. On desktop chromedriver that re-entrancy is tolerated. On an Appium mobile-web session it deadlocks: the wrapped command never reaches the browser.

packages/service/src/index.ts beforeCommand:

if (PAGE_TRANSITION_COMMANDS.includes(command)) {          // includes 'url'
  await this.#sessionCapturer.captureTrace(this.#browser)  // browser.execute(...)
}
if (topLevelUserCommand && mode === 'trace' && ) {
  const snap = await captureActionSnapshot(this.#browser, )  // 2 injected scripts + url + title + screenshot
  await this.#markDocument()                                  // browser.execute(...)
}

Measured

Emulator medium_phone, API 36 arm64, Appium 3.7.0 + uiautomator2 7.6.1, browserName: Chrome.

result
the example spec without the devtools service 2 passing in 1.6 s
the same spec with the service 2 failing, 6 m 13 s, every command at the 180 s timeout

A screenshot of the emulator during the failing run shows Chrome on its new-tab page: browser.url() never executed.

Everything the service wants to do is individually fast — measured over raw HTTP against the same Appium, on a session created the same way:

call time
POST /session ok
POST /urlhttp://10.0.2.2:8099/ 0 s
GET /titleMobile web capture ok
POST /execute/sync (return 1+1) 0 s
POST /execute/sync with a 213 KB script (the collector's size) 0 s
POST /execute/sync (return window.visualViewport) 1 s

So it is neither the script size, nor execute itself, nor the network. It is the nesting.

The failure then cascades: the timed-out execute/sync is followed by ECONNREFUSED 127.0.0.1:<chromedriver port>, then Cannot read properties of undefined (reading 'jwproxy'), then Method has not yet been implemented for url (the session has fallen back to the native context), then the UiAutomator2 instrumentation crashes. All of that is downstream of the first deadlock.

Why native mobile is unaffected

isNativeAppSession (added for #372) makes all three of those calls no-ops, so a native app session never re-enters. The native example passes on the same emulator and writes a correct trace (device: {platform: 'android', name: 'sdk_gphone64_arm64', version: '16'}, viewport 1080 × 2400). The bug is specific to a session that HAS a document and is driven through Appium.

This is the same class the Nightwatch adapter already solved

CLAUDE.md records it for Nightwatch: "browser.* are QUEUED commands, so a probe issued from inside the plugin's own command hook enqueues behind the command still running and never resolves" — which is why that adapter routes its probes over raw WebDriver HTTP (helpers/webdriverHttp.ts). The WDIO service has no equivalent escape hatch, and until now never needed one because desktop chromedriver does not serialise this way.

Options

  1. Gate the in-hook page calls on isAppiumSession rather than isNativeAppSession. Smallest change, keeps every run working, and costs a mobile-web Appium session its pre-action DOM capture and its __wdioSnapMark navigation detection. The per-command screenshots and the whole command timeline survive.
  2. Stop awaiting in the hook — fire-and-forget with the result reconciled later. Preserves capture, but changes the ordering guarantee the pre-action snapshot depends on ("state BEFORE this action executes"), for every adapter and platform.
  3. A raw-HTTP transport for the service's own probes, mirroring nightwatch-devtools/src/helpers/webdriverHttp.ts. Most faithful, most work.

(1) is the safe default and (3) is the real fix; (2) trades a documented invariant for it.

Until this is fixed, DEVTOOLS_MOBILE=web against Appium is unusable with the service attached, and examples/MOBILE.md says so.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcapture-architectureCross-language capture architecturemobileAppium / native mobile capture and playback

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions