Example app demonstrating Percy's visual testing integration with Maestro on BrowserStack, using the @percy/maestro-app SDK.
The repo ships two flows:
flows/screenshot.yaml— baseline: launches the calculator and captures two snapshots.flows/regions.yaml— demonstrates Percy regions: one coordinate-based ignore region, one element-based ignore region.
Both flows target the bundled BrowserStack sample calculator (com.sample.browserstack.samplecalculator).
- Node.js 14+ and npm
zipon yourPATH(used bynpm run prepare-zip)- A BrowserStack account with App Automate access
- A Percy project of type App and its
PERCY_TOKEN
git clone https://github.com/percy/example-percy-maestro-app
cd example-percy-maestro-app
npm installnpm install brings in @percy/maestro-app and @percy/cli (devDependencies).
A pre-built APK ships in resources/. To build from source instead, see Build from source below.
curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \
-X POST "https://api-cloud.browserstack.com/app-automate/maestro/v2/app" \
-F "file=@resources/app-debug.apk"Note the app_url (e.g. bs://...) from the response.
prepare-zip vendor-copies the SDK from node_modules/@percy/maestro-app/percy into flows/percy/ and zips flows/ into Flows.zip. This is the recommended Mode B workflow from the SDK README.
npm run prepare-zipcurl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \
-X POST "https://api-cloud.browserstack.com/app-automate/maestro/v2/test-suite" \
-F "file=@Flows.zip"Note the test_suite_url (e.g. bs://...) from the response.
curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \
-X POST "https://api-cloud.browserstack.com/app-automate/maestro/v2/android/build" \
-H "Content-Type: application/json" \
-d '{
"app": "<APP_URL>",
"testSuite": "<TEST_SUITE_URL>",
"devices": ["Samsung Galaxy S22-13.0"],
"project": "Percy Maestro Example",
"percyOptions": {
"enabled": true,
"percyToken": "<PERCY_TOKEN>"
}
}'Replace <APP_URL>, <TEST_SUITE_URL>, and <PERCY_TOKEN> with values from previous steps.
BrowserStack runs both screenshot.yaml and regions.yaml in this build. Percy CLI on the BS host receives the screenshots and uploads them to your Percy project — 4 snapshots total (2 from each flow).
iOS: trigger the iOS build endpoint instead and use
appPercyin place ofpercyOptions. See the SDK README's BrowserStack Integration section for the iOS payload shape.
Open the Percy build URL from your project. The first build is the baseline. Modify a tapOn: step in either flow, re-run npm run prepare-zip and Step 3–4, and Percy will diff the new snapshots against the baseline.
For the regions flow, notice that changes inside the masked regions (status bar, calculator result display) are not flagged as diffs — that's the regions feature working.
Captures two snapshots: the calculator launch screen and a screen after entering an arithmetic operation. No regions, no special configuration. This is the minimum integration shape.
Captures two snapshots, each demonstrating one region type:
- Coordinate region:
top: 0, bottom: 50, left: 0, right: 1080withalgorithm: "ignore"— masks the device status bar. - Element region:
element: { "resource-id": "com.sample.browserstack.samplecalculator:id/editText" }withalgorithm: "ignore"— masks the calculator's result display, whose value changes between runs.
The bundled calculator app has zero android:contentDescription attributes, so resource-id is the only stable selector available. Resource IDs survive into the build because app/build.gradle sets minifyEnabled false. If you adapt this demo to an app that ships R8/minified release builds, prefer content-desc selectors — see the SDK's Release-build caveat (Android) section.
example-percy-maestro-app/
├── package.json ← devDeps: @percy/maestro-app + @percy/cli
├── scripts/
│ └── prepare-zip.sh ← vendors the SDK from node_modules + zips flows/
├── flows/
│ ├── screenshot.yaml ← baseline 2-snapshot flow
│ └── regions.yaml ← coordinate + element regions demo
├── app/ ← Android sample app source
├── resources/
│ └── app-debug.apk ← pre-built sample APK
└── build.gradle, gradlew, … ← Gradle infra (used only by Build from source)
After npm run prepare-zip, a flows/percy/ directory is added (vendored from node_modules/@percy/maestro-app/percy). Both flows/percy/ and Flows.zip are gitignored — they're build outputs, not source.
To build the APK yourself instead of using the pre-built one:
./gradlew assembleDebugThe APK lands at app/build/outputs/apk/debug/app-debug.apk.
MIT