How to Automate Location Services Testing (Step-by-Step)

How to Automate Location Services Testing (Step-by-Step) is a practical guide for developers and QA engineers who need reliable, repeatable validation of GPS, geofencing, and mock‑location features in

February 20, 2026 · 15 min read · How-To Guides

How to Automate Location Services Testing (Step-by-Step) is a practical guide for developers and QA engineers who need reliable, repeatable validation of GPS, geofencing, and mock‑location features in mobile and web applications. Location‑based behavior often hides behind device‑specific quirks, network latency, and permission flows that are tedious to verify manually. Automating these checks reduces regression risk, uncovers edge cases that only appear under certain coordinate sets or accuracy levels, and frees testers to focus on exploratory work. The following sections walk through a complete, end‑to‑end process: deciding when automation pays off, picking a framework, crafting maintainable tests, handling waits and flakiness, managing data setup and teardown, integrating with CI, and surfacing actionable reports. Each step includes concrete code snippets, a test matrix, and a tool‑comparison table to help you make informed decisions.

How to Automate Location Services Testing (Step-by-Step): Setting Up the Environment

Before writing any test, you need a stable, controllable environment that can simulate location changes without relying on physical movement. For Android, the Android Emulator provides the geo fix command via ADB, while iOS simulators expose xcrun simctl location. Web tests can override the Geolocation API using browser‑level mocks or devtools protocol commands.

Installing Required Tools

Configuring Mock Location Permissions

On Android, the test harness must grant the ACCESS_MOCK_LOCATION permission to the test APK or to the emulator’s shell. Add the following to your test setup script:


adb root
adb shell appops set <package_name> android:mock_location allow
adb shell pm grant <package_name> android.permission.ACCESS_MOCK_LOCATION

On iOS, enable the “Allow Location Simulation” toggle in the simulator’s Debug menu, or use:


xcrun simctl location booted set <latitude> <longitude>

For web, launch Chrome with the --disable-features=Geolocation flag and then inject a mock via the DevTools Protocol:


from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    context = browser.new_context()
    # Override geolocation for the context
    context.grant_permissions(['geolocation'], origin='https://maps.example.com')
    context.set_geolocation({'latitude': 40.7128, 'longitude': -74.0060, 'accuracy': 10})
    page = context.new_page()
    page.goto('https://maps.example.com')
    # … test steps …
    browser.close()

Verifying the Setup

Run a quick sanity check that the mock location is being consumed:

If the values differ, re‑check permission grants and ensure no other process is overriding the location provider (e.g., a background location service).

With a controllable location source in place, you can now decide which aspects of location services merit automation.

How to Automate Location Services Testing (Step-by-Step): When Automation Pays Off

Not every location‑related scenario needs a script. Manual exploratory testing remains valuable for assessing UI feel, accessibility of permission dialogs, and ad‑hoc edge cases. Automation shines when you need repeatable validation across multiple coordinate sets, accuracy levels, or when the feature is part of a critical user flow such as ride‑hailing, asset tracking, or geofenced notifications.

Criteria for Automation

CriterionDescriptionAutomation Benefit
RepeatabilitySame coordinate sequence must be exercised many times (e.g., regression after each build).Eliminates human error, ensures exact same inputs.
Combinatorial ExplosionTesting latitude/longitude pairs, altitude, accuracy, speed, and heading creates dozens of combos.Scripts can iterate over data files quickly.
Time‑Sensitive TriggersGeofence entry/exit depends on dwell time or speed thresholds.Precise control over timestamps and movement simulation.
Cross‑Platform ConsistencySame feature must behave identically on Android, iOS, and web.Centralized test logic reduces divergence.
Failure‑Prone PermissionsRuntime permission dialogs can flake if timing shifts.Scripts can grant/revoke permissions programmatically, removing UI timing variance.

If your feature meets at least three of the above criteria, invest in automated location tests. Otherwise, a lightweight manual checklist may suffice.

Example: Ride‑Hailing Pickup Flow

Consider a ride‑hail app where the user taps “Set Pickup”, the map centers on the current location, and a “Confirm” button appears only when the accuracy radius is < 50 m. Manual testing would require walking around or using a joystick emulator; automation can inject a series of locations with varying accuracy to confirm the button appears/disappears at the right thresholds.

