For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Discord
DocsAPI Reference
DocsAPI Reference
  • Get Started
    • Welcome
    • Introduction
    • Quick Start
  • Run
    • Run Videos
    • Run Mode
    • Viewport Size
    • Preparation Test
    • Pull Request Testing
    • Production Monitoring
    • Group Webhooks
    • Run Troubleshooting
  • Auth
    • Test Credentials
    • API Keys
    • Agent Mail Inboxes
    • HTTP Basic Auth
    • Auth Troubleshooting
  • Mobile
    • Overview
    • App Uploads
    • Expo EAS
    • GitHub Actions
  • Integrations
    • Vercel
    • Coolify
    • Custom Infrastructure
    • Slack
    • Discord
    • Email
  • Guides
    • Testing Staging Environment
  • CLI
    • Getting Started
    • Local Development
    • Agentic Usage
  • AI
    • LLMs
LogoLogo
Discord
On this page
  • Prerequisites
  • Required environment variables
  • Instructions for AI agents
  • Configure mobile build profiles
  • Add the EAS workflow
  • GitHub PR comments and checks
  • Example repository
  • Troubleshooting
  • The build has an unsupported platform or format
  • TesterArmy warns that GitHub integration is not configured / TesterArmy cannot create a PR comment
  • Related docs
Mobile

Expo EAS

||View as Markdown|
Was this page helpful?
Edit this page
Previous

App Uploads

Next

GitHub Actions

Built with

Run TesterArmy mobile tests from Expo EAS workflows by uploading an EAS iOS Simulator build or Android APK and triggering a remote test group.

Prerequisites

Before you set it up, make sure you have already:

  • Created mobile project (can be without uploaded app)
  • Created at least one mobile test

Also make sure that you have configured Expo EAS with Github

Required environment variables

Environment variableDescription
TESTERARMY_API_KEYAPI key for TesterArmy
TESTERARMY_PROJECT_IDProject ID for project you want to run tests on
TESTERARMY_GROUP_IDGroup ID for group you want to run tests on

These values can be found in the TesterArmy Dashboard:

  • API key - Profile → API Keys
  • Project ID - Project Settings
  • Group ID - Test Tab, then click on three dots on the group you want to run tests on and copy the ID

Set TESTERARMY_API_KEY as an EAS secret or sensitive environment variable. Do not commit it, and do not expose it through an EXPO_PUBLIC_* environment variable.

Instructions for AI agents

Below you will find instructions for AI agent to set up EAS integration with TesterArmy for you.

