This document describes how to set up Android emulators, iOS simulators, Linux desktop dependencies, and Chrome for running integration tests locally and in CI.
Same-repository PR, develop push and release-candidate workflows use
scripts/run_android_emulator_ci.sh in group vypdev with runner labels
[self-hosted, codex, Linux] to install the required SDK components, create an
API 30 aosp_atd pixel_2 AVD, and run the Android integration tests. The Android Test Device image avoids Google Play services that are not needed by this package's tests and is suitable for headless execution. The generated AVD disables GPS because the tests do not use location, and the launcher disables the emulator's GnssGrpcV1 feature so it does not start an unnecessary host GNSS socket. Vulkan is disabled explicitly because this software-only runner has experienced emulator crashes while initializing the Vulkan/SwiftShader backend; swiftshader_indirect remains enabled for GLES rendering. The workflow builds the APK first and explicitly uses software emulation because the current self-hosted runner does not expose /dev/kvm. The launcher intentionally starts the emulator directly instead of using a generic action whose unconditional input-unlock step is unreliable while this slow software image is still bringing up Android services. Before Flutter starts, scripts/wait_for_android_ci_services.sh requires the package, input, and settings services plus the package manager to pass a single combined adb probe repeatedly for 90 seconds; this avoids relying on the image's early boot_completed signal without multiplying slow ADB round trips. Every ADB operation has its own timeout so a stalled ADB daemon cannot consume the whole job silently; ANDROID_ADB_TIMEOUT_SECONDS can override the 30-second default. If boot or readiness times out, the launcher prints the emulator log and the readiness script prints Android logcat output.
- Android SDK: Install via Android Studio or the command-line tools. Set
ANDROID_HOMEorANDROID_SDK_ROOTto the SDK root (e.g.~/Library/Android/sdkon macOS). - Platform tools: Include
adb(usually in$ANDROID_HOME/platform-tools). - Emulator: Install the "Android Emulator" package and a system image from SDK Manager (e.g. API 31,
google_atd,x86_64orarm64-v8afor Apple Silicon). - Linux CI:
/dev/kvmis recommended for speed, but the current workflow can run without it using software emulation.
-
Start an emulator from Android Studio (AVD Manager → Play) or from the command line:
emulator -avd <your_avd_name> -no-window &
Wait until the device appears in
adb devicesand is fully booted. -
Run the tests from the repo root:
./scripts/test_android_integration.sh
The script picks the first connected device/emulator. To use a specific device:
FLUTTER_DEVICE_ID=<id> ./scripts/test_android_integration.sh(get<id>fromflutter devices).
If you need to create an AVD, install a system image first, then create the AVD in Android Studio or with avdmanager:
# Intel / AMD (x86_64)
$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "system-images;android-31;google_atd;x86_64"
# Apple Silicon (arm64-v8a)
$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "system-images;android-31;google_atd;arm64-v8a"- "adb not found": Ensure
platform-toolsis installed and thatANDROID_HOME(orANDROID_SDK_ROOT) is set. - "No Android device or emulator found": Start an emulator from Android Studio or run
emulator -avd <avd> -no-window &, then run the script again. Useflutter devicesto confirm the device is visible. - To skip Android in the full integration suite:
ZSTANDARD_SKIP_ANDROID=1 ./scripts/test_all_integration.sh.
- Xcode: Install from the Mac App Store. Accept the license and install additional components if prompted.
- Command Line Tools:
xcode-select --installif needed. Simulators are controlled viaxcrun simctl.
| Command | Description |
|---|---|
start |
Boot a simulator (default device: iPhone 16, overridable with ZSTANDARD_IOS_DEVICE). |
stop |
Shut down the booted simulator. |
list |
List available simulators. |
status |
Print whether a simulator is booted. |
device-id |
Print the device ID (UUID or name) for flutter test -d <device-id>. |
Environment variables:
ZSTANDARD_IOS_DEVICE: Device name (e.g.iPhone 16,iPhone 15). Default:iPhone 16.ZSTANDARD_IOS_BOOT_TIMEOUT: Boot wait timeout in seconds (default:60).
Example:
./scripts/manage_ios_simulator.sh start
./scripts/test_ios_integration.sh
./scripts/manage_ios_simulator.sh stop # optional- "No available iPhone simulator": Open Xcode → Window → Devices and Simulators and download a simulator runtime, or run
xcrun simctl list devices availableto see what is installed. AdjustZSTANDARD_IOS_DEVICEto a device you have (e.g.iPhone 15). - Simulator already booted: The script will reuse the booted simulator. Use
device-idto get the ID forflutter test -d. - Flutter cannot find device: Ensure the simulator is booted and run
flutter devicesto confirm the device id; then pass that id toflutter test integration_test/ -d <id>.
Linux integration tests require CMake, Ninja, Clang, pkg-config, GTK 3 development headers, and Xvfb on headless runners. The CI workflow installs these through .github/actions/setup-linux-dependencies/action.yml, then runs:
cd zstandard_linux/example
flutter build linux --debug
xvfb-run --auto-servernum flutter test integration_test/ -d linuxThe Linux runner must be Debian/Ubuntu-based with APT/dpkg tools and network
access. The dependency action reuses installed packages and extracts missing
dependencies into a private job prefix. It requires no passwordless sudo and
does not change or repair the host package database.
Web tests run in Chrome. The script runs both unit tests (flutter test -d chrome) and integration tests (flutter drive with a local web server and ChromeDriver).
- Chrome: Installed and on PATH. GitHub Actions installs Chrome for Testing with
browser-actions/setup-chrome@v2. - ChromeDriver (for integration tests only): Must be on PATH and listen on port 4444. Flutter uses it to drive the browser for integration tests.
- Install locally with
brew install chromedriver(macOS), or download a version that matches your Chrome. CI installs the matching driver automatically. - macOS: If a security popup says "chromedriver cannot be opened" or "Apple could not verify...", remove the quarantine attribute:
xattr -d com.apple.quarantine "$(which chromedriver)"
If that fails (e.g. symlink), use the real binary path (e.g./opt/homebrew/Caskroom/chromedriver/<version>/chromedriver-mac-arm64/chromedriver). - See Flutter: Test in a web browser.
- Install locally with
From the repo root:
./scripts/test_web_integration.shThis runs:
- Unit tests in Chrome (
zstandard_webpackage tests). - Integration tests via
flutter drive --target=integration_test/... -d web-server, which starts a local server and uses ChromeDriver to control Chrome. On Linux the script uses Xvfb. If ChromeDriver is unavailable or fails to start, the script fails; useZSTANDARD_SKIP_WEB=1only for an intentional partial local run.
If the script skips integration tests (ChromeDriver not available), start ChromeDriver in another terminal, then run the script again:
# Terminal 1
chromedriver --port=4444
# Terminal 2 (repo root)
./scripts/test_web_integration.shOr run only the integration tests from the example app:
chromedriver --port=4444 &
cd zstandard_web/example
flutter drive \
--driver=test_driver/integration_test.dart \
--target=integration_test/zstandard_web_integration_test.dart \
-d web-server --web-port=8080From zstandard_web:
flutter test -d chrome- Android: Reuse a single emulator and avoid closing it between test runs to save boot time. Leave the emulator running and run
./scripts/test_android_integration.shas needed. - iOS: Similarly, leaving the simulator booted between runs avoids repeated boot time.
- CI: Self-hosted runners with pre-created AVDs and simulators can reduce job time. Ensure
ANDROID_HOME(orANDROID_SDK_ROOT) is available for Linux Android jobs; KVM is optional for the current software-emulation configuration, and Xcode is configured for Apple jobs.