Examples
Using a predefined condition:
// Traffic must be routed through the gateway before applying
// network conditions — use direct mode if you don't need a VPN
const routeCleanup = await ios.routeTraffic({
apps: ["com.example.app"],
tunnel: { type: "direct" },
});
const conditionCleanup = await ios.simulateNetworkCondition(ios.NETWORK_3G);
// ... verify the app handles slow network gracefully ...
await conditionCleanup();
await routeCleanup();
Custom conditions:
const cleanup = await ios.simulateNetworkCondition({
bandwidthKbps: 5000,
latencyMs: 600,
jitterMs: 50,
packetLossPercent: 1.0,
});
// ... verify timeouts, retries, offline banners ...
await cleanup();
Offline mode (no connectivity):
// Simulates offline mode by dropping all packets.
// Note: this may not trigger every app's offline UI —
// some apps only show offline states when the connection drops abruptly
const cleanup = await ios.simulateNetworkCondition(ios.NETWORK_OFFLINE);
// ... verify offline error handling, cached content ...
await cleanup();
When to use
- Testing how your app behaves when loading is slow — spinners, timeouts, retry logic
- Verifying your app shows the right error messages when connectivity is poor or lost
- Testing video or audio streaming features that adapt quality based on available bandwidth (adaptive bitrate streaming)
- Reproducing issues customers have reported on slow or unreliable connections
- Making sure your app degrades gracefully for users on 2G or 3G networks
Notes
- Before calling
ios.simulateNetworkCondition(), you must call ios.routeTraffic() otherwise you will get an error.
- Always call cleanup functions in reverse order: restore network conditions first, then stop routing.
- Bandwidth limiting applies to TCP traffic only.
- Latency, jitter, and packet loss apply to all traffic (TCP and UDP).
NETWORK_OFFLINE simulates no connectivity by dropping all packets. Requests will time out rather than fail immediately — this may behave differently from a true offline state on some devices.
Full sample test
import { flow } from "@qawolf/flows/ios";
export default flow(
"Ios Network Simulation with fast.com",
"iOS - iPhone 15 (iOS 26)",
async ({ test, ...testContext }) => {
const { ios, runCommand, wdio } = testContext;
await test("Install app", async () => {
// Start VPN
const cleanupProxy = await ios.routeTraffic({
apps: [],
tunnel: {
type: "direct",
}});
let cleanUpNetworkCondition = await ios.simulateNetworkCondition(ios.NETWORK_5G)
console.log(await ios.getNetworkCondition())
const safari = await wdio.startIos({ browserName: "safari" });
await safari.url("https://fast.com");
// switch to webview
const contexts = await safari.getContexts();
const webViewContext = contexts.reverse().find(context => context.toLowerCase().startsWith("webview_"));
await safari.switchContext(webViewContext);
// wait for the test result for 5G
await safari.$(`//*[@id='your-speed-message']`).waitForDisplayed({timeout: 30_000});
// clean-up and set 2G
await cleanUpNetworkCondition();
cleanUpNetworkCondition = await ios.simulateNetworkCondition(ios.NETWORK_2G_EDGE)
console.log(await ios.getNetworkCondition())
await safari.url("https://fast.com");
// wait for the test result for 2G
await safari.$(`//*[@id='your-speed-message']`).waitForDisplayed({timeout: 30_000});
});
},
);
Last modified on April 7, 2026