A test matrix for this feature might look like:

Test IDLatitudeLongitudeAccuracy (m)Expected Button StateNotes
P137.7749-122.419410EnabledHigh accuracy, inside geofence
P237.7749-122.4194100DisabledLow accuracy, should block confirm
P337.7749-122.419450EnabledBoundary case
P437.8000-122.500010DisabledOutside service area

Automating this matrix lets you run the same checks on every commit, catching regressions where the accuracy check is accidentally removed or the UI bound to the wrong view model property.

How to Automate Location Services Testing (Step-by‑Step): Choosing a Framework

Selecting a test framework influences language choice, device control capabilities, and ease of integrating location mocks. The most common options for mobile are Appium (Android/iOS) and platform‑specific tools like Espresso/XCUITest. For web, Playwright and Selenium dominate. Below is a comparison focused on location‑services support.

Tool‑Comparison Table

FeatureAppiumEspresso (Android)XCUITest (iOS)PlaywrightSelenium WebDriver
Language SupportJava, JS, Python, C#, RubyJava/KotlinSwift/Obj‑CJS/TS, Python, Java, C#Java, JS, Python, C#, Ruby
Location Mockingadb geo fix or mobile: setLocationLocationManager test doubles via Dependency InjectionCLLocationManager mock via XCTestbrowser.context.set_geolocation or page.evaluate overrideexecute_script to override navigator.geolocation
Geofence SimulationSend latitude/longitude updates repeatedly; can emulate speed via adb shell svc locationRequires custom test double or Firebase Test Lab location spoofingUse CLLocation test double; limited to simulatorCan fire setInterval to update location; easy to simulate heading/speedSame as Playwright via execute_script
Permission Handlingmobile: permission command; can grant/revoke at runtimegrantRuntimePermission via UiAutomatorXCUITest addLocationAuthorizationbrowserContext.grantPermissionsexecute_script to navigate to chrome://settings/content/location
Cross‑PlatformYes (single codebase)No (Android only)No (iOS only)Yes (Chromium, Firefox, WebKit)Yes (multiple browsers)
Speed & StabilityModerate (JSON wire protocol overhead)High (in‑process)High (in‑process)High (devtools protocol)Moderate to high (depends on browser)
Learning CurveMedium (need to understand server)Low for Android devsLow for iOS devsLow‑Medium (API is concise)Medium (Selenium Grid complexity)
Best ForTeams needing one script for both platforms, hybrid appsPure Android native apps with extensive unit‑testable location logicPure iOS native appsWeb apps, PWAs, hybrid web viewsLegacy web projects, Selenium‑grid shops

If your project already uses Appium for functional UI tests, extending it with location commands is the lowest‑friction path. For greenfield native projects, writing location‑specific unit tests with Espresso/XCUITest and then layering UI validation offers the best speed and hybrid apps, and WebView(

Now let's see how to integrate location mocking into each framework.

#### Appium Example (Java)


import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class LocationTest {
    private AppiumDriver driver;

    @BeforeEach
    public void setUp() throws Exception {
        URL serverUrl = new URL("http://localhost:4723/wd/hub");
        Map<String, Object> caps = new HashMap<>();
        caps.put("platformName", "Android");
        caps.put("deviceName", "Pixel_4_API_33");
        caps.put("appPackage", "com.example.myapp");
        caps.put("appActivity", ".MainActivity");
        driver = new AndroidDriver(serverUrl, caps);
    }

    @Test
    public void testGeofenceEntry() {
        // Set initial location outside geofence
        driver.setLocation(37.7700, -122.4200, 50);
        // Perform actions that should NOT trigger geofence
        assertFalse(isGeofenceNotificationVisible());

        // Move inside geofence
        driver.setLocation(37.7749, -122.4194, 10);
        // Wait for possible notification (use explicit wait)
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
        wait.until(d -> isGeofenceNotificationVisible());
        assertTrue(isGeofenceNotificationVisible());
    }

    private boolean isGeofenceNotificationVisible() {
        // Implement based on your app's UI (e.g., toast, dialog, status bar icon)
        return driver.findElements(By.id("geofence_alert")).size() > 0;
    }

    @AfterEach
    public void tearDown() {
        if (driver != null) driver.quit();
    }
}

#### Playwright Example (TypeScript)


import { test, expect } from '@playwright/test';

test('geofence triggers notification', async ({ page }) => {
  await page.goto('https://myapp.com/map');

  // Mock initial location outside the geofence
  await page.context().setGeolocation({ latitude: 37.7700, longitude: -122.4200, accuracy: 50 });
  await page.context().grantPermissions(['geolocation']);
  await page.waitForTimeout(500); // allow time

  const outsideNotify = page.locator('#geofalert');
  await outsideNotifyNotifyfBeVisible()).toNot(beBeVisible());

  // Move inside geofence
  await page.context().setGeolocation({ latitude: 37.7749, longitude: -122.4194, accuracy: 10 });
  await page.waitForTimeout(500);
  await expect(page.locator('#geofence-alert')).toBeVisible();
});

