run-local.sh builds the app, boots a simulator/emulator, starts Appium, resets app state, and runs the E2E test suite.
Quick start: run ./bootstrap.sh — it idempotently installs Appium + drivers,
Vite+ (and the vpx symlink), test deps, and creates .env from the example.
Then fill in your OneSignal credentials in .env and open a new shell so vpx
is on PATH. The manual steps below are the same thing, broken out.
-
Clone the SDK repo next to
sdk-shared(or setFLUTTER_DIR):Code/SDK/ ├── sdk-shared/ # this repo └── OneSignal-Flutter-SDK/ # Flutter SDK (auto-detected at ../../OneSignal-Flutter-SDK) -
Create your
.envfile:cp .env.example .env
At minimum, set your OneSignal credentials (the script fails fast without them). Use the OneSignal app dedicated to Appium tests — not a general or shared app, whose live in-app marketing campaigns can cover the UI and cause misleading "element not displayed" failures:
ONESIGNAL_APP_ID=your-appium-test-app-id ONESIGNAL_API_KEY=your-appium-test-api-key -
Install Appium and drivers (if not already):
npm i -g appium appium driver install xcuitest # iOS appium driver install uiautomator2 # Android
-
Install Vite+ (if not already) — it provides the
vpxcommand the script uses to run WebdriverIO:curl -fsSL https://vite.plus | bashvpxis thevpbinary under an argv[0] alias. If the installer doesn't create the symlink (seen on some versions), add it manually and open a new shell:ln -sf ../current/bin/vp ~/.vite-plus/bin/vpxNote: the npm package
vite-plusships onlyvp/oxfmt/oxlint(novpx). Use the official installer above;./bootstrap.shhandles the symlink for you.
The script checks all of these up front and prints the exact install command for anything missing; node_modules in appium/ is installed automatically on first run.
CI vs local: CI runs on BrowserStack (Node 24) without this script. Notification-dependent tests (in
02_push.spec.tsand12_activity.spec.ts) are skipped on BrowserStack iOS viaisBrowserStackIos()because BrowserStack requires an Enterprise Signing Certificate for those notification flows, which we don't have yet (temporary — they'll be re-enabled once signing support is available), so for now they only run locally. If your local Node is 26+, the script setsWDIO_USE_NATIVE_FETCH=1automatically.
./run-local.sh --platform=ios --sdk=flutterIf --platform or --sdk are not provided, the script prompts interactively.
| Flag | Description |
|---|---|
--platform=P |
ios or android |
--sdk=S |
flutter or react-native |
--spec=GLOB |
Spec file glob (default: tests/specs/**/*.spec.ts) |
--skip |
Skip build, device launch, and app reset (rerun tests only) |
--skip-build |
Skip app build (reuse existing .app/.apk) |
--skip-device |
Skip simulator/emulator launch |
--skip-reset |
Keep existing app data between runs |
--pods |
Use examples/demo-pods for Flutter, Cordova, and Capacitor |
-h, --help |
Show help |
Run all tests (full build + fresh install):
./run-local.sh --platform=ios --sdk=flutterRun a single spec file:
./run-local.sh --platform=ios --sdk=flutter --spec="tests/specs/01_user.spec.ts"
# partial
./run-local.sh --platform=ios --sdk=flutter --spec="01_"Run multiple spec files:
./run-local.sh --platform=ios --sdk=flutter --spec="tests/specs/{01_user,08_outcome}.spec.ts"
# partial
./run-local.sh --platform=ios --sdk=flutter --spec="tests/specs/{01_,08_}*"Re-run tests without rebuilding or relaunching the simulator:
./run-local.sh --platform=ios --sdk=flutter --skipSkip only the build (simulator + reset still happen):
./run-local.sh --platform=ios --sdk=flutter --skip-buildAll env vars can be set in .env or exported in your shell. See .env.example for the full list.
| Variable | Default | Description |
|---|---|---|
ONESIGNAL_APP_ID |
-- | OneSignal app ID (written to demo app .env) |
ONESIGNAL_API_KEY |
-- | OneSignal REST API key |
FLUTTER_DIR |
../../OneSignal-Flutter-SDK |
Path to the Flutter SDK repo |
APP_PATH |
auto-detected from build | Path to .app or .apk |
BUNDLE_ID |
com.onesignal.example |
App bundle/package ID |
DEVICE |
iPhone 17 / Samsung Galaxy S26 |
Device name for WebdriverIO |
OS_VERSION |
26.2 / 16 |
Platform version |
IOS_SIMULATOR |
same as DEVICE |
Simulator name for simctl |
IOS_RUNTIME |
iOS-26-2 |
simctl runtime identifier |
AVD_NAME |
Samsung_Galaxy_S26 |
Android AVD name |
APPIUM_PORT |
4723 |
Appium server port |
-
Test fails with "element not displayed": The app may not have been rebuilt after code changes. The script rebuilds by default, but if you used
--skip-build, delete the existing build and re-run:rm -rf /path/to/OneSignal-Flutter-SDK/examples/demo/build/ios/iphonesimulator/Runner.app ./run-local.sh --platform=ios --sdk=flutter
-
Simulator not found: The script falls back automatically to the booted simulator, or to the newest installed iOS runtime, when the requested device/runtime isn't on your machine. To pin a specific one, check
xcrun simctl list devices availableand setDEVICE/OS_VERSION/IOS_RUNTIMEin your.env. -
Appium fails to start: Make sure Appium and the required drivers are installed (
appium driver list --installed). The script checks both up front and prints the install command for anything missing. -
vpx: command not found: Install Vite+ withcurl -fsSL https://vite.plus | bash. Ifvpis installed butvpxis missing, runvp --versiononce —vpcreates thevpxsymlink on its first run. -
UND_ERR_INVALID_ARG/ fetch errors on Node 26+: webdriverio's undici dispatcher is rejected by Node 26+'sfetch. The script exportsWDIO_USE_NATIVE_FETCH=1automatically when it detects Node 26+; if you invokevpx wdio runmanually, export it yourself. -
Test waiting for the notification permission alert fails: A reused simulator remembers a previously-decided notification permission, and
simctl privacycan't reset it. The script's app reset uninstalls the app, which restores the prompt — avoid--skip/--skip-resetwhen running the push specs. -
Misleading "element not displayed" failures: Live in-app marketing campaigns on the configured app can cover the UI. Use the OneSignal app dedicated to Appium tests (set
ONESIGNAL_APP_ID/ONESIGNAL_API_KEYin.env) rather than a general or shared app.