@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:
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 }) => {
await driver.pause(1000);
await device.installConfigurationProfile(driver, profile);
},
);
Flow Callback Context
All iOS flow callbacks receive:
input
setOutput(...)
test(...)
Launch-enabled iOS flows also receive driver.
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:
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:
import { flow } from "@qawolf/flows/ios";
export const targetOnlyFlow = flow(
"Target-only path",
"iOS - iPhone 15 (iOS 26)",
async () => {
// call launch() imperatively when startup should happen in the callback
},
);
export const launchedFlow = flow(
"Launch-enabled path",
{ target: "iOS - iPhone 15 (iOS 26)", launch: true },
async ({ driver }) => {
await driver.pause(1000);
},
);
flow(...)
Use flow(...) for iOS authoring.
Behavior from the implementation:
- without launch, the callback receives
input, 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:
import { flow } from "@qawolf/flows/ios";
export default flow(
"Launch in flow definition",
{ target: "iOS - iPhone 15 (iOS 26)", launch: true },
async ({ driver }) => {
await driver.pause(1000);
},
);
launch(...)
launch() starts iOS automation for the active flow and returns:
type LaunchResult = {
driver: Awaited<ReturnType<Dependencies["wdio"]["startIos"]>>;
};
This API is only available while a flow is running.
Example:
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
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:
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:
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 app is provided, the current resolution order is:
app.path
app.env
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:
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:
// The runner sets RUN_INPUT_PATH before the flow starts.
await launch({
bundleId: "com.example.ios",
});
If app is present but does not resolve to a value, launch does not fall back to RUN_INPUT_PATH.
device
device is a runtime proxy over the iOS simulator or device API. Use it for device-level operations that sit outside the main flow(...) and launch() path.
Example:
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:
import { expect, flow } from "@qawolf/flows/ios";
export default flow(
"Use runner expect",
{ target: "iOS - iPhone 15 (iOS 26)", launch: true },
async ({ driver }) => {
await expect(driver).toBeDefined();
},
);
Last modified on April 24, 2026