Skip to main content

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