These snippets illustrate the core actions: setting coordinates, granting permissions, and asserting UI reactions. Adjust the locators and wait strategies to match your application's specifics.

How to Automate Location Services Testing (Step-by‑Step): Writing Stable/Maintainable Tests

Stability hinges on isolating location logic from flaky UI timing, using deterministic data, and encapsulating repetitive steps in reusable helpers. Below are patterns that keep your test suite readable and robust.

1. Abstract Location Actions

Create a utility class or module that wraps platform‑specific location commands. This isolates changes if you switch from Appium to Espresso, for example.


// LocationHelper.java (Appium + Java)
public class LocationHelper {
    private final AppiumDriver driver;

    public LocationHelper(AppiumDriver driver) {
        this.driver = driver;
    }

    public void setLocation(double lat, double lng, float accuracy) {
        driver.setLocation(lat, lng, accuracy);
    }

    public void grantLocationPermission() {
        // Android specific
        driver.executeScript("mobile: permission", ImmutableMap.of(
            "action", "grant",
            "appId", driver.getCapabilities().getCapability("appPackage"),
            "permission", "android.permission.ACCESS_FINE_LOCATION"
        ));
    }

    public void revokeLocationPermission() {
        driver.executeScript("mobile: permission", ImmutableMap.of(
            "action", "revoke",
            "appId", driver.getCapabilities().getCapability("appPackage"),
            "permission", "android.permission.ACCESS_FINE_LOCATION"
        ));
    }
}

Use this helper in every test: new LocationHelper(driver).setLocation(...);

2. Parameterize Test Data

Store coordinate sets, accuracy values, and expected outcomes in external files (CSV, JSON, YAML). This enables non‑technical stakeholders to edit scenarios without touching code.


// geofence_scenarios.json
[
  {"id":"S1","lat":37.7749,"lng":-122.4194,"acc":10,"expected":"inside"},
  {"id":"S2","lat":37.7749,"lng":-122.4194,"acc":100,"expected":"outside"},
  {"id":"S3","lat":37.8000,"lng":-122.5000,"acc":10,"expected":"outside"}
]

In JUnit 5 with @ParameterizedTest and a custom ArgumentProvider, you can feed each entry to a single test method.


@ParameterizedTest
@ArgumentSource(GeofenceArgumentsProvider.class)
void testGeofenceScenario(String id, double lat, double lng, float acc, String expected) {
    locationHelper.setLocation(lat, lng, acc);
    locationHelper.grantLocationPermission();
    // perform the action that should trigger geofence check
    boolean inside = isInsideGeofence(); // your UI check
    Assertions.assertEquals(expected.equals("inside"), inside,
        () -> "Scenario " + id + " failed");
}

3. Use Explicit Waits, Not Sleeps

Location updates may take a few hundred milliseconds to propagate through the OS stack. Replace Thread.sleep with condition‑based waits.


WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
wait.until(d -> {
    Location loc = ((AndroidDriver) d).getLocation();
    return loc.getLatitude() == lat && loc.getLongitude() == lng;
});

4. Encapsulate UI Assertions

If your app shows a toast, status bar icon, write a small method that returns a boolean. This makes test method bodies short: private boolean isGeofenceToastVisible() {

return driver.findElements(By.id("toast_geofence")).stream()

.anyMatch(e -> e.isDisplayed());

}



### 5. Handle Permission Flakiness  

