Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
node_modules
.git
dist
*.log
coverage
playwright-report
test-results
.env
docs/superpowers
.DS_Store
*.tsbuildinfo
19 changes: 19 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,22 @@ jobs:
- run: npm run build
- run: npm run lint
- run: npm test

docker:
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
runner: ubuntu-24.04
- arch: arm64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
permissions:
contents: read
steps:
- uses: actions/checkout@v5
- name: Build image
run: docker build -t mobilewright:ci .
- name: Smoke test
run: docker run --rm mobilewright:ci help
115 changes: 115 additions & 0 deletions .github/workflows/ghcr-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
name: Publish Docker Image

on:
workflow_run:
workflows: ["Publish to npm"]
types:
- completed

jobs:
build-amd64:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v5
with:
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0
- uses: docker/login-action@v3

Check failure

Code scanning / CodeQL

Checkout of untrusted code in a privileged context High

Checkout of untrusted code in a privileged workflow with later potential execution (event trigger:
workflow_run
).
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Comment on lines +17 to +21
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set version
id: version
run: |
TAG=$(git describe --tags --exact-match ${{ github.event.workflow_run.head_sha }})
echo "value=${TAG#v}" >> $GITHUB_OUTPUT
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v6
with:
context: .
push: true
provenance: false
platforms: linux/amd64
tags: ghcr.io/mobile-next/mobilewright:${{ steps.version.outputs.value }}-amd64
build-args: MOBILEWRIGHT_VERSION=${{ steps.version.outputs.value }}

build-arm64:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-24.04-arm
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v5
with:
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0
- uses: docker/login-action@v3

Check failure

Code scanning / CodeQL

Checkout of untrusted code in a privileged context High

Checkout of untrusted code in a privileged workflow with later potential execution (event trigger:
workflow_run
).
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Comment on lines +48 to +52
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set version
id: version
run: |
TAG=$(git describe --tags --exact-match ${{ github.event.workflow_run.head_sha }})
echo "value=${TAG#v}" >> $GITHUB_OUTPUT
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v6
with:
context: .
push: true
provenance: false
platforms: linux/arm64
tags: ghcr.io/mobile-next/mobilewright:${{ steps.version.outputs.value }}-arm64
build-args: MOBILEWRIGHT_VERSION=${{ steps.version.outputs.value }}

manifest:
runs-on: ubuntu-24.04
needs: [build-amd64, build-arm64]
permissions:
contents: read
packages: write
id-token: write
attestations: write
steps:
- uses: actions/checkout@v5
with:
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0
- uses: docker/login-action@v3

Check failure

Code scanning / CodeQL

Checkout of untrusted code in a privileged context High

Checkout of untrusted code in a privileged workflow with later potential execution (event trigger:
workflow_run
).
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Comment on lines +81 to +85
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set version
id: version
run: |
TAG=$(git describe --tags --exact-match ${{ github.event.workflow_run.head_sha }})
echo "value=${TAG#v}" >> $GITHUB_OUTPUT
- uses: docker/setup-buildx-action@v3
- name: Create and push multi-arch manifest
run: |
VERSION=${{ steps.version.outputs.value }}
IMAGE=ghcr.io/mobile-next/mobilewright
docker buildx imagetools create \
--tag "${IMAGE}:${VERSION}" \
--tag "${IMAGE}:latest" \
"${IMAGE}:${VERSION}-amd64" \
"${IMAGE}:${VERSION}-arm64"
- name: Resolve manifest digest
id: digest
run: |
IMAGE=ghcr.io/mobile-next/mobilewright
DIGEST=$(docker buildx imagetools inspect "${IMAGE}:${{ steps.version.outputs.value }}" --format '{{.Manifest.Digest}}')
echo "value=${DIGEST}" >> $GITHUB_OUTPUT
- uses: actions/attest-build-provenance@v2
with:
subject-name: ghcr.io/mobile-next/mobilewright
subject-digest: ${{ steps.digest.outputs.value }}
push-to-registry: true
43 changes: 43 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
FROM ubuntu:jammy

ARG DEBIAN_FRONTEND=noninteractive
ARG TZ=America/Los_Angeles
ARG NODE_VERSION=24
ARG MOBILEWRIGHT_VERSION=latest

ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8

# Install base deps, Node.js, and ADB client in a single layer
RUN apt-get update && \
apt-get install -y --no-install-recommends curl gpg ca-certificates && \
mkdir -p /etc/apt/keyrings && \
curl -sL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_VERSION}.x nodistro main" >> /etc/apt/sources.list.d/nodesource.list && \
apt-get update && \
apt-get install -y --no-install-recommends nodejs android-tools-adb && \
rm -rf /var/lib/apt/lists/*

# Point ADB client at the host's ADB server.
# host.docker.internal resolves natively on macOS/Windows Docker Desktop.
# On Linux, pass --add-host=host.docker.internal:host-gateway to docker run.
ENV ANDROID_ADB_SERVER_HOST=host.docker.internal
ENV ANDROID_ADB_SERVER_PORT=5037

# ADB does not natively read ANDROID_ADB_SERVER_HOST. This wrapper injects
# -H/-P so every adb call (doctor, mobilecli, etc.) reaches the host's server.
RUN printf '#!/bin/sh\nexec /usr/bin/adb -H "${ANDROID_ADB_SERVER_HOST:-127.0.0.1}" -P "${ANDROID_ADB_SERVER_PORT:-5037}" "$@"\n' \
> /usr/local/bin/adb && chmod +x /usr/local/bin/adb

