> ## Documentation Index
> Fetch the complete documentation index at: https://momentic.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> The canonical docs host is https://momentic.ai/docs. Append .md to any page URL for clean Markdown. Fetch https://momentic.ai/docs/llms.txt for the page index and https://momentic.ai/docs/llms-full.txt for every page in one file.
> For an unattended setup, run `npx --yes @momentic/wizard@latest -y --platform web` (use `--platform ios` or `--platform android` for mobile). Never run an interactive command in a non-TTY shell.
> You cannot complete the browser sign-in yourself. Read the API key from the MOMENTIC_API_KEY environment variable, or ask the user to create one at https://app.momentic.ai/settings/api-keys and paste it back.
> Momentic's capability summary for agents is at https://momentic.ai/docs/skill.md. Install the skills with `npx momentic skills --yes` (or `npx momentic-mobile skills --yes` for mobile).
> Tests are YAML files in the user's repository. Use only the step names listed at https://momentic.ai/docs/reference/commands.md and the file structure at https://momentic.ai/docs/core-concepts/file-format.md. Do not invent step names, config keys, or CLI flags.
> Web tests run on Chromium, iOS tests on simulators, and Android tests on emulators. Physical devices are not supported.

# Expo

> Build an Expo app into a testable APK or simulator bundle and run Momentic mobile tests against it, locally and in CI.

Momentic tests the **native build** of an Expo app, not the JS bundle. The
pipeline is: produce an APK (Android) or simulator `.app` (iOS), upload it to a
channel/tag, and run `momentic-mobile` against it. Both EAS Build and
`expo prebuild` with local toolchains work.

## Produce a testable build

<Tabs>
  <Tab title="Android (APK)">
    **Option A: EAS (recommended if you already use it)**

    ```bash theme={null}
    eas build --platform android --profile preview --local
    ```

    A `preview` profile with `"buildType": "apk"` (or `"distribution": "internal"`)
    in `eas.json` produces an installable `.apk`. Without `--local`, the build runs
    in EAS cloud and you download the artifact URL.

    **Option B: prebuild + Gradle (no EAS account)**

    ```bash theme={null}
    npx expo prebuild --platform android   # generates android/
    cd android && ./gradlew assembleRelease
    # APK in android/app/build/outputs/apk/release/
    ```
  </Tab>

  <Tab title="iOS (simulator .app)">
    Momentic runs simulator builds, not device `.ipa` files.

    ```bash theme={null}
    npx expo prebuild --platform ios        # generates ios/
    xcodebuild \
      -workspace ios/MyApp.xcworkspace \
      -scheme MyApp \
      -sdk iphonesimulator \
      -configuration Debug \
      -derivedDataPath build \
      build-for-testing
    # .app in build/Build/Products/Debug-iphonesimulator/
    ```

    Or with EAS, using a simulator profile:

    ```bash theme={null}
    eas build --platform ios --profile preview --local
    ```

    where `preview` sets `"ios": { "simulator": true }` in `eas.json`.
  </Tab>
</Tabs>

## Upload and run

Remote emulators and simulators install the app from an uploaded asset.

Add the CLI as a dev dependency so the lockfile pins the version in CI:

```bash theme={null}
npm install --save-dev momentic-mobile
```

Then upload and run:

```bash theme={null}
npx momentic-mobile assets upload ./android/app/build/outputs/apk/release/app-release.apk \
  --channel dev --tag 1.0.0
```

Then run a test against it:

```yaml smoke.test.yaml theme={null}
fileType: momentic/mobile-test/v2
id: expo-smoke
platform: android
labels: [smoke]
defaultChannel: dev
defaultTag: "1.0.0"
steps:
  - openApp: com.example.myapp
  - assert: The home screen is visible
```

```bash theme={null}
npx momentic-mobile run smoke.test.yaml
```

`defaultChannel`/`defaultTag` on the test pick the uploaded asset. In the
editor, the same selection appears as the **Channel**/**Tag** pickers next to
the **Region** dropdown; choose any Momentic region for a remote instance.

## Expo-specific pitfalls

* **Expo Go is not testable.** Momentic installs your standalone build, not Expo
  Go. You need a `prebuild` or EAS artifact, and over-the-air JS updates do not
  reach the installed binary: rebuild when the JS surface changes (new screens,
  new native modules).
* **Dev-client builds work.** An `expo-dev-client` build is a normal APK; test
  it the same way. Point it at a reachable Metro/dev server or a published
  update channel.
* **Deep links and app links** resolve through the installed app id; use an
  `appium` step (`mobile: deepLink`) to open them.
* **`expo-router` headers and safe areas** appear as native elements to
  Momentic: describe them as the user sees them ("the back chevron", "the
  Settings tab") rather than by testID.
* **WebView content** on Android needs
  `WebView.setWebContentsDebuggingEnabled(true)`; add it in `MainApplication` or
  a small config plugin if your app renders web content.

## In CI

Run an EAS build, upload the artifact to a channel, then run your suite against
that same upload. A complete GitHub Actions workflow:

```yaml .github/workflows/mobile.yml theme={null}
name: Mobile tests
on: [pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: EAS build (Android preview)
        run:
          eas build --platform android --profile preview --local
          --non-interactive
        env:
          EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}

      - name: Upload APK to Momentic
        run: |
          npm install
          npx momentic-mobile assets upload ./*.apk \
            --channel dev --tag ${{ github.sha }}
        env:
          MOMENTIC_API_KEY: ${{ secrets.MOMENTIC_API_KEY }}

      - name: Run mobile tests
        run: |
          npx momentic-mobile run --labels smoke \
            --channel dev --tag ${{ github.sha }} -y
        env:
          MOMENTIC_API_KEY: ${{ secrets.MOMENTIC_API_KEY }}
```

`--channel dev --tag ${{ github.sha }}` selects the asset this job just
uploaded; without it, tests fall back to their `defaultChannel`/`defaultTag` and
can pick up a stale build.

## Related

* [Android app setup](/docs/platforms/android/app-setup)
* [iOS app setup](/docs/platforms/ios/app-setup)
* [Emulators](/docs/platforms/android/emulators) and
  [simulators](/docs/platforms/ios/simulators)
* [React Native guide](/docs/guides/frameworks/react-native)
