Skip to main content

The JavaScript client

It speaks to the same tool layer as the CLI and the MCP server, by spawning mobium pipe, so the mobium binary has to be on PATH or named by MOBIUM_BIN_PATH. The quick start goes from nothing to a running script.

Install​

git clone https://github.com/mobiumdev/mobium.git
npm install ./mobium/clients/javascript

Connect​

import { start } from 'mobium'

const device = await start({ platform: 'android', app: 'com.android.settings' })
for (const el of await device.map()) console.log(el.ref, el.label)
await device.quit()

device below is what start() or connect() resolved to: a Device. Every method returns a promise.

Every tool, by method​

MethodTool
accessibilityapp_accessibility
alert, answerAlertapp_alert
appearanceapp_appearance
auditapp_audit
backgroundapp_background
batchapp_batch
batteryapp_battery
biometricapp_biometric
bootapp_boot
incomingCallapp_call
checkapp_check
clearDataapp_clear_data
clipboard, setClipboardapp_clipboard
contextapp_context
contextsapp_contexts
clearCookies, cookies, setCookiesapp_cookies
crash, crashesapp_crashes
currentapp_current
devicesapp_devices
addDialogRule, clearDialogRules, dialogRulesapp_dialogs
doctorapp_doctor
download, downloads, pullPathapp_download
dragapp_drag
evalapp_eval
fillapp_fill
findapp_find
grantapp_grant
hitTestapp_hit_test
hookapp_hook
installapp_install
keyboardapp_keyboard
launchapp_launch
appsapp_list_apps
appLocale, setAppLocaleapp_locale
clearLocation, followGpx, followRoute, location, setLocationapp_location
screenLocked, setScreenLockedapp_lock
deviceLogs, logsapp_logs
longPressapp_long_press
map, mapDiffapp_map
network, resetNetwork, setOffline, shapeNetworkapp_network
notifications, postNotification, shadeapp_notifications
openUrlapp_open_url
orientation, setOrientationapp_orientation
back, pressapp_press
pressDragapp_press_drag
pressTapapp_press_tap
recordapp_record
resetPermissionsapp_reset_permissions
revokeapp_revoke
rotateapp_rotate
screenapp_screen
screenshotapp_screenshot
scrollToapp_scroll_to
quit, sessions, startapp_session
shakeapp_shake
shutdownapp_shutdown
smsapp_sms
sourceapp_source
appStateapp_state
clearStorage, setStorage, storageapp_storage
swipeapp_swipe
doubleTap, tapapp_tap
terminateapp_terminate
textapp_text
deviceTimeapp_time
timezoneapp_timezone
trace, traceStart, traceStopapp_trace
typeapp_type
uninstallapp_uninstall
pushPath, uploadapp_upload
waitForapp_wait_for
zoomapp_zoom

Connecting, ending, and errors​

start​

export function start(options?: StartOptions): Promise<Device>

Connect and open the session on the device. End it with quit().

Open a session on the one running device

import { start } from 'mobium'
const device = await start()
try {
console.log(device.session?.platform, device.session?.driver)
} finally {
await device.quit()
}

Pick the device and platform, and launch an app

import { start } from 'mobium'
const device = await start({ platform: 'ios', device: 'booted', app: 'com.apple.Preferences' })

connect​

export function connect(options?: ConnectOptions): Promise<Device>

Connect to mobium without touching the device. close() leaves the session open.

Connect without opening a session, and leave it open

import { connect } from 'mobium'
const device = await connect({ device: 'emulator-5554' })
console.log(await device.current())
await device.close()

Give each parallel run a daemon of its own

import { connect } from 'mobium'
const device = await connect({ device: 'emulator-5556', session: 'run2', callTimeoutMs: 60000 })

findBinary​

export function findBinary(explicit?: string): string

Locate the mobium binary: the explicit path, then MOBIUM_BIN_PATH, then PATH.

Find the mobium executable a connection would run

import { findBinary } from 'mobium'
console.log(findBinary()) // MOBIUM_BIN_PATH, else the first on PATH

errorFrom​

export function errorFrom(text: string, structured?: unknown): MobiumError

The exception for a failed tool call, from its text and structured content.

Turn a tool's error result into the matching exception

import { errorFrom, NoSuchElementError } from 'mobium'
const err = errorFrom('no element matches text=Sign in', { code: 'no_such_element', remedy: 'run app_map' })
console.log(err instanceof NoSuchElementError, err.remedy)

session​

session?: string
session: Session | null

A daemon of this connection's own, by name, as MOBIUM_SESSION sets one. One daemon serves one call at a time across every device, so parallel runs on different devices should each name one. Keep it short; it is part of a socket path.

See what start() opened

const { device: id, platform, driver, reused } = device.session ?? {}
console.log(id, platform, driver, reused)

sessions​

sessions(): Promise<{ device: string; platform: string; driver: string }[]>

The sessions open on the daemon.

List the sessions open on the daemon

for (const s of await device.sessions()) console.log(s.device, s.platform, s.driver)

quit​

quit(): Promise<void>

End the session on the device and close the connection. The app start() launched, if any, is stopped too.

End the session, whatever happens

try {
await device.tap('text=Network & internet')
} finally {
await device.quit()
}

close​

close(): Promise<void>

Close the connection; the session stays open. Resolves once mobium has exited.

Close the connection and keep the session for the CLI

await device.close()

MobiumError​

export class MobiumError extends Error

Decide by the error's code, never its message

import { MobiumError } from 'mobium'
try {
await device.tap('text=Sign in')
} catch (e) {
if (!(e instanceof MobiumError)) throw e
console.log(e.code, e.remedy, e.retryable, e.details)
}

NoSuchElementError​

export class NoSuchElementError extends MobiumError {}

Treat a missing element as an answer

import { NoSuchElementError } from 'mobium'
try {
await device.tap('text=Skip')
} catch (e) {
if (!(e instanceof NoSuchElementError)) throw e // no Skip button this time
}

TimedOutError​

export class TimedOutError extends MobiumError {}

Wait, and say what happened if it never came

import { TimedOutError } from 'mobium'
try {
await device.waitFor('text=Welcome back', { timeoutMs: 5000 })
} catch (e) {
if (e instanceof TimedOutError) console.log(e.message) // what was on screen instead
else throw e
}

UnsupportedError​

export class UnsupportedError extends MobiumError {}

Skip what a platform cannot do

import { UnsupportedError } from 'mobium'
try {
await device.press('back')
} catch (e) {
if (!(e instanceof UnsupportedError)) throw e
console.log(e.remedy) // iOS has no back button
}

Types​

TypeWhat it is
BoundsAn on-screen rectangle, in device pixels on both platforms.
ElementOne actionable thing on screen, from map() or find().
MapChangeOne element that is on both maps and differs between them, from mapDiff().
MapDiffWhat changed since the last map of this device, from mapDiff().
DeviceInfoOne attached device or simulator.
SessionWhat start() opened.
CookieOne of a page's cookies, with Vibium's keys.
StorageStateA page's cookies and web storage, in the shape Vibium saves.
PointA point in device pixels.
TraceWhat traceStart(), traceStop() and trace() resolve to.
DataA tool's structured answer, for the calls that return one as is.
BatchStepOne call in a batch: a tool and the arguments it takes on its own.
BatchStepResultOne step's answer in a batch.
ConnectOptions
StartOptions
WaitOptions
Device
MobiumError
NoDeviceError
DeviceNotReadyError
ToolchainMissingError
NoSuchElementError
AmbiguousLocatorError
ElementNotReachableError
NoSuchContextError
NoSuchAlertError
UnsupportedError
NotConfirmedError
TimedOutError
InvalidArgumentError
DeviceServerError
InternalError