On Android 12+ the permission dialog may appear after a location request. Instead of assuming it’s already granted, actively grant/revoke in the test setup. For iOS, use `XCUITest`’s `addLocationAuthorization` or `simctl` commands in a `beforeEach` hook.

### 6. Keep Tests Idempotent  

Each test should start from a known location state (e.g., set to a default “null” location like 0,0) and end with the same state. This prevents cross‑test contamination when running in parallel.

Applying these patterns yields a test suite that remains green across refactors, device OS updates, and framework upgrades.

## How to Automate Location Services Testing (Step-by‑Step): Locator Strategy

Location‑based features often rely on map widgets (Google Maps SDK, Mapbox, Apple MapKit) or custom canvas renders. Locators that depend on pixel coordinates or dynamically generated IDs are brittle. Adopt strategies that survive UI theme changes, localization, and map tile updates.

### 1. Prefer Accessibility IDs  

Both Android and iOS expose accessibility labels that are less likely to change than view IDs. For a map pin, set an accessibility label like `"pickup_pin"` in the code and locate it via:

* **Android (Espresso)**: `onView(withContentDescription("pickup_pin"))`
* **iOS (XCUITest)**: `app.buttons["pickup_pin"]` (if you set the button’s accessibilityIdentifier)

### 2. Use Data‑Test Attributes for Web  

Add `data-testid` attributes to map‑related elements (markers, info windows, buttons). Example:



Then locate with Playwright: `page.locator('[data-testid="map-marker"]')`.

### 3. Leverage Map‑Specific APIs  

Some map SDKs expose methods to query rendered features. For instance, Mapbox GL JS offers `map.queryRenderedFeatures`. You can call this via `page.evaluate` to get a list of features at a given screen point, then assert properties like `feature.properties.type === 'pickup'`.

const features = await page.evaluate(() => {

return map.queryRenderedFeatures([x, y], { layers: ['symbol-layer'] });

});

expect(features.some(f => f.properties.id === 'pickup-1')).toBe(true);



This approach sidesteps DOM fragility altogether.

### 4. Avoid Hard‑Coded Pixel Coordinates  

If you must interact with the map by coordinate, compute the point relative to the map container bounding box:  

// Java

int centerX = mapView.getWidth() / 2;

intmap via tap coordinates, compute them from the map container’s dimensions rather than using magic numbers. Example in Appium:


Dimension size = driver.manage().window().getSize();
int startX = size.width / 2;
int startY = size.height / 2;
new TouchAction(driver)
    .press(PointOption.point(startX, startY))
    .waitAction(WaitOptions.waitOptions(Duration.ofMillis(200)))
    .moveTo(PointOption.point(endX, endY))
    .release()
    .perform();

5. Test Map Tile Loading Separately

Map tile network failures can cause false negatives. Include a checkpoint that verifies at least one tile has loaded before interacting with markers. For Android, you can check MapView.isMyLocationEnabled() or observe that onTileLoaded callback fires a known number of times.

By anchoring locators to semantic attributes or SDK query methods, your tests survive UI redesigns and remain readable.

How to Automate Location Services Testing (Step-by‑Step): Handling Waits and Flakiness

Even with solid locators, location services introduce timing variables: GPS fix latency, network‑based location provider delays, and animation durations for map transitions. Mitigate flakiness with a combination of explicit waits, retry logic, and observability.

1. Explicit Waits for Location‑Dependent UI

Instead of waiting a fixed time, wait for a condition that directly reflects the location state. Example using Appium’s WebDriverWait in Java:


new WebDriverWait(driver, Duration.ofSeconds(10))
    .until(d) {
       
    driver.getLocation() != null && 
          d -> {
        Location loc = ((AndroidDriver) d).getLocation();
        return Math.abs(loc.getLatitude() - targetLat) < 0.0001 && 
        Math.abs(loc.getLongitude() < 0.0001;
    );

2. Polling every 500 ms until condition true.

return Math.abs(loc.getLatitude() - expectedLat) < 0.00001 &&

Math.abs(loc.getLongitude() - expectedLng) < 0.00001;

});



### 2. Retry Wrapper for Assertions  

Sometimes the UI updates a fraction of a second after the location change. Wrap assertions in a retry loop with exponential back‑off.

