Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.qawolf.com/llms.txt

Use this file to discover all available pages before exploring further.

Use device.injectBeacon() to simulate the device detecting a nearby iBeacon, triggering CLLocationManager callbacks in your app as if real hardware were present. Pushing a .region file triggers a region-entry callback; also pushing a .beacon file triggers ranging callbacks. See the iOS Device Reference for the full injectBeacon API.

Examples

Region entry and ranging
const cleanup = await device.injectBeacon(driver, "com.example.app", {
  uuid: "8613BEAD-5465-4515-8F9C-AEEA717484C9",
  beacons: [{ major: 1, minor: 7 }],
});

// assert your app responded to the beacon event

await cleanup();
Region entry only (no ranging) Omit the beacons array to trigger only a region-entry event.
const cleanup = await device.injectBeacon(driver, "com.example.app", {
  uuid: "e62c96fd-014a-454f-9b41-32245d802bb3",
});

// assert your app responded to the region entry

await cleanup();

When to use

  • Your app uses iBeacon proximity for retail check-ins, loyalty triggers, or location-based promotions.
  • Your app uses indoor navigation or asset tracking via Bluetooth beacons.
  • Your app responds to beacon region entry or exit events.
  • Your test needs to verify ranging callbacks with specific major/minor values.

Location permissions

iBeacons require location permissions. Two important caveats: autoAcceptAlerts chooses “Ask Next Time” for location dialogs. If the permission dialog appears, Appium will not choose “Always Allow” — and there is no way to change it after the fact. Background location access cannot be auto-accepted. If your app requires “Change to Always Allow” for background beacon detection, you must handle the dialog manually using respectSystemAlerts: true:
const { driver: d } = await launch({
  bundleId: "com.example.app",
  respectSystemAlerts: true,
});

const allowBtn = d.$(`//XCUIElementTypeButton[@name='Allow']`);
if (await allowBtn.isExisting()) {
  await allowBtn.click();
}
respectSystemAlerts: true may slow down Appium performance. Use it only when you need to interact with system dialogs manually.

Full sample test

import { device, flow } from "@qawolf/flows/ios";

export default flow(
  "Test beacon proximity",
  { target: "iOS - iPhone 15 (iOS 26)", launch: true },
  async ({ driver, test }) => {
    await test("inject beacon and verify app response", async () => {
      // Arrange
      const allowBtn = driver.$(`//XCUIElementTypeButton[@name='Allow']`);
      if (await allowBtn.isExisting()) {
        await allowBtn.click();
      }

      await driver.$(`//XCUIElementTypeStaticText[@name='Nearby']`).waitForDisplayed({ timeout: 10_000 });

      // Act
      const cleanup = await device.injectBeacon(driver, process.env.BUNDLE_ID, {
        uuid: "8613BEAD-5465-4515-8F9C-AEEA717484C9",
        beacons: [{ major: 1, minor: 7 }],
      });

      // Assert
      await driver
        .$(`//XCUIElementTypeStaticText[@name='Beacon Detected']`)
        .waitForDisplayed({ timeout: 10_000 });

      await cleanup();
    });
  },
);
Last modified on May 20, 2026