> ## Documentation Index
> Fetch the complete documentation index at: https://qawolf-mktg-5213-self-service-faq-page.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# iOS Reference

> Reference notes for @qawolf/flows/ios.

`@qawolf/flows/ios` defines iOS flows and advanced simulator or device control.

## Primary Exports

* `flow(...)`
* `launch(...)`
* `device`
* `expect`
* `testContextDependencies`

It also exports iOS-specific target, launch, device, callback context, and flow definition types.

Example:

```ts theme={null}
import { device, flow } from "@qawolf/flows/ios";

const profile = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict></dict></plist>`;

export default flow(
  "Open iOS app",
  { target: "iOS - iPhone 15 (iOS 26)", launch: true },
  async ({ driver, test }) => {
    await test("install profile", async () => {
      await driver.pause(1000);
      await device.installConfigurationProfile(driver, profile);
    });
  },
);
```

## Flow Callback Context

All iOS flow callbacks receive:

* `inputs`
* `setOutput(...)`
* `test(...)`

Launch-enabled iOS flows also receive `driver`.

<Note>
  `test(...)` can be omitted for simple flows where grouping steps into named sub-steps doesn't add value. For most flows, wrapping steps in `test(...)` is recommended — the label appears in your results and makes failures easier to locate.
</Note>

## `testContextDependencies`

`testContextDependencies` is exported for runner and tooling integration. Flow authors should usually use the public callback parameters above instead of depending on the raw runner dependency list.

## Target Model

The current target input model is:

```ts theme={null}
type IosFlowTargetInput =
  | IosFlowTarget
  | {
      target: IosFlowTarget;
      launch?: false | undefined;
    }
  | {
      target: IosFlowTarget;
      launch: true | LaunchOptions;
    };
```

The implementation accepts either:

* a target directly for the common path
* `{ target, launch }` when startup behavior should be part of the flow

Example:

```ts theme={null}
import { flow } from "@qawolf/flows/ios";

export const targetOnlyFlow = flow(
  "Target-only path",
  "iOS - iPhone 15 (iOS 26)",
  async () => {
    // call launch() explicitly when startup should happen in the callback
  },
);

export const launchedFlow = flow(
  "Launch-enabled path",
  { target: "iOS - iPhone 15 (iOS 26)", launch: true },
  async ({ driver, test }) => {
    await test("launch app", async () => {
      await driver.pause(1000);
    });
  },
);
```

## `flow(...)`

Use `flow(...)` for iOS authoring.

Behavior from the implementation:

* without launch, the callback receives `inputs`, `setOutput(...)`, and `test(...)`
* with `launch: true`, the flow calls `launch()` with default iOS startup
* with `launch: <options>`, the flow calls `launch(options)`
* when launch is enabled, the callback also receives `driver`

Example:

```ts theme={null}
import { flow } from "@qawolf/flows/ios";

export default flow(
  "Launch in flow definition",
  { target: "iOS - iPhone 15 (iOS 26)", launch: true },
  async ({ driver, test }) => {
    await test("launch app", async () => {
      await driver.pause(1000);
    });
  },
);
```

## `launch(...)`

`launch()` starts iOS automation for the active flow and returns:

```ts theme={null}
type LaunchResult = {
  driver: Awaited<ReturnType<Dependencies["wdio"]["startIos"]>>;
};
```

This API is only available while a flow is running.

Example:

```ts theme={null}
import { flow, launch } from "@qawolf/flows/ios";

export default flow(
  "Launch explicitly",
  "iOS - iPhone 15 (iOS 26)",
  async () => {
    const { driver } = await launch();
    await driver.pause(1000);
  },
);
```

### Launch Shape

```ts theme={null}
type LaunchOptions = {
  app?: {
    path?: string;
    env?: string;
    url?: string;
  };
  autoAcceptAlerts?: boolean;
  autoDismissAlerts?: boolean;
  browserName?: string;
  bundleId?: string;
  capabilities?: Record<string, unknown>;
  noReset?: boolean;
  platformVersion?: string;
  respectSystemAlerts?: boolean;
  snapshotMaxDepth?: number;
  udid?: string;
  waitForIdleTimeout?: number;
  webDriverAgentUrl?: string;
};
```

Example:

```ts theme={null}
import { flow, launch } from "@qawolf/flows/ios";

export default flow(
  "Launch app bundle",
  "iOS - iPhone 15 (iOS 26)",
  async () => {
    const { driver } = await launch({
      app: { path: "ios/MyApp.app" },
      bundleId: "com.example.ios",
      snapshotMaxDepth: 500,
    });

    await driver.pause(1000);
  },
);
```

### Launch Defaults

The current implementation applies these defaults:

* when `app` is omitted, launch falls back to the runner-provided executable input path and then to installed-app startup through `bundleId`
* `respectSystemAlerts` defaults to `true`
* `snapshotMaxDepth` defaults to `999`
* `noReset` defaults to `false`

Example:

```ts theme={null}
import { flow, launch } from "@qawolf/flows/ios";

export default flow(
  "Use iOS defaults",
  "iOS - iPhone 15 (iOS 26)",
  async () => {
    const { driver } = await launch({
      bundleId: "com.example.ios",
    });

    await driver.pause(1000);
  },
);
```

### App Resolution

When your CI pipeline uploads an iOS build, QA Wolf sets `RUN_INPUT_PATH` to the uploaded file before the flow runs. Omit `app` in your launch call and QA Wolf will use that path automatically — you only need to provide the `bundleId`.

When `app` is provided, the current resolution order is:

1. `app.path`
2. `app.env`
3. `app.url`

When `app` is omitted, launch falls back to `RUN_INPUT_PATH`.

Relative paths are resolved against `RUN_INPUTS_EXECUTABLES_DIR` when that environment variable is present.

Explicit app source examples:

```ts theme={null}
await launch({ app: { path: "ios/MyApp.app" } });
await launch({ app: { env: "IOS_APP_PATH" } });
await launch({ app: { url: "https://example.com/MyApp.zip" } });
```

`RUN_INPUT_PATH` fallback example:

```ts theme={null}
// The runner sets RUN_INPUT_PATH before the flow starts.
await launch({
  bundleId: "com.example.ios",
});
```

<Note>
  If `app` is present but does not resolve to a value, launch does not fall back to `RUN_INPUT_PATH`.
</Note>

## `device`

`device` is a runtime proxy over the iOS simulator or device API. Use it for device-level operations — such as installing configuration profiles, simulating sensors, or managing device state — that sit outside app UI interactions. Use `driver` for interacting with the app itself.

Example:

```ts theme={null}
import { device, flow, launch } from "@qawolf/flows/ios";

const profile = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict></dict></plist>`;

export default flow("Install profile", "iOS - iPhone 15 (iOS 26)", async () => {
  const { driver } = await launch();
  await device.installConfigurationProfile(driver, profile);
});
```

## `expect`

The exported `expect` value is a type-safe stub in package code and is replaced by the runner during execution.

Example:

```ts theme={null}
import { expect, flow } from "@qawolf/flows/ios";

export default flow(
  "Use runner expect",
  { target: "iOS - iPhone 15 (iOS 26)", launch: true },
  async ({ driver, test }) => {
    await test("check driver", async () => {
      await expect(driver).toBeDefined();
    });
  },
);
```