public static void assertWithRetry(BooleanSupplier condition, String message, int maxAttempts) {

int attempt = 0;

while (attempt < maxAttempts) {

if (condition.getAsBoolean()) return;

try { Thread.sleep(200 * (1 << attempt)); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }

attempt++;

}

throw new AssertionError(message + " after " + maxAttempts + " attempts");

}

// Usage

assertWithRetry(() -> isPickupButtonEnabled(),

"Pickup button never enabled after location set", 5);



### 3. Use Event‑Based Triggers  

If your app emits events (e.g., via LiveData, RxJava, Combine) when location updates arrive, expose a test hook or observe a test‑only observable. For Android, you can add a `MutableLiveData<Location>` that the production code observes; in tests, you set its value directly.

// Production code

locationRepository.getLocationLiveData().observe(lifecycleOwner, loc -> {

updateUI(loc);

});

// Test code

@Test

void testLocationUpdate() {

MutableLiveData testLive = new MutableLiveData<>();

// Inject testLive into the repository via dependency injection

repository.setLocationLiveDataForTest(testLive);

// UI observes the LiveData

activityScenario.onActivity(activity -> {

// set location

testLive.setValue(new Location("gps") {{

setLatitude(37.7749);

setLongitude(-122.4194);

setAccuracy(10);

}});

});

// assert UI changed

onView(withId(R.id.pickup_button)).check(matches(isEnabled()));

}



This eliminates reliance on timing altogether.

### 4. Capture Logs and Metrics  

Enable location‑related logging (`adb logcat | grep LocationManager`) and assert that expected log lines appear within a timeout. This gives an early signal if the location provider never received the mock.

LogCollector logCollector = new LogCollector(driver);

logCollector.startCapture();

locationHelper.setLocation(lat, lng, acc);

logCollector.awaitLineContains("Mock location set", Duration.ofSeconds(5));



### 5. Stabilize Map Animations  

Map SDKs often animate camera changes. Disable animations in test builds or wait for the `onCameraIdle` callback (Android) or `map.isCameraMoving` (iOS) to become false.

// Android: turn off animations in test-only build: map.getUiSettings().setScrollGesturesEnabled(false);



By combining condition‑based waits, retry mechanisms, and event hooks, you reduce false positives caused by the inherent asynchrony of location services.

## How to Automate Location Services Testing (Step-by‑Step): Data Setup and Teardown

Location tests often depend on device state such as mocked GPS, network mode, or battery level. Proper setup and teardown guarantee that each test runs in isolation and that the emulator/simulator returns to a clean baseline.

### 1. Reset Location Provider  

After each test, clear any mock location and restore the provider to its default state.

@AfterEach

public void resetLocation() {

// Clear mock location

driver.executeScript("mobile: geoFix", ImmutableMap.of(

"latitude", 0,

"longitude", 0,

"accuracy", 0

));

// Optionally disable mock location permission to avoid leakage

driver.executeScript("mobile: permission", ImmutableMap.of(

"action", "revoke",

"appId", driver.getCapabilities().getCapability("appPackage"),

"permission", "android.permission.ACCESS_MOCK_LOCATION"

));

}



For iOS simulators:

xcrun simctl location booted unset



### 2. Clear Geofences  

If your app registers geofences via the OS, explicitly remove them to prevent cross‑test interference.

// Android example using LocationManager via reflection or a test-only method

public void clearGeofences() {

// Assuming you exposed a test-only method in your LocationRepository

repository.clearAllGeofencesForTest();

}



If no test hook exists, you can invoke the OS command to delete all geofences for the package:

adb shell cmd appops set android:mock_location ignore

adb shell pm clear // caution: clears all data, use sparingly



### 3. Manage Network Conditions  

Location may rely on Wi‑Fi or cellular for assisted GPS. Use the emulator’s network controls to simulate different conditions:

# Emulate 3G slow network

adb emu network speed 3g

# Return to full speed

adb emu network speed full



Wrap these commands in setup/teardown methods if you need to test under degraded connectivity.

### 4. Battery and Power State  

Some location APIs change behavior under low‑power mode. You can set battery level via:

adb shell dumpsys battery set level 20

adb shell dumpsys battery set status 2 // 2 = charging



Reset to default after each test.

### 5. teardown Hook Summary  

A typical JUnit `@AfterEach` might look like:

@AfterEach

