This repository demonstrates how to run Appium tests using WebdriverIO on BrowserStack App Automate.
The project is written in TypeScript and uses Mocha as the test framework. It includes standard sample tests and dialler tests that use BrowserStack Cross-Device Automation Agent (AI authoring) to answer incoming calls and perform DTMF.
- Node.js 18+ — Download if needed.
- BrowserStack account — Sign up and get your username and access key from Account Settings.
Android and iOS have separate package.json files. Install the one you need:
# Android
cd android && npm i
# iOS
cd ios && npm iSet these before running tests (or export in your shell):
BROWSERSTACK_USERNAME— your BrowserStack usernameBROWSERSTACK_ACCESS_KEY— your BrowserStack access key
Upload the app first, then set BROWSERSTACK_APP_ID:
Upload your .apk or .ipa to BrowserStack (e.g. via App Automate Dashboard → Upload App, or the Upload App API). After upload, set BROWSERSTACK_APP_ID to the returned app URL (e.g. bs://... or your custom_id). This avoids re-uploading on every run and is required for some setups (e.g. dedicated devices).
BROWSERSTACK_APP_ID— app URL from BrowserStack after upload (e.g.bs://...); set this when using a pre-uploaded app.
From the android or ios directory:
| Command | Description |
|---|---|
npm run test |
Parallel tests (BStack sample app) |
npm run dialler |
Dialler flow: app test → wait → prompt to dial → answer call (AI) → DTMF → end call |
npm run typecheck |
TypeScript check only |
Examples:
cd android
npm run test # parallel
npm run dialler # dialler (Wikipedia app + incoming call + DTMF)
cd ios
npm run test # parallel
npm run dialler # dialler (BStack sample app + incoming call + DTMF)The project includes a configurable reporter that aggregates:
- Test Reporting & Analytics (build details + tests)
- App Automate (sessions + apps)
It produces customer-shareable outputs for spreadsheets, docs, and IDE previews.
cd tools/browserstack-report
npm i
cp browserstack-report.config.sample.json browserstack-report.config.json
export BROWSERSTACK_USERNAME="your_username"
export BROWSERSTACK_ACCESS_KEY="your_access_key"
npm run reportReports are generated under tools/browserstack-report/reports/browserstack-report/ by default.
browserstack-report-overview.csvbrowserstack-report-builds.csvbrowserstack-report-tests.csvbrowserstack-report-sessions.csvbrowserstack-report-apps.csvbrowserstack-report.xlsx(one sheet per section)browserstack-report.md(full markdown tables, latest-first)browserstack-report-*.json(raw tabular exports)
Most config keys are optional. If a key is omitted, defaults are applied in code, so config files stay small and portable.
Useful knobs:
filters.days: trailing-day filter; setnull(default) to export all datafilters.projects/filters.teams/filters.people: optional keyword filtersfilters.applyDaysToApps: whetherdaysalso applies to app inventory (falseby default)outputs.formats: choosecsv,xlsx,md, and/orjsoncolumns.*: override output columns and order for customer-facing schemasinputs.discoverRecentBuilds: auto-discover recent builds when build IDs are not provided
Example filter block:
"filters": {
"days": 14,
"projects": ["dialler", "payments"],
"teams": ["griffins"],
"people": ["thomas"],
"caseSensitive": false
}- If
inputs.testReportingBuildIdsis empty, Test Reporting builds are discovered from Test Reporting project build lists. - If
inputs.appAutomateBuildIdsis empty, App Automate builds are discovered from recent App Automate builds. filters.daysis used during discovery so only recent runs are pulled when a day window is set.- You can always provide explicit build IDs to lock reporting to specific runs.
- Empty report sections usually mean no matching build IDs after filtering; set
filters.daystonullto validate first. - Ensure
BROWSERSTACK_USERNAMEandBROWSERSTACK_ACCESS_KEYare exported in the same shell running the script. - Keep
discoverRecentBuilds.enabled: trueunless you always pass explicit build IDs.
- Android:
android/examples/run-parallel-test/— runs against multiple devices. - iOS:
ios/examples/run-parallel-test/— BStack sample app: Text Button → Text Input → assert Text Output. - Docs: Parallel testing on App Automate.
End-to-end flow that uses a real (or SIM-capable) device, then an incoming call and DTMF:
- Device info — read SIM/phone number from the device (for the “dial this number” prompt).
- App flow — run the main app test (Wikipedia on Android, BStack sample app on iOS).
- Wait & prompt — wait ~20s, then print “PLEASE DIAL THE DEVICE PHONE NUMBER NOW” and the number in the terminal.
- Answer call — you call the device; the test uses BrowserStack AI (Cross-Device Automation Agent) to accept the call (e.g. swipe/tap the green Answer button).
- DTMF & end — AI taps the digit sequence on the keypad, then ends the call.
Config:
- Android:
android/examples/run-dialler-test/dialler.conf.ts— uses WikipediaSample.apk,aiAuthoring: true, optional SIM capabilities. - iOS:
ios/examples/run-dialler-test/dialler.conf.ts— uses BStackSampleApp.ipa,aiAuthoring: true.
AI service: DialerAIService (in support/DialerAIService.ts) sends natural-language commands via browserstack_executor: {"action": "ai", "arguments": ["..."]} for answer, keypad, DTMF, and end call. Logging goes to both the terminal and BrowserStack session logs.
Requirements:
- Upload the app first and set
BROWSERSTACK_APP_IDto the app URL (e.g.bs://...) — see Environment variables above. - BrowserStack AI / Cross-Device Automation Agent enabled for your account.
- For real incoming calls: device with SIM (or BrowserStack SIM) and a phone to dial from.
Reports: JUnit XML is written under examples/run-dialler-test/reports/junit/ (per platform).
android/
examples/
run-parallel-test/ # parallel BStack sample tests
run-dialler-test/ # dialler: Wikipedia + call + DTMF (DialerAIService)
WikipediaSample.apk, LocalSample.apk
ios/
examples/
run-parallel-test/ # parallel BStack sample tests
run-dialler-test/ # dialler: BStack sample + call + DTMF (DialerAIService)
BStackSampleApp.ipa, LocalSample.ipa

