dánwòdánwò

Platforms

iOS tests

Bind an iOS Simulator to the run, then run the same tests, agent steps, invariants and matrix as on Android.

An iOS test is the same file as an Android test. screen finds elements on the simulator's screen, expect waits for checks, and an invariant compares your backend with Stripe. danwo boots the simulator, routes its traffic through the proxy, and installs your build.

A test on a simulator

tests/buy-credits.danwo.ts
import type { DeviceFixtures } from "@danwo/device"
import { type StripeFixtures, test as base } from "@danwo/sdk"

const test = base.extend<StripeFixtures & DeviceFixtures>()

test("buys 500 credits", async ({ screen, expect, device }) => {
  await screen.getByTestId("buy").tap()

  /* Checkout opens in a Safari view; the same locators read the web page. */
  expect((await device.foreground()).browser).toBe(true)
  await screen.getByLabel("Email").fill("[email protected]")
  await screen.getByRole("button", { name: "Pay $5.00" }).tap()

  await expect(screen.getByTestId("credits")).toHaveText("Credits: 500")
})

getByTestId matches React Native's testID, which iOS reports as the accessibility identifier. A tap the keyboard covers, such as Pay under a field just filled, puts the keyboard away first. As on Android, a tap waits for its element to be enabled and finds it again on the latest screen.

Bind the simulator in the config

withIosDevice wraps your environment and binds a simulator to it:

danwo.config.ts · the device
return withIosDevice(environment, {
  worker: workerIndex,
  app: { bundleId: "com.danwo.shopmobile", app: build.app, scheme: "danwoshop" },
})

The full file, which runs on Android or iOS by DANWO_PLATFORM, is in examples/shop-mobile. For each worker, danwo:

  1. finds its simulator by name, or creates it, and boots it headless;
  2. trusts the run's certificate in the simulator's keychain;
  3. sets the simulator's own proxy to danwo's;
  4. installs the .app.
OptionWhat it does
namethe simulator's name; default danwo iPhone
runtimethe iOS to create it on: iOS 26.5, 26.5 or an identifier
deviceTypethe device to create: iPhone 17 Pro; default the newest iPhone Pro
udiduses a simulator that already exists, as it is
workergives each worker its own simulator: danwo iPhone 2, and so on
removedeletes a simulator this run created when it closes
app.launchArgsarguments the app is launched with
app.envenvironment the app is launched with
app.permissionssimctl privacy services to grant before each launch

Pass blocked: IOS_BACKGROUND_HOSTS from @danwo/device to your services. It blocks the simulator's own background traffic (Safari's safe browsing, Apple's services), so the matrix never faults it.

Run it

DANWO_PLATFORM=ios npx @danwo/cli test
  ✓ tests/agent-buy.danwo.ts › buys 500 credits when asked in plain words 35842 ms, worker 0
  ✓ tests/buy-credits.danwo.ts › buys 500 credits through Stripe Checkout in the in-app browser 11239 ms, worker 0

2 passed
cache: 3 replayed · 0 relocated · 0 handed off · 0 missed

Every attempt starts the app afresh: it is stopped, its data container emptied, and launched again. Agent steps record per platform, so steps recorded on Android don't replay on iOS: record them once on each.

What a test can do

FixtureOn iOS
screengetByTestId, getByLabel, getByText, getByRole (no headings); tap, fill
expectthe same checks as the web, including toHaveScreenshot
app.openopens a deep link; with no path, restarts the app
deviceforeground(), back(), openLink(url), logs(), swipe(), dismissKeyboard()
agentact, assert, extract, waitFor, with device tools

back() taps the screen's own back or close control, since an iPhone has no Back button. swipe() takes the same options as on Android.

Run the matrix on several simulators

iosWorkers picks a worker count from the Mac: a simulator takes about 2 GB and two cores.

DANWO_PLATFORM=ios npx @danwo/cli matrix tests/buy-credits.danwo.ts --workers 2

The example shop's matrix, on a 12-core, 32 GB Apple silicon Mac:

MatrixSimulatorsWall timeMedian trial
buy-credits, 23 runs1370 s13.4 s
agent-buy, 23 runs, replayed2298 s13.4 s

Next

On this page

Run it on every pull request

A GitHub check and one comment per pull request, with the flight records attached.

Set up CI