Skip to main content
Skip to Content

Run web tests on BrowserStack browsers and mobile tests on BrowserStack Android and iOS devices, with app uploads, BrowserStack Local and session marks.

The BrowserStack plugin, @vostride/agent-qa-plugin-browserstack, runs web tests on BrowserStack browsers over the Playwright protocol, and mobile tests on BrowserStack Android and iOS devices over Appium. It uploads your app once per build, links each test to its BrowserStack session, and marks the session passed or failed.

Install

Install the plugin at exactly the version of agent-qa your project runs:

npm install --save-dev --save-exact @vostride/agent-qa-plugin-browserstack@$(npx agent-qa --version)

Configure

One plugins entry holds the account. Add a remote for each place you run, and point devices at a device remote:

plugins:
  - name: browserstack
    package: "@vostride/agent-qa-plugin-browserstack"
    options:
      username: "{{secret:BROWSERSTACK_USERNAME}}"
      accessKey: "{{secret:BROWSERSTACK_ACCESS_KEY}}"

registry:
  remotes:
    - name: browserstack
      plugin: browserstack
      settings:
        os: Windows
        osVersion: "11"
    - name: browserstack-devices
      plugin: browserstack
  devices:
    bs-pixel:
      platform: android
      remote: browserstack-devices
      model: Google Pixel 9
      os: "15"

A web test runs on BrowserStack with use.browser.remote: browserstack in the config, a suite or the test. A mobile test runs there when its device, here bs-pixel, names a BrowserStack remote. Put both credentials in your secrets file.

Options

Options belong to the plugins entry and describe the account.

OptionDefaultMeaning
usernamerequiredThe BrowserStack username, a credential.
accessKeyrequiredThe BrowserStack access key, a credential.
localfalseStart a BrowserStack Local tunnel for the run.
localIdentifierThe tunnel's identifier. Without local, a tunnel you already run.
localBinaryThe BrowserStackLocal binary to run, instead of the one the wrapper finds or downloads. Needs local: true.
apiUrlhttps://api.browserstack.comThe Automate API: web session lookups, marks and the plan.
appApiUrlhttps://api-cloud.browserstack.comThe App Automate API: uploads, device sessions and the plan.
hubUrlhttps://hub.browserstack.com/wd/hubThe Appium hub device sessions connect to.
playwrightUrlwss://cdp.browserstack.com/playwrightThe Playwright endpoint web sessions connect to.

Write both credentials as {{secret:NAME}} references. Leave the four endpoints unset unless BrowserStack tells you otherwise; they must use https://, or wss:// for playwrightUrl, with no user or password, unless they point at this machine.

The credentials travel only in the Playwright URL, in the device capabilities and in the basic auth header of BrowserStack's REST API, and agent-qa masks them everywhere they could be printed or recorded.

Settings

Settings belong to each remote and describe one place.

SettingDefaultMeaning
osOS XThe web session's operating system, such as Windows.
osVersionSequoiaThe operating system version, such as 11 or Sequoia.
browserby enginechrome, edge, playwright-chromium, playwright-firefox or playwright-webkit.
browserVersionThe Chrome or Edge version, such as latest or latest-1.
projectagent-qaThe BrowserStack project sessions are filed under.
buildthe run IDThe BrowserStack build name.
appiumVersion3.5.2The Appium version device sessions ask for.
extraCapabilities merged last, overriding the ones above.

Web tests

A web session asks BrowserStack for:

  • browser: the browser setting, or the one that matches the test's engine: chrome for Chromium, playwright-firefox for Firefox and playwright-webkit for WebKit. A browser that cannot run the test's engine is refused at settings.browser;
  • os, os_version and, when set, browser_version;
  • the Playwright version agent-qa runs, which BrowserStack must list;
  • project, build and name, the test's name, so each run is one build in BrowserStack's dashboard;
  • extra, merged last.

To run the same tests on several browsers, add a remote for each and pick one per suite:

registry:
  remotes:
    - name: bs-windows-edge
      plugin: browserstack
      settings: { os: Windows, osVersion: "11", browser: edge }
    - name: bs-mac-webkit
      plugin: browserstack
      settings: { os: OS X, osVersion: Sequoia, browser: playwright-webkit }

The suite's engine must fit the browser: edge and chrome run Chromium tests, so a suite on bs-mac-webkit also sets use.browser.name: webkit.

Device tests

A device session connects to BrowserStack's Appium hub. agent-qa sends the device's identity, model as appium:deviceName and os as appium:platformVersion, and BrowserStack picks a real device that matches. The plugin adds bstack:options with:

  • the credentials;
  • appiumVersion: the device's own bstack:options.appiumVersion capability, else the appiumVersion setting, else 3.5.2;
  • projectName, buildName and sessionName, the test's name;
  • extra, merged last.

The device's own capabilities are merged over all of that.

registry:
  devices:
    bs-iphone:
      platform: ios
      remote: browserstack-devices
      model: iPhone 16
      os: "18"
  targets:
    shop-ios:
      platform: ios
      bundleId: com.example.shop
      device: bs-iphone
      app:
        path: builds/Shop.ipa

Apps

A device test needs the app on BrowserStack:

  • app.ref wins. When the target sets app.ref, a bs:// ID from an earlier upload or an https URL, BrowserStack installs that app and nothing is uploaded.
  • Otherwise the plugin uploads app.path. It names the file by its content, agent-qa- and the first 32 hex digits of its SHA-256, and reuses the newest upload under that name. Only a build it has not seen is uploaded, with progress in the run, such as uploading app (84 MB). BrowserStack keeps an upload for 30 days.

An upload may take up to the remote's uploadTimeout, ten minutes by default. The plugin checks that the file still has the size and hash agent-qa saw before it sends it.

BrowserStack Local

BrowserStack Local is a tunnel that lets BrowserStack's browsers and devices reach a target only your machine can reach, such as localhost or a staging host behind a VPN. Turn it on in the entry:

plugins:
  - name: browserstack
    package: "@vostride/agent-qa-plugin-browserstack"
    options:
      username: "{{secret:BROWSERSTACK_USERNAME}}"
      accessKey: "{{secret:BROWSERSTACK_ACCESS_KEY}}"
      local: true
  • local: true starts one tunnel on the run's first session, with a fresh identifier or localIdentifier when set, and every web and device session of the run uses it. The plugin stops the tunnel when the run ends, and when agent-qa is stopped.
  • localIdentifier without local uses a tunnel you already run under that identifier. The plugin starts nothing.
  • The tunnel comes from BrowserStack's browserstack-local package, which finds BrowserStack's binary in ~/.browserstack, the working folder or the temp folder, and downloads it when none is there. localBinary names a binary to run instead.
  • The tunnel logs to a fresh file in the temp folder, readable only by you. Nothing is written into the project.
  • Before it starts the tunnel, the plugin checks that this machine can run the binary. A binary it cannot run refuses the session with kind unreachable at options.local, or options.localBinary when that is set, and the line says how to fix it:
CauseFix
EBADARCH: a Mac binary built for another CPUInstall Rosetta with softwareupdate --install-rosetta --agree-to-license, or set localBinary to a binary built for this Mac. The wrapper downloads BrowserStack's Intel build on every Mac.
ENOENT: the path does not existSet localBinary to the path of a BrowserStackLocal binary.
EACCES: the file is not executableMake it executable, or set localBinary to one that is.
Anything elseSet localBinary to a binary this machine can run.

If the tunnel starts but then fails, the session is refused the same way, and the line names the tunnel's log.

When a session starts, the test gets a link to its page in BrowserStack's dashboard, which needs a BrowserStack login. agent-qa prints it as Remote <name>: <link> and the run page shows it. BrowserStack's shareable public URL is never used.

When the test ends, the plugin marks the session:

OutcomeMark
Passedpassed
Failedfailed, with the reason, cut to 255 characters
agent-qa's own errorfailed, with agent-qa's sentence
Cancellednone

A device session is found by its WebDriver session ID. A web session is found through BrowserStack's API: the one running session in the run's build with the test's name, started after agent-qa asked for it. When none or several match, the test gets no link and the session stays unmarked; a guessed session is never marked. A lookup or mark that fails never fails the test.

Account check

agent-qa doctor runs the plugin's account check, which opens no session:

  • it reads the Automate and App Automate plans, and reports each product's sessions, such as Automate: 1 of 5 parallel sessions running, 0 queued;
  • it warns the username or access key was refused when BrowserStack refuses them, and that a product is not on the account, such as App Automate is not on this account;
  • it warns when BrowserStack does not list agent-qa's Playwright version.

When a remote is refused

KindCauseFix
authBrowserStack responded with 401.Check the username and access key in your secrets file.
capacityBrowserStack responded with 429: every parallel session is in use, or the API rate limit was hit.Wait, or lower use.workers.
versionBrowserStack does not list agent-qa's Playwright version.Run web tests here or on another remote until a plugin release adds it.
refused at a path such as settings.browserThat setting or option is wrong.Fix the line it names.
refused with no pathBrowserStack responded with another error.Read the status and message in the line.
unreachableBrowserStack did not respond.Check the network.
unreachable at options.local or options.localBinaryThe tunnel did not start.Follow the fix in the line, or read the tunnel's log it names.

npx agent-qa plugins describe browserstack --json lists every option and setting with its type, default and description.