A mobile UI test automation project built on Mobilewright — a Playwright-style testing framework for real iOS and Android apps. If you already know Playwright, you already know most of this: screen.getByText(...), .tap(), expect(...).toBeVisible() — the same mental model, pointed at a phone instead of a browser tab.
This repository is a ready-to-run starter: install it, plug in a device, and run the included example test against a real app.
▸ Node.js test → Mobilewright → mobilecli → DeviceKit → your phone
New to the codebase? Jump to How It Works for two diagrams that trace a single
tap()call all the way from your test file to a finger touching the glass.
- What You Need
- 1. Install the Project
- 2. Connect a Physical Device
- 3. Configure Your Test
- 4. Write a Test
- 5. Run It
- CLI Cheat Sheet
- Troubleshooting
- How It Works, Under the Hood
- Project Structure
- Resources
| Requirement | macOS | Windows |
|---|---|---|
| Node.js 18 or newer | ✔ | ✔ |
| Android device or emulator | ✔ | ✔ |
| iOS device or simulator | ✔ | ✘ (Apple's tooling is Mac-only — see iOS section) |
| Xcode (for iOS) | ✔ | — |
Android SDK Platform-Tools (adb) |
✔ | ✔ |
You do not need to install mobilecli yourself — it ships as a dependency and Mobilewright starts it automatically the first time you run a test.
git clone <this-repo-url>
cd Mobilewright
npm installThat pulls in the two packages this project actually depends on:
| Package | Role |
|---|---|
mobilewright |
The CLI, config loader, and device orchestration |
@mobilewright/test |
Playwright Test fixtures (test, expect, screen, device) |
Mobilewright can also drive simulators/emulators with zero setup, but here's how to get a real, physical phone talking to your laptop — the most common source of first-time friction.
- Install the Android platform tools (gives you
adb):- macOS:
brew install --cask android-platform-tools - Windows: download the SDK Platform-Tools and add the folder to your
PATH, or install Android Studio (which includes them).
- macOS:
- Enable Developer Options on the phone: Settings → About phone → tap "Build number" 7 times.
- Enable USB debugging: Settings → Developer options → toggle "USB debugging" on.
- Plug the phone into your computer with a USB cable.
- Authorize the RSA key prompt that appears on the phone's screen ("Allow USB debugging?") — tick "Always allow from this computer" and tap Allow.
- Verify the connection:
You should see your device listed with
adb devices
device(notunauthorizedoroffline) next to its ID.
That's it — no extra agent is required for standard taps, swipes, and text input on Android. Mobilewright will only install a small helper agent automatically if your test needs to type non-Latin text (e.g. Japanese, Arabic, emoji), since plain adb can't do that.
Apple's device tooling (Xcode, code signing, usbmuxd) only runs on macOS, so iOS automation — simulator or real device — requires a Mac. Windows and Linux users can automate Android from this same project, but not iOS.
- Install Xcode from the Mac App Store, then the Command Line Tools:
xcode-select --install
- Plug the iPhone into your Mac with a cable and tap "Trust This Computer" on the phone when prompted.
- Real devices only — install the on-device agent (called DeviceKit). It's what actually taps the screen and reads the accessibility tree, since Apple gives no other way in:
You'll need a valid Apple provisioning profile for your own Apple Developer account with your device's UDID registered, so Xcode can re-sign the agent for your phone. (Simulators skip this step entirely — the agent installs automatically the first time you connect.)
npx mobilewright devices # find your device's ID npx mobilewright install --device <id> --provisioning-profile /path/to/profile.mobileprovision
- Verify the agent is installed:
npx mobilecli agent status --device <id>
Before running a real test, let Mobilewright audit your whole environment in one shot:
npx mobilewright doctorIt checks Node, mobilecli, connected devices, and — depending on your OS — Xcode/Simulators (macOS) or Java/ANDROID_HOME/adb/emulator/Hyper-V and Windows Defender exclusions (Windows), and tells you exactly what's missing and the command to fix it. Add --json for machine-readable output, or --category android / --category ios to check just one platform.
Test-run behavior lives in mobilewright.config.ts, already set up in this project:
import { defineConfig } from 'mobilewright';
export default defineConfig({
platform: 'android',
bundleId: 'com.lambdatest.proverbial',
installApps: './proverbial_android.apk',
timeout: 30_000,
});The options you'll touch most often:
| Option | What it does |
|---|---|
platform |
'ios' or 'android' |
bundleId |
Your app's package name (Android) or bundle identifier (iOS) |
installApps |
Local path to the .apk / .ipa / .zip to install before the test runs |
deviceName |
A regex to target a specific simulator/emulator/device by name |
deviceId |
An exact device ID, if you don't want auto-discovery |
timeout |
Per-test timeout, in milliseconds |
use.actionTimeout |
How long a single action (tap, fill, …) waits before giving up |
expect.timeout |
How long expect(...) assertions poll before failing |
Swap platform: 'android' for 'ios' and point installApps at a .ipa (real device) or a zipped .app bundle (simulator) to target iOS instead.
example.test.ts is already here and shows the core API:
import { test, expect } from '@mobilewright/test';
test('app launches and verifies home screen', async ({ screen }) => {
const colorElement = screen.getByText('COLOR');
await expect(colorElement).toBeVisible();
await colorElement.tap();
const continueBtn = screen.getByRole('button', { name: 'GEOLOCATION' });
await continueBtn.tap();
const emailInput = screen.getByTestId('com.lambdatest.proverbial:id/url');
await emailInput.fill('https://whatismyipaddress.com/');
});A few things worth knowing as you write your own:
screen.getByText(),getByRole(),getByLabel(),getByTestId()— the same semantic locators Playwright uses for the web, aimed at native elements here.- Every action auto-waits: Mobilewright keeps polling until the element exists, is visible, and has stopped moving — no manual
sleep()calls. expect(locator).toBeVisible()(and friends) poll the same way, until they pass or time out.
npx mobilewright testUseful flags:
npx mobilewright test --grep "home screen" # run only matching tests
npx mobilewright test --workers 2 # run across 2 parallel devices
npx mobilewright test --reporter html # generate an HTML report
npx mobilewright test --list # list tests without running them
npx mobilewright show-report # open the last HTML report| Command | Purpose |
|---|---|
npx mobilewright doctor |
Audit your environment; explains exactly what to fix |
npx mobilewright devices |
List connected devices, simulators, and emulators |
npx mobilewright install --device <id> |
Install the on-device agent (DeviceKit) |
npx mobilewright screenshot --device <id> |
Grab a screenshot from a connected device |
npx mobilewright inspect |
Open a live, visual locator browser in your browser |
npx mobilewright test |
Run your test suite |
npx mobilewright show-report |
View the last HTML report |
npx mobilewright init |
Scaffold a fresh mobilewright.config.ts + example test |
| Symptom | Likely fix |
|---|---|
adb devices shows nothing |
USB debugging isn't enabled, or you haven't accepted the "Allow USB debugging?" prompt on the phone. Unplug, replug, and check the phone's screen. |
adb devices shows unauthorized |
Reject and reconnect — the authorization prompt was dismissed or timed out. |
| "No online devices found" from Mobilewright | Run npx mobilewright devices first — the device must show state: online. |
| iOS: "agent not installed" | Real devices need npx mobilewright install --device <id> --provisioning-profile ... with a profile that covers that device's UDID. |
| iOS steps fail on Windows/Linux | Expected — iOS automation requires a Mac with Xcode. Only Android is available on Windows/Linux. |
| Android emulator won't boot on Windows | Run npx mobilewright doctor — it flags missing Windows Hypervisor Platform or a Windows Defender exclusion for the SDK folder, both of which slow or block emulators. |
| Test times out finding an element | Increase use.actionTimeout / expect.timeout in mobilewright.config.ts, or double-check the locator with npx mobilewright inspect. |
Two diagrams live in this repo, tracing the exact same call — screen.getByText('COLOR').tap() — at two levels of depth. Both were generated directly from this project's own node_modules, not from documentation elsewhere.
The full picture — from your TypeScript test, through the orchestrator and automation engine, to a fork between running locally (mobilecli + on-device DeviceKit) or in LambdaTest's device cloud:
The deep, local dive — exactly what happens on a wire and on a chip: the JSON-RPC message your test sends, how mobilecli routes it over ADB/usbmuxd, and how DeviceKit reads the OS accessibility tree to find and physically touch the right pixel:
Mobilewright/
├── mobilewright.config.ts # test-run configuration
├── example.test.ts # sample test using @mobilewright/test
├── mobilewright-architecture.png # full framework architecture (svg alongside it)
├── mobilewright-local-execution.png# deep local-execution trace (svg alongside it)
├── package.json
└── test-results/ # generated on test runs
- mobilewright.dev — official docs
- github.com/mobile-next/mobilewright — framework source
- github.com/mobile-next/mobilecli — the local device-automation binary
- LambdaTest / Mobile Next Cloud — run the same tests against real devices in the cloud, no local device required