# Install mobilewright CLI globally (mobilecli binaries for all arches are
# bundled inside the mobilecli npm package — no optionalDependencies needed)
RUN npm install -g mobilewright@${MOBILEWRIGHT_VERSION} && \
npm cache clean --force

# Non-root user (activated, unlike Playwright which only creates pwuser)
RUN adduser --disabled-password --gecos "" mwuser

USER mwuser
WORKDIR /home/mwuser

ENTRYPOINT ["mobilewright"]
157 changes: 157 additions & 0 deletions docs/src/guides/docker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
---
sidebar_position: 4
title: Docker
---

# Docker

The `ghcr.io/mobile-next/mobilewright` Docker image runs `mobilewright` commands inside a container — without installing Node.js or the Android SDK on your machine. It works two ways:

- **Local Android emulator** — connects to an emulator running on your host via ADB.
- **Cloud devices** — connects to real Android and iOS devices on [Mobile Next Cloud](https://mobilenext.ai).

The container runs Linux and cannot reach an iOS simulator running on your Mac host. To test iOS, use cloud devices.

## Local Android emulator

The image ships the ADB client and points it at the ADB server running on your host, so an emulator started on your machine is visible inside the container.

### Run `doctor`

Use `doctor` to verify the container can reach your host's ADB server.

#### macOS and Windows

`host.docker.internal` resolves automatically in Docker Desktop — no extra flags needed:

```bash
docker run --rm ghcr.io/mobile-next/mobilewright doctor
```

#### Linux

Pass `--add-host` so `host.docker.internal` resolves to the host gateway:

```bash
docker run --rm \
--add-host=host.docker.internal:host-gateway \
ghcr.io/mobile-next/mobilewright doctor
```

#### Expected output

All Android checks pass as long as your host ADB server is running and an emulator is connected.

```
mobilewright doctor v0.0.x
────────────────────────────────────────────────────────────

System
✓ Node.js v24.x.x
✓ npm x.x.x
✓ mobilecli mobilecli version x.x.x
✓ mobilecli devices 1 online device
emulator-5554

Android
✓ ADB (Android Debug Bridge) 1.0.41
```

### Run tests

Mount your project directory into the container at `/home/mwuser` and run `mobilewright test`.

#### macOS and Windows

```bash
docker run --rm \
-v "$(pwd):/home/mwuser" \
ghcr.io/mobile-next/mobilewright test
```

#### Linux

```bash
docker run --rm \
--add-host=host.docker.internal:host-gateway \
-v "$(pwd):/home/mwuser" \
ghcr.io/mobile-next/mobilewright test
```

Test results, screenshots, and other output are written to the mounted directory and remain available after the container exits.

### Capture a screenshot

Mount your current directory so the output file lands on the host. The screenshot is written to `--output` relative to the working directory (`/home/mwuser`), which maps directly to your mounted path.

#### macOS and Windows

```bash
docker run --rm \
-v "$(pwd):/home/mwuser" \
ghcr.io/mobile-next/mobilewright screenshot
# → screenshot.png appears in the current directory
```

#### Linux

```bash
docker run --rm \
--add-host=host.docker.internal:host-gateway \
-v "$(pwd):/home/mwuser" \
ghcr.io/mobile-next/mobilewright screenshot
```

Use `--output` to specify a different filename:

```bash
docker run --rm \
-v "$(pwd):/home/mwuser" \
ghcr.io/mobile-next/mobilewright screenshot --output before-login.png
```

## Cloud devices

[Mobile Next Cloud](https://mobilenext.ai) gives the container access to real Android and iOS devices over the network. No host ADB server, emulator, or `--add-host` flag is needed, and the commands are identical on macOS, Windows, and Linux.

### Configure the cloud driver

Point your `mobilewright.config.ts` at the cloud driver. Read the API key from an environment variable so it is never committed:

```ts
import { defineConfig } from 'mobilewright';

export default defineConfig({
platform: 'ios', // or 'android'
driver: {
type: 'mobile-use',
apiKey: process.env.MOBILE_USE_API_KEY,
},
});
```

### Run tests

Mount your project and pass the API key with `-e`:

```bash
docker run --rm \
-v "$(pwd):/home/mwuser" \
-e MOBILE_USE_API_KEY="$MOBILE_USE_API_KEY" \
ghcr.io/mobile-next/mobilewright test
```

This works for both Android and iOS — the devices run in the cloud, so nothing else is required on the host.

## Volume and environment reference

| Option | Purpose |
|--------|---------|
| `-v "$(pwd):/home/mwuser"` | Mount your project so config, tests, and output are accessible on the host |
| `--add-host=host.docker.internal:host-gateway` | Local Android on Linux only — makes the host reachable as `host.docker.internal` |
| `-e MOBILE_USE_API_KEY=…` | Cloud devices only — authenticates with Mobile Next Cloud |

## Limitations

- **No local iOS simulator.** The container runs Linux and cannot reach an iOS simulator running on your Mac host. Test iOS against [cloud devices](#cloud-devices), or run directly on macOS with `npx mobilewright test`.
- **`screenshot` is local-only.** The `mobilewright screenshot` command always uses the local ADB driver and cannot capture Mobile Next Cloud devices. Capture cloud-device screenshots from within a test run instead.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.