Setup Expo EAS integration with TesterArmy
You are working in an Expo app repository. Add TesterArmy mobile testing through Expo EAS workflows. Before editing files: * Inspect the existing `eas.json`, `.eas/workflows`, `package.json`, and package manager lockfile. * Do not overwrite an existing EAS workflow. Create a new workflow file or make the smallest safe edit. * Do not hard-code secrets, API keys, project IDs, or group IDs in committed files. * Use the repository’s existing package manager style when adding commands. Implement this setup: 1. Detect which platforms are already configured in the app (`ios`, `android`, or both). If it is not clear, ask the user whether to set up iOS, Android, or both before editing workflow files. 2. For iOS, ensure `eas.json` has a TesterArmy iOS Simulator build profile. Prefer `testerarmy-ios-simulator`. If the project already has a compatible simulator profile, reuse it and keep the workflow profile name in sync. 3. For Android, ensure `eas.json` has a TesterArmy APK build profile. Prefer `testerarmy-android-apk`. If the project already has a compatible APK profile, reuse it and keep the workflow profile name in sync. 4. The iOS profile must set `ios.simulator` to `true`. TesterArmy needs a `.app` simulator build, not an `.ipa` device build. 5. The Android profile must produce an APK. Prefer `android.buildType: "apk"`. TesterArmy needs a `.apk`; `.aab` and `.xapk` are not supported. 6. Create `.eas/workflows/testerarmy-mobile-tests.yml` if it does not already exist. 7. The workflow should support `push` to `main`, `pull_request` to `main`, and `workflow_dispatch`. 8. The workflow should read these values from EAS environment variables: * `TESTERARMY_API_KEY` * `TESTERARMY_PROJECT_ID` * `TESTERARMY_GROUP_ID` 9. The workflow should build only the selected platform artifacts: an iOS Simulator app, an Android APK, or both. 10. The workflow should download the selected build artifacts with `eas/download_build`. 11. The workflow should upload each downloaded artifact with `npx --yes testerarmy@latest upload-app`. 12. The workflow should run the saved TesterArmy group for each selected platform, using `--platform ios` for iOS and `--platform android` for Android, plus the uploaded app ID for that platform. 13. The workflow should pass commit SHA for GitHub check reporting when the EAS/GitHub context provides it. 14. The workflow should pass PR number only when the workflow is running for a pull request. 15. The workflow should delete each uploaded app after its run. Use this workflow as the baseline and adapt it to the repository if needed: ```yaml name: TesterArmy Mobile Tests on: push: branches: - main pull_request: branches: - main workflow_dispatch: {} jobs: build_ios: name: Build iOS Simulator app type: build environment: preview params: platform: ios profile: testerarmy-ios-simulator build_android: name: Build Android app type: build environment: preview params: platform: android profile: testerarmy-android-apk upload_ios_app: name: Upload iOS app to TesterArmy needs: [build_ios] environment: preview outputs: app_id: ${{ fromJSON(steps.upload_app.outputs.upload_result).uploadedAppId }} steps: - uses: eas/checkout - uses: eas/download_build id: download_build with: build_id: ${{ needs.build_ios.outputs.build_id }} extensions: - app - name: Upload app id: upload_app run: | set -euo pipefail APP_PATH="${{ steps.download_build.outputs.artifact_path }}" mkdir -p .testerarmy npx --yes testerarmy@latest upload-app \ --app-path "$APP_PATH" \ --project "$TESTERARMY_PROJECT_ID" \ --output .testerarmy/upload.json set-output upload_result "$(tr -d '\n' < .testerarmy/upload.json)" upload_android_app: name: Upload Android app to TesterArmy needs: [build_android] environment: preview outputs: app_id: ${{ fromJSON(steps.upload_app.outputs.upload_result).uploadedAppId }} steps: - uses: eas/checkout - uses: eas/download_build id: download_build with: build_id: ${{ needs.build_android.outputs.build_id }} extensions: - apk - name: Upload app id: upload_app run: | set -euo pipefail APP_PATH="${{ steps.download_build.outputs.artifact_path }}" mkdir -p .testerarmy npx --yes testerarmy@latest upload-app \ --app-path "$APP_PATH" \ --project "$TESTERARMY_PROJECT_ID" \ --output .testerarmy/upload.json set-output upload_result "$(tr -d '\n' < .testerarmy/upload.json)" run_ios_tests: name: Run iOS TesterArmy tests needs: [upload_ios_app] environment: preview steps: - uses: eas/checkout - name: Run tests run: | set -euo pipefail APP_ID="${{ needs.upload_ios_app.outputs.app_id }}" COMMIT_SHA="${{ github.sha }}" EVENT_NAME="${{ github.event_name }}" PR_NUMBER="${{ github.event.pull_request.number || '' }}" TIMEOUT_MS="1800000" POLL_INTERVAL_SECONDS="10" mkdir -p .testerarmy args=( ci --group "$TESTERARMY_GROUP_ID" --project "$TESTERARMY_PROJECT_ID" --platform ios --app-id "$APP_ID" --commit-sha "$COMMIT_SHA" --timeout "$TIMEOUT_MS" --poll-interval-seconds "$POLL_INTERVAL_SECONDS" --output .testerarmy/ci-result.json --delete-app-after-run ) if [ "$EVENT_NAME" = "pull_request" ] && [ -n "$PR_NUMBER" ]; then args+=(--pr-number "$PR_NUMBER") fi npx --yes testerarmy@latest "${args[@]}" run_android_tests: name: Run Android TesterArmy tests needs: [upload_android_app] environment: preview steps: - uses: eas/checkout - name: Run tests run: | set -euo pipefail APP_ID="${{ needs.upload_android_app.outputs.app_id }}" COMMIT_SHA="${{ github.sha }}" EVENT_NAME="${{ github.event_name }}" PR_NUMBER="${{ github.event.pull_request.number || '' }}" TIMEOUT_MS="1800000" POLL_INTERVAL_SECONDS="10" mkdir -p .testerarmy args=( ci --group "$TESTERARMY_GROUP_ID" --project "$TESTERARMY_PROJECT_ID" --platform android --app-id "$APP_ID" --commit-sha "$COMMIT_SHA" --timeout "$TIMEOUT_MS" --poll-interval-seconds "$POLL_INTERVAL_SECONDS" --output .testerarmy/ci-result.json --delete-app-after-run ) if [ "$EVENT_NAME" = "pull_request" ] && [ -n "$PR_NUMBER" ]; then args+=(--pr-number "$PR_NUMBER") fi npx --yes testerarmy@latest "${args[@]}" ``` Use these command shapes: ```bash npx --yes testerarmy@latest upload-app \ --app-path "$APP_PATH" \ --project "$PROJECT_ID" \ --output .testerarmy/upload.json ``` ```bash npx --yes testerarmy@latest ci \ --group "$GROUP_ID" \ --project "$PROJECT_ID" \ --platform ios \ --app-id "$APP_ID" \ --commit-sha "$COMMIT_SHA" \ --timeout "$TIMEOUT_MS" \ --poll-interval-seconds "$POLL_INTERVAL_SECONDS" \ --output .testerarmy/ci-result.json ``` Use `--platform android` for Android test runs. If a PR number is available, append: ```bash --pr-number "$PR_NUMBER" ``` If cleanup is enabled, append: ```bash --delete-app-after-run ``` After editing: * Show the user which files changed. * Tell the user to configure `TESTERARMY_API_KEY`, `TESTERARMY_PROJECT_ID`, and `TESTERARMY_GROUP_ID` in their EAS environment. * Tell the user which EAS workflow command to run. * Do not run the real TesterArmy CLI or EAS build unless the user explicitly asks you to. Finish by summarizing the files changed and the manual test command.

