> ## 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.

# Flutter

> Build a Flutter 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 a Flutter app. The pipeline is: produce
an APK (Android) or simulator `.app` (iOS), upload it to a channel/tag, run
`momentic-mobile`. No Flutter-specific test tooling is involved. The app under
test is the same binary your users install.

## Produce a testable build

<Tabs>
  <Tab title="Android (APK)">
    ```bash theme={null}
    flutter build apk --release
    # APK in build/app/outputs/flutter-apk/app-release.apk
    ```

    `flutter build apk --debug` also works for local iteration.
  </Tab>

  <Tab title="iOS (simulator .app)">
    ```bash theme={null}
    flutter build ios --simulator
    # .app in build/ios/iphonesimulator/
    ```

    Builds must target the simulator. A device `.ipa` cannot run on a simulator and
    Momentic does not support physical devices.
  </Tab>
</Tabs>

## Upload and run

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 ./build/app/outputs/flutter-apk/app-release.apk \
  --channel dev --tag 1.0.0
```

```yaml smoke.test.yaml theme={null}
fileType: momentic/mobile-test/v2
id: flutter-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
```

## Flutter pitfalls

* **Semantics drive what Momentic sees.** Momentic reads the native
  accessibility tree. Flutter renders everything on a canvas, so elements are
  only visible to the tester when they produce semantics nodes. Most Material
  and Cupertino widgets do this automatically; custom `CustomPainter` content
  and decorative widgets may need `Semantics` wrappers or `excludeSemantics`
  tuning. If a check cannot find a control the user can see, the widget tree is
  missing semantics.
* **`Key` values do not reach the accessibility tree.**
  `ValueKey('login-button')` is invisible to Momentic; keys exist for Flutter's
  own finder APIs. For a stable hook, wrap the widget in `Semantics(label:)` or
  give it a `tooltip`. Prefer natural-language targets so tests survive renames.
* **Splash and async init.** A Flutter app often shows a splash while `main()`
  awaits. Rather than a fixed `wait`, assert on the first real screen:
  `assert: The home screen is visible` with a `timeout`.
* **DevTools/`--dart-define` config** does not reach the installed binary. Embed
  test config via `--dart-define` at build time so the shipped artifact carries
  it.
* **Impeller vs. Skia rendering** does not change what the accessibility tree
  exposes; either engine works.
* **WebView content** on Android needs
  `WebView.setWebContentsDebuggingEnabled(true)`.

## In CI

```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: Set up Flutter
        uses: subosito/flutter-action@v2
        with:
          channel: stable

      - name: Build APK
        run: flutter build apk --release

      - name: Upload APK to Momentic
        run: |
          npm install
          npx momentic-mobile assets upload ./build/app/outputs/flutter-apk/app-release.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`/`--tag` on `run` select the asset this job just uploaded. iOS builds
need `runs-on: macos-latest` with `flutter build ios --simulator` before the
upload step.

## 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)