public void tearDown() {

// 1. Reset mock location

locationHelper.setLocation(0, 0, 0);

// 2. Revoke mock location permission (optional)

locationHelper.revokeLocationPermission();

// 3. Clear app-specific geofences

repository.clearGeofencesForTest();

// 4. Reset network to full speed

try { Runtime.getRuntime().exec("adb emu network speed full"); } catch (IOException ignored) {}

// 5. Reset battery to 100% unplugged

try { Runtime.getRuntime().exec("adb shell dumpsys battery set level 100"); } catch (IOException ignored) {}

// 6. Close any lingering dialogs

dismissSystemDialogs();

}



Implementing deterministic setup and teardown eliminates “it works on my machine” flakiness and makes CI runs reliable.

## How to Automate Location Services Testing (Step‑by‑Step): Running in CI

Integrating location tests into a continuous‑integration pipeline ensures that regressions are caught early. The key challenges are provisioning emulators/simulators with location‑mocking capabilities, managing test execution time, and collecting artifacts for debugging.

### 1. Choose the Right Execution Environment  

* **Linux‑based agents** (most CI services) can run Android Emulator via the `android-emulator-runner` script.  
* **macOS agents** are required for iOS simulators and Xcode‑based tests.  
* For web, any agent with Chrome/Firefox installed works.

If you use a hosted service like GitHub Actions, GitLab CI, or Azure Pipelines, select the appropriate runner image (`ubuntu-latest` for Android, `macos-latest` for iOS).

### 2. Emulator/Simulator Provisioning Script  

Create a reusable script that starts an emulator with Google Play services, grants mock location permission, and sets a default location.

# start_android_emulator.sh

#!/usr/bin/env bash

EMULATOR_NAME="Pixel_4_API_33"

# Create if not exists

if ! avdmanager list avd | grep -q "$EMULATOR_NAME"; then

echo "no" | avdmanager create avd -n "$EMULATOR_NAME" -k "system-images;android-33;google_apis_playstore;x86_64"

fi

# Start emulator in background

emulator -avd "$EMULATOR_NAME" -no-window -no-audio -gpu swiftshader_indirect &

EMULATOR_PID=$!

# Wait for boot

adb wait-for-device

adb shell svc wifi enable

# Grant mock location to the app under test (replace with your package)

adb shell pm grant com.example.myapp android.permission.ACCESS_MOCK_LOCATION

# Set initial dummy location

adb shell geo fix 0 0

# Export emulator PID for later cleanup

echo $EMULATOR_PID > emulator.pid



A similar script for iOS:

# start_ios_simulator.sh

#!/usr/bin/env bash

SIM_NAME="iPhone_14"

# Boot a specific device type and OS version

xcrun simctl boot "$SIM_NAME"

# Wait for boot

while [[ $(xcrun simctl list | grep -i Booted" ]]; do sleep 1

done

# Grant location: xcrun simctl list devices | grep "$SIM_NAME.*Booted" ]]; do

sleep 1

done

done

# Grant location simulation permission (requires enabling in Debug menu automatically via simctl)

xcrun simctl spawn booted launchctl setenv SIMULATOR_CHAMBER_UID Enabled

# Set initial location

xcrun simctl location booted set 0 0



### 3. Parallel Execution  

Location tests are often I/O‑bound (waiting for emulator response). Running multiple emulator instances in parallel can reduce total pipeline time. Use Docker containers or separate VM agents, each with its own emulator port (`emulator -port 5556`, `-port 5558`, etc.). Ensure each test picks up its assigned port via an environment variable.

### 4. Artifact Collection  

When a test fails, capture:

* **Logcat** (`adb logcat > logcat.txt`)  
* **Simulator console output** (`xcrun simctl spawn booted log --console`)  
* **Screenshots** (`adb shell screencap -p /sdcard/fail.png && adb pull /sdcard/fail.png .`)  
* **Video** (emulator `-record video.webm`)  

Configure your CI to upload these as build artifacts or attach them to the test report.

### 5. Example GitHub Actions Workflow (Android)  

name: Location Tests

on:

push:

branches: [ main ]

pull_request:

jobs:

android-location:

runs-on: ubuntu-latest

timeout-minutes: 30

steps:

uses: actions/setup-java@v3

Test Your App Autonomously

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.

Try SUSA Free