Skip to content

fix(browserstack): send W3C-only capabilities so bstack:options labels are honoured - #2608

Merged
thymikee merged 1 commit into
callstack:mainfrom
Procopis-QG:fix/browserstack-w3c-capabilities
Sep 14, 2026
Merged

thymikee merged 1 commit into
callstack:mainfrom
Procopis-QG:fix/browserstack-w3c-capabilities

Conversation

@Procopis-QG

Copy link
Copy Markdown
Contributor

Summary

BrowserStack sessions still land in "Untitled Project" / "Untitled Build" with an empty name after #2495 carried --provider-project, --provider-build and --provider-session-name through to the provider (#2494). The remaining half of that symptom is in buildBrowserStackCapabilities: it emits the legacy JSON Wire keys device, os_version and app at the top level beside the W3C bstack:options block. The hub classifies any request carrying a legacy key as a legacy session, reads project/build/name from the legacy top-level keys (never set), and ignores bstack:options entirely.

The builder now emits appium:deviceName, appium:platformVersion and appium:app, leaving bstack:options as the only vendor block. Verified against live App Automate sessions: the same bstack:options payload is ignored with the legacy keys present and honoured without them, independent of Appium version.

Integration assertions move to the W3C shape and cloud-webdriver-provider-adapters additionally rejects any legacy key (device, os_version, app, project, build, name) at the top level.

5 files touched (1 source, 3 integration tests, CHANGELOG). Related: #2494, #2495.

Validation

Tested commit: 12e5c14

  • pnpm check:affected --base upstream/main --run — all runnable checks passed (format, lint, typecheck, layering, fallow, build, vitest-related: 103 files / 588 tests).
  • pnpm exec vitest run test/integration/provider-scenarios/cloud-webdriver-{lease-http,provider-adapters,runtime}.test.ts packages/provider-webdriver/src/browserstack.test.ts — 14/14 passed (provider-integration project).
  • Live evidence: named/statused sessions on App Automate from a fork build carrying this change (v0.21.1-pelago.1), used in our CI since 2026-09-14.
  • GitHub-authoritative lanes (web-smoke, replay-ios) not run locally.

Unresolved risk: none known. No public flag or wire-response change.

…s are honoured

BrowserStack's hub classifies a create-session request as legacy JSON Wire as soon as
any legacy top-level key (`device`, `os_version`, `app`) is present. In that mode it
reads project/build/name from the legacy top-level keys, which agent-device never
sets, and ignores `bstack:options` entirely — so every session still landed in
"Untitled Project" / "Untitled Build" with an empty name after #2495 carried the
`--provider-project` / `--provider-build` / `--provider-session-name` flags through to
the provider (#2494).

`buildBrowserStackCapabilities` now emits `appium:deviceName`, `appium:platformVersion`
and `appium:app` instead, leaving `bstack:options` as the only vendor block. Verified
against live App Automate sessions: the same `bstack:options` payload is ignored with
the legacy keys present and honoured without them, independent of Appium version.

Integration assertions updated to the W3C shape and extended to reject any legacy key
at the top level.

Co-authored-by: Cursor <cursoragent@cursor.com>
@thymikee

Copy link
Copy Markdown
Member

Reviewed at 12e5c14. This looks clean: the builder now sends only appium: keys next to bstack:options, and the new test fails without the fix.

One question: can a user-supplied webdriverCapabilities override still add a legacy top-level key such as device or project? No test covers that path.

No CI checks have run on this head yet.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Sep 14, 2026
@thymikee

Copy link
Copy Markdown
Member

Reviewed at 12e5c14. The capability change looks fine, with no code findings.

The live App Automate check in the description ran on the fork release v0.21.1-pelago.1. Could you link a run on 12e5c14, or confirm that release is built from this commit? This changes what the hosted session receives, so a run of this exact change matters. CI has not run yet on this fork PR, and there are no conflicts.

@Procopis-QG

Copy link
Copy Markdown
Contributor Author

Good catch — it depends on which entrypoint builds the session.

CLI / daemon path (what this PR fixes): no. prepareSession in provider-definitions.ts always passes configured: buildCloudWebDriverBaseCapabilities(platform, deviceName) into buildBrowserStackCapabilities — there is no operator-facing flag or profile field that threads an arbitrary capability blob into configured. The integration assertions on this path now reject any legacy top-level key (device, os_version, app, project, build, name).

Programmatic @internal factory (createBrowserStackWebDriverRuntime({ webdriverCapabilities })): yes. That option becomes configured and spreads after the appium: keys, so a caller could still reintroduce a legacy top-level key and flip the hub back to legacy mode. Same shape as before this PR — the defect we hit was the builder emitting legacy keys itself, not an operator override.

Happy to add a reject-list in buildBrowserStackCapabilities (strip known legacy keys from configured before merge) and a unit test on the factory path if you'd like that closed in this PR or as a follow-up.

@thymikee
thymikee merged commit 8dd6b85 into callstack:main Sep 14, 2026
13 checks passed
@Procopis-QG
Procopis-QG deleted the fix/browserstack-w3c-capabilities branch September 14, 2026 21:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants