The generated reference for the simgadget package: every exported function,
class, interface and type alias, with its full type and the documentation
written beside it in the source. It is rebuilt from src/index.ts on each
deploy.
src/index.ts is also the package's only entry point. The exports map in
package.json resolves that module and nothing else, so a path such as
simgadget/build/idb/client.js does not resolve regardless of the file layout.
Anything absent from this reference cannot be imported.
An introduction in prose is at simgadget.dev/library.html. To drive simulators from an AI agent rather than from code, see simgadget-mcp.
import { createSimulator } from "simgadget";
// Creates on the latest installed iOS runtime and waits until the device is
// actually driveable — `simctl boot` returns a minute before accessibility
// answers. Does not throw on a slow boot; ask the handle how it went.
const sim = await createSimulator({ deviceType: "iPhone 16 Pro" });
console.log(sim.udid, sim.lastBoot); // { ready: true, waitedMs: 41000, ... }
await sim.installApp("./build/MyApp.app");
await sim.launchApp("com.example.myapp"); // -> { pid: 18900 }
// Resolve the element, refuse it if disabled or covered, then touch it.
const result = await sim.tap({ label: "Sign Up" });
// { acted: "touch", x: 201, y: 442, count: 1, durationSeconds: 0.1, element: {...} }
await sim.tap({ label: "Email" });
await sim.typeText("test@example.com");
// null is the ordinary "not on screen" answer, not an error.
const banner = await sim.findByLabel("Welcome back");
await sim.screenshot({ path: "/tmp/signup.png" });
await sim.delete();
CommonJS works the same way:
const { createSimulator } = require("simgadget").
Nothing in the library deletes a simulator except a delete() written by the
caller.
Three functions return a Simulator:
createSimulator(opts?) creates a device on the newest installed iOS runtime
and, by default, boots it and waits until accessibility answers. It does not
throw when that wait runs out; read sim.lastBoot for the outcome.attachSimulator(udid) adopts a simulator that already exists. It checks the
device is present. It does not boot it or probe it; call waitReady() if it
needs to be driveable.listSimulators() reports every simulator simctl knows about, without
creating or attaching anything.The rest of the API is on Simulator: reads (describeScreen, findByLabel,
findByIdentifier, describePoint, screenSize), actions (tap, typeText,
swipe, pressButton), lifecycle (boot, waitReady, shutdown, delete),
apps (installApp, launchApp), orientation (rotate, detectOrientation)
and capture (screenshot, startRecording, stopRecording).
The fourth exported function, prefetchCompanion, returns the path to the
pinned idb_companion binary, downloading it if the cache is cold. The
simgadget prefetch command does the same from a shell.
These apply throughout the API, and none of them is visible in the types.
Arguments to tap, swipe and describePoint, and the frames inside every
AXElement, are logical points in the orientation the interface is currently
displaying. This is the space the accessibility tree reports, and the space
visible on screen.
The companion requires portrait-space coordinates. tap, swipe and
describePoint convert to portrait on the way in and back on the way out, so a
landscape tap at (162, 352) is reported as (162, 352).
Screenshots are the exception. simctl captures in physical portrait whatever
the rotation, so screenshot() rotates the image to match the interface and
reports the orientation it matched. The image is measured in pixels, not
points; pass resizeTo: "points" to compare it against coordinates.
An action reports what happened, not what was asked for. tap returns the
element it resolved, which kind of action it performed (acted) and, for a
toggle, the state read back afterwards. rotate returns the orientation the
interface adopted, which is not always the one requested. Applications decline
orientations, and no Face ID iPhone adopts upside_down.
swipe and typeText return void. The companion acknowledges both and
reports nothing further, so there is no outcome to return.
findByLabel, findByIdentifier and describePoint return null when the
lookup finds nothing. A miss is an ordinary result.
An action that cannot proceed without the element throws instead. tap({label})
checks the touch will reach the element before sending it, so a control that is
covered, disabled or scrolled out of view produces an error rather than a touch
that lands nowhere.
Every error extends SimGadgetError and carries a code from the ErrorCode
union. Subclasses add a payload where there is one to inspect:
DeviceTypeNotFoundError carries the list of available device types,
TapObstructedError carries the obstructing element, UntypeableTextError
carries the offending characters.
Branch on code, not on the message. Messages name no tool, URL or remediation
specific to a caller, and can change between releases.
macOS on Apple Silicon: iOS simulators are macOS-only and the pinned companion is arm64-only. Xcode with at least one iOS runtime installed. Node.js 18 or newer.
idb and idb_companion do not need to be installed. The package resolves a
pinned, checksum-verified companion build and caches it under
~/Library/Caches/simgadget.