BrowserStack
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.
| Option | Default | Meaning |
|---|---|---|
username | required | The BrowserStack username, a credential. |
accessKey | required | The BrowserStack access key, a credential. |
local | false | Start a BrowserStack Local tunnel for the run. |
localIdentifier | The tunnel's identifier. Without local, a tunnel you already run. | |
localBinary | The BrowserStackLocal binary to run, instead of the one the wrapper finds or downloads. Needs local: true. | |
apiUrl | https://api.browserstack.com | The Automate API: web session lookups, marks and the plan. |
appApiUrl | https://api-cloud.browserstack.com | The App Automate API: uploads, device sessions and the plan. |
hubUrl | https://hub.browserstack.com/wd/hub | The Appium hub device sessions connect to. |
playwrightUrl | wss://cdp.browserstack.com/playwright | The 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.
| Setting | Default | Meaning |
|---|---|---|
os | OS X | The web session's operating system, such as Windows. |
osVersion | Sequoia | The operating system version, such as 11 or Sequoia. |
browser | by engine | chrome, edge, playwright-chromium, playwright-firefox or playwright-webkit. |
browserVersion | The Chrome or Edge version, such as latest or latest-1. | |
project | agent-qa | The BrowserStack project sessions are filed under. |
build | the run ID | The BrowserStack build name. |
appiumVersion | 3.5.2 | The Appium version device sessions ask for. |
extra | Capabilities merged last, overriding the ones above. |
Web tests
A web session asks BrowserStack for:
browser: thebrowsersetting, or the one that matches the test's engine:chromefor Chromium,playwright-firefoxfor Firefox andplaywright-webkitfor WebKit. A browser that cannot run the test's engine is refused atsettings.browser;os,os_versionand, when set,browser_version;- the Playwright version agent-qa runs, which BrowserStack must list;
project,buildandname, 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 ownbstack:options.appiumVersioncapability, else theappiumVersionsetting, else3.5.2;projectName,buildNameandsessionName, 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.ipaApps
A device test needs the app on BrowserStack:
app.refwins. When the target setsapp.ref, abs://ID from an earlier upload or anhttpsURL, 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 asuploading 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: truelocal: truestarts one tunnel on the run's first session, with a fresh identifier orlocalIdentifierwhen 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.localIdentifierwithoutlocaluses a tunnel you already run under that identifier. The plugin starts nothing.- The tunnel comes from BrowserStack's
browserstack-localpackage, which finds BrowserStack's binary in~/.browserstack, the working folder or the temp folder, and downloads it when none is there.localBinarynames 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
unreachableatoptions.local, oroptions.localBinarywhen that is set, and the line says how to fix it:
| Cause | Fix |
|---|---|
EBADARCH: a Mac binary built for another CPU | Install 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 exist | Set localBinary to the path of a BrowserStackLocal binary. |
EACCES: the file is not executable | Make it executable, or set localBinary to one that is. |
| Anything else | Set 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.
Links and marks
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:
| Outcome | Mark |
|---|---|
| Passed | passed |
| Failed | failed, with the reason, cut to 255 characters |
| agent-qa's own error | failed, with agent-qa's sentence |
| Cancelled | none |
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 refusedwhen BrowserStack refuses them, and that a product is not on the account, such asApp Automate is not on this account; - it warns when BrowserStack does not list agent-qa's Playwright version.
When a remote is refused
| Kind | Cause | Fix |
|---|---|---|
auth | BrowserStack responded with 401. | Check the username and access key in your secrets file. |
capacity | BrowserStack responded with 429: every parallel session is in use, or the API rate limit was hit. | Wait, or lower use.workers. |
version | BrowserStack 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.browser | That setting or option is wrong. | Fix the line it names. |
refused with no path | BrowserStack responded with another error. | Read the status and message in the line. |
unreachable | BrowserStack did not respond. | Check the network. |
unreachable at options.local or options.localBinary | The 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.