webdriverio/webdriverio

[🐛 Bug]: browser.url() on BiDi is much slower than classic navigateTo for a simple page load

开放

#15,481 创建于 2026年8月9日

 (1 条评论) (0 个反应) (0 位负责人)JavaScript (1,793 个派生)batch import
Bug 🐛PerformanceProtocol Relatedhelp wanted

仓库指标

星标
 (6,029 个星标)
PR 合并指标
 (平均合并 15天 15小时) (30 天内合并 48 个 PR)

描述

Have you read the Contributing Guidelines on issues?

WebdriverIO Version

Latest

Node.js Version

v24.12.0

Mode

WDIO Testrunner

Which capabilities are you using?

{
  browserName: 'chrome',
  // Chrome 151.0.7922.76, macOS arm64, headless
  // session is BiDi (browser.isBidi === true)
}

What happened?

I was comparing navigation cost for a local static page (http://localhost:4173/index.html). Same browser, same URL, reloads in one session. When the session is on BiDi, browser.url() is consistently in the ~450–700ms range. If I call classic navigateTo on the same URL in that same session, it lands around ~65ms.

So most of the time is not “waiting for the page to load”, the page can be ready in ~65ms. The rest looks like BiDi path overhead: context lookup, browsingContext.navigate, and then the url() wrapper still waiting on network request payload so it can return the rich request object.

Rough split from my measurements:

browser.url() (BiDi)     ≈ 450–700ms
  ├── navigateTo (classic) ≈ 65ms     ← actual navigation / load
  └── BiDi overhead        ≈ 400–600ms

I also timed the raw BiDi call:

  • browsingContextNavigate with wait: 'complete' → ~600ms
  • browsingContextNavigate with wait: 'none' → still ~430ms

So even wait: 'none' does not get close to classic. The wait flag is not the whole story, a lot of cost is already in the BiDi navigate path / surrounding setup.

I’m not saying BiDi url() is wrong, the richer options (headers, auth, onBeforeLoad, networkIdle, request metadata) are useful. The issue is that the default path pays for that setup even when I only do browser.url('/index.html') and never use those options.

What is your expected behavior?

For a plain browser.url(url) with no BiDi-only options, I’d expect cost much closer to classic navigateTo / a normal page-load wait, not hundreds of ms of overhead on a local static page.

How to reproduce the bug.

// repro-url-bidi.mjs
import { remote } from 'webdriverio'

const URL = 'http://localhost:4173/index.html // or any cheap local static page
const N = 10

const browser = await remote({
  logLevel: 'error',
  capabilities: {
    browserName: 'chrome',
    'goog:chromeOptions': { args: ['--headless=new'] },
  },
})

console.log('isBidi', browser.isBidi)
await browser.url(URL) // warm-up

const urlTimes = []
const classicTimes = []
const biDiComplete = []
const biDiNone = []

const tree = await browser.browsingContextGetTree({})
const context = tree.contexts[0].context

for (let i = 0; i < N; i++) {
  let t0 = performance.now()
  await browser.url(URL)
  urlTimes.push(Math.round(performance.now() - t0))

  t0 = performance.now()
  await browser.navigateTo(URL)
  classicTimes.push(Math.round(performance.now() - t0))

  t0 = performance.now()
  await browser.browsingContextNavigate({ context, url: URL, wait: 'complete' })
  biDiComplete.push(Math.round(performance.now() - t0))

  t0 = performance.now()
  await browser.browsingContextNavigate({ context, url: URL, wait: 'none' })
  biDiNone.push(Math.round(performance.now() - t0))
}

const med = (a) => [...a].sort((x, y) => x - y)[Math.floor(a.length / 2)]
console.log({
  urlMed: med(urlTimes),
  classicNavigateToMed: med(classicTimes),
  browsingContextCompleteMed: med(biDiComplete),
  browsingContextNoneMed: med(biDiNone),
  urlSamples: urlTimes,
  classicSamples: classicTimes,
})

await browser.deleteSession()
node repro-url-bidi.mjs

On my machine (Chrome headless, BiDi session, warm reloads) I see url and browsingContextNavigate hundreds of ms above navigateTo.

Relevant log output

Based on my local http://localhost:4173/index.html


isBidi true
{
  urlMed: 334,
  classicNavigateToMed: 35,
  browsingContextCompleteMed: 694,
  browsingContextNoneMed: 336,
  urlSamples: [
    131, 356, 326, 332,
    331, 330, 335, 420,
    334, 422
  ],
  classicSamples: [
    56, 30, 29, 34, 36,
    35, 30, 36, 28, 39
  ]
}

Code of Conduct

  • I agree to follow this project's Code of Conduct

Is there an existing issue for this?

  • I have searched the existing issues

贡献者指南