Configure mobile build profiles

TesterArmy requires an iOS Simulator build profile and an Android APK build profile in EAS. Add the following snippet to your eas.json file:

eas.json
1{
2 "build": {
3 "testerarmy-ios-simulator": {
4 "ios": {
5 "simulator": true
6 }
7 },
8 "testerarmy-android-apk": {
9 "android": {
10 "buildType": "apk"
11 }
12 }
13 }
14}

For Android builds, make sure your Expo config has an Android package name, for example android.package in app.json.

Add the EAS workflow

Basic
Fingerprint + Repack

Here is an example workflow file that:

  1. Builds the iOS Simulator app and Android APK
  2. Uploads each app to TesterArmy
  3. Runs the saved test group once for iOS and once for Android
  4. Deletes each uploaded app from TesterArmy after the tests complete
.eas/workflows/testerarmy-mobile-tests.yml
1name: TesterArmy Mobile Tests
2
3on:
4 push:
5 branches:
6 - main
7 pull_request:
8 branches:
9 - main
10 workflow_dispatch: {}
11
12jobs:
13 build_ios:
14 name: Build iOS Simulator app
15 type: build
16 environment: preview
17 params:
18 platform: ios
19 profile: testerarmy-ios-simulator
20
21 build_android:
22 name: Build Android app
23 type: build
24 environment: preview
25 params:
26 platform: android
27 profile: testerarmy-android-apk
28
29 upload_ios_app:
30 name: Upload iOS app to TesterArmy
31 needs: [build_ios]
32 environment: preview
33 outputs:
34 app_id: ${{ fromJSON(steps.upload_app.outputs.upload_result).uploadedAppId }}
35 steps:
36 - uses: eas/checkout
37
38 - uses: eas/download_build
39 id: download_build
40 with:
41 build_id: ${{ needs.build_ios.outputs.build_id }}
42 extensions:
43 - app
44
45 - name: Upload app
46 id: upload_app
47 run: |
48 set -euo pipefail
49
50 APP_PATH="${{ steps.download_build.outputs.artifact_path }}"
51
52 mkdir -p .testerarmy
53
54 npx --yes testerarmy@latest upload-app \
55 --app-path "$APP_PATH" \
56 --project "$TESTERARMY_PROJECT_ID" \
57 --output .testerarmy/upload.json
58
59 set-output upload_result "$(tr -d '\n' < .testerarmy/upload.json)"
60
61 upload_android_app:
62 name: Upload Android app to TesterArmy
63 needs: [build_android]
64 environment: preview
65 outputs:
66 app_id: ${{ fromJSON(steps.upload_app.outputs.upload_result).uploadedAppId }}
67 steps:
68 - uses: eas/checkout
69
70 - uses: eas/download_build
71 id: download_build
72 with:
73 build_id: ${{ needs.build_android.outputs.build_id }}
74 extensions:
75 - apk
76
77 - name: Upload app
78 id: upload_app
79 run: |
80 set -euo pipefail
81
82 APP_PATH="${{ steps.download_build.outputs.artifact_path }}"
83
84 mkdir -p .testerarmy
85
86 npx --yes testerarmy@latest upload-app \
87 --app-path "$APP_PATH" \
88 --project "$TESTERARMY_PROJECT_ID" \
89 --output .testerarmy/upload.json
90
91 set-output upload_result "$(tr -d '\n' < .testerarmy/upload.json)"
92
93 run_ios_tests:
94 name: Run iOS TesterArmy tests
95 needs: [upload_ios_app]
96 environment: preview
97 steps:
98 - uses: eas/checkout
99
100 - name: Run tests
101 run: |
102 set -euo pipefail
103
104 APP_ID="${{ needs.upload_ios_app.outputs.app_id }}"
105 COMMIT_SHA="${{ github.sha }}"
106 EVENT_NAME="${{ github.event_name }}"
107 PR_NUMBER="${{ github.event.pull_request.number || '' }}"
108 TIMEOUT_MS="1800000"
109 POLL_INTERVAL_SECONDS="10"
110
111 mkdir -p .testerarmy
112
113 args=(
114 ci
115 --group "$TESTERARMY_GROUP_ID"
116 --project "$TESTERARMY_PROJECT_ID"
117 --platform ios
118 --app-id "$APP_ID"
119 --commit-sha "$COMMIT_SHA"
120 --timeout "$TIMEOUT_MS"
121 --poll-interval-seconds "$POLL_INTERVAL_SECONDS"
122 --output .testerarmy/ci-result.json
123 --delete-app-after-run
124 )
125
126 if [ "$EVENT_NAME" = "pull_request" ] && [ -n "$PR_NUMBER" ]; then
127 args+=(--pr-number "$PR_NUMBER")
128 fi
129
130 npx --yes testerarmy@latest "${args[@]}"
131
132 run_android_tests:
133 name: Run Android TesterArmy tests
134 needs: [upload_android_app]
135 environment: preview
136 steps:
137 - uses: eas/checkout
138
139 - name: Run tests
140 run: |
141 set -euo pipefail
142
143 APP_ID="${{ needs.upload_android_app.outputs.app_id }}"
144 COMMIT_SHA="${{ github.sha }}"
145 EVENT_NAME="${{ github.event_name }}"
146 PR_NUMBER="${{ github.event.pull_request.number || '' }}"
147 TIMEOUT_MS="1800000"
148 POLL_INTERVAL_SECONDS="10"
149
150 mkdir -p .testerarmy
151
152 args=(
153 ci
154 --group "$TESTERARMY_GROUP_ID"
155 --project "$TESTERARMY_PROJECT_ID"
156 --platform android
157 --app-id "$APP_ID"
158 --commit-sha "$COMMIT_SHA"
159 --timeout "$TIMEOUT_MS"
160 --poll-interval-seconds "$POLL_INTERVAL_SECONDS"
161 --output .testerarmy/ci-result.json
162 --delete-app-after-run
163 )
164
165 if [ "$EVENT_NAME" = "pull_request" ] && [ -n "$PR_NUMBER" ]; then
166 args+=(--pr-number "$PR_NUMBER")
167 fi
168
169 npx --yes testerarmy@latest "${args[@]}"

GitHub PR comments and checks

When your workflow is triggered by a pull request, TesterArmy will create a GitHub check and comment on the PR.

When workflow is triggered by a commit (eg. on push to main), TesterArmy will create a GitHub check on the commit.

To enable this, you need to configure your TesterArmy project with your GitHub repository. You can do it in Integrations Tab in project.

Example repository

You can find a working example repository here.

Troubleshooting

The build has an unsupported platform or format

TesterArmy requires an iOS Simulator .app build or Android .apk build. If you are using an iOS physical-device build, build a simulator app first. If you are using Android, make sure the EAS profile produces an APK, not an .aab.

Prefer release builds for CI, especially for Android runs that execute without a Metro dev server.

TesterArmy warns that GitHub integration is not configured / TesterArmy cannot create a PR comment

If you are seeing this error, it means that your TesterArmy project has no GitHub integration configured. You can configure it in Integrations Tab in project.

Related docs

  • App Uploads
  • GitHub Actions