Set location on an iOS Simulator and full-reset before/after each test case

Hello everyone,

Facing two issues here:

  1. How do I set my location on a simulator? Recently I started getting a dialog while running tests that pretty much says the location of the device couldn’t be found and because of this one dialog my tests fail. Happens maybe 10% of the time. Completely random and has no specific steps in order to reproduce this problem. I’d like to set my location before each test case if possible, but not sure how?

P.S. I could possible just write something that expects the dialog to come up and handle it, but then my location isn’t set and my tests would fail anyways. Instead of some hack solution I’d like to find some long term, reliable solution like setting the location to custom before each launch or something.

  1. I know a full-reset before each test case isn’t the best option because the regression test suite would take way longer, so I wanted to ask how other folks are handling it. I thought about bundling up some test cases because right now for each test case I relaunch the sim and install the app so that the user is always “brand new”. Any other ideas would be greatly appreciated.

Thank you

Option1:
If you don’t want to handle Location services alert anywhere in your scripts, then use the below appium capabilities.

"locationServicesAuthorized"  = true
"bundleId" = "bundle id name"

Option2:
If you need location services alert for some scripts and if you can’t use above capabilities, then you can use appium’s waitForAppScript capability and handle the unwanted alerts.

Ex:-
You can use the capability in this way.

"waitForAppScript", "if (target.frontMostApp().alert().name()=='the location of the device couldn't be found') {$.acceptAlert(); true;}"

This capability will take care of handling the “location not found” alert at any point of time, while running the scripts.

@hemche thank you very much for your reply.

I would love to write something to handle the location alert whenever it comes up. However, I can’t because the results in the app I am testing depend on the location that is being returned. This means that if during the test “location not found” dialog comes up, then the whole app content will not be displayed and therefore fail the tests.

we use:

Location some_loc = new Location(xx.xxxxxx, xx.xxxxxx, 0);
driver.setLocation(some_loc);

does not work reliable but … can try

Thanks @Aleksei! I write my code in Ruby and just wanted to see if I need to import any library for the “set location” to work?

@aleksei - thank you very much!
For anyone else looking for help on how to set simulator location:
Ruby: set_location({latitude: 50.000, longitude: -50.000})

You can also set tup altitude the same way!

So the problem is still happening…
My tests launch the emulator, set the location to XXX,XXX and I still randomly get a dialog on the simulator stating that the location wasn’t returned correctly.
I can’t think of any other solution, I’ve tried the following:

  1. Reset the simulator for every single test case
  2. Manually / automatically allow location services
  3. Manually / automatically set location to XXX,XXX

What else can I do? Any help would be highly appreciated.

if issue quite rear and subsequent retry fixing issue for you - i suggest to implement retry login in case.

BTW i have found out that it is helps following steps:
in simulator do:

  • debug -> Location -> None
  • debug -> Location -> Custom Location

Setting only Custom Location does not help.

i managed to do this in code with osascript.

Could you share the code that you use to set location to none and then custom? I know the custom location, but not none. Thanks!

here it is below. NOTE: only with simulator! and on same machine where test code is running.
And only with xCODE7. with xCODE6 you need to update simulator name.

    public void setLocationWithEmulator(Location loc) {
        try {
            String[] cmd = {"osascript", "-e",
                    "on menu_click(mList)\n" +
                    "    local appName, topMenu, r\n" +
                    "\n" +
                    "    -- Validate our input\n" +
                    "    if mList's length < 3 then error \"Menu list is not long enough\"\n" +
                    "\n" +
                    "    -- Set these variables for clarity and brevity later on\n" +
                    "    set {appName, topMenu} to (items 1 through 2 of mList)\n" +
                    "    set r to (items 3 through (mList's length) of mList)\n" +
                    "\n" +
                    "    -- This overly-long line calls the menu_recurse function with\n" +
                    "    -- two arguments: r, and a reference to the top-level menu\n" +
                    "    tell application \"System Events\" to my menu_click_recurse(r, ((process appName)'s ¬\n" +
                    "        (menu bar 1)'s (menu bar item topMenu)'s (menu topMenu)))\n" +
                    "end menu_click\n" +
                    "\n" +
                    "on menu_click_recurse(mList, parentObject)\n" +
                    "    local f, r\n" +
                    "\n" +
                    "    -- `f` = first item, `r` = rest of items\n" +
                    "    set f to item 1 of mList\n" +
                    "    if mList's length > 1 then set r to (items 2 through (mList's length) of mList)\n" +
                    "\n" +
                    "    -- either actually click the menu item, or recurse again\n" +
                    "    tell application \"System Events\"\n" +
                    "        if mList's length is 1 then\n" +
                    "            click parentObject's menu item f\n" +
                    "        else\n" +
                    "            my menu_click_recurse(r, (parentObject's (menu item f)'s (menu f)))\n" +
                    "        end if\n" +
                    "    end tell\n" +
                    "end menu_click_recurse\n" +
                    "\n" +
                    "application \""+simulatorAppName()+"\" activate    \n" +
                    "delay 0.2\n" +
                    "menu_click({\""+simulatorAppName()+"\",\"Debug\", \"Location\", \"None\"})\n" +
                    "\n" +
                    "delay 0.2\n" +
                    "menu_click({\""+simulatorAppName()+"\",\"Debug\", \"Location\", \"Custom Location…\"})\n" +
                    "\n" +
                    "delay 0.2\n" +
                    "tell application \"System Events\"\n" +
                    "    tell process \""+simulatorAppName()+"\"\n" +
                    "        set value of text field 1 of window \"Custom Location\" to \""+loc.getLatitude()+"\"\n" +
                    "        set value of text field 2 of window \"Custom Location\" to \""+loc.getLongitude()+"\"\n" +
                    "        click UI Element \"OK\" of window \"Custom Location\"\n" +
                    "    end tell\n" +
                    "end tell"
            };
            Process process = Runtime.getRuntime().exec(cmd);
            BufferedReader bufferedReader = new BufferedReader(
                    new InputStreamReader(process.getErrorStream()));
            String lsString;
            while ((lsString = bufferedReader.readLine()) != null) {
                System.out.println(lsString);
            }
            try{Thread.sleep(10000);}catch (Exception e1){}
        } catch (Exception e) {}
    }

  public String simulatorAppName() {
        return "Simulator";
    }

I’m almost sure that my problem would be solved if only I could figure out the syntax in Ruby to set location to none. At the moment I’m just trying anything that comes to my mind

try: http://tech.natemurray.com/2007/03/ruby-shell-commands.html
all you need is execute mentioned “String[] cmd = {“osascript”…” variable in command line.

  • onMac you need to provide admin rights in Security&Privacy -> tab Privacy -> Accesibility

do you know if there is any way to set location to none just like we set location so some actual coordinates?
for example I use: set_location({latitude: 50.000, longitude: -50.000})

but I just cant figure out the syntax to set it to none… tried the following:

  1. set_location({latitude: 50.000, longitude: -50.000})
  2. set_location({latitude: 0, longitude: 0})
  3. set_location({latitude: nil, longitude: nil})
  4. set_location({latitude: none, longitude: none})
  5. set_location({latitude: ‘none’, longitude: ‘none’})
  6. set_location({none, none})
  7. set_location({nil, nil})

We have a way to do that.

1- Instal set simulator location from here > https://github.com/lyft/set-simulator-location
2- In your base class add this method :

public static void SetLocationDeice() throws IOException {
Runtime.getRuntime().exec(“set-simulator-location -c 24.583852 46.784436 -s iPhone 11 -u FF517BC5-4460-49A6-9042-5A750B367BAC”);
}

3- or run this command line:

set-simulator-location -c 24.583852 46.784436 -s iPhone 11 -u FF517BC5-4460-49A6-9042-5A750B367BAC

The rule here:

set-simulator-location [-c 0 0|-q San Francisco] [-s Simulator Name|-u Simulator udid]

4- Use this method when your script is running

SetLocationDeice();

Example:

@Test(priority = 2)
public void LoginScreenEn() throws IOException, InterruptedException {
IOSDriver driver1 = Capabilities2(“Application”);
SetLocationDeice();
LoginScreenEnObjects PageObject2 = new LoginScreenEnObjects(driver1);
PageObject2.AllowBt.click();

Hi there,
I tried this and it works but how do i reset it to the current location afterwards…??
Somehow - after quiting android driver and restarting appium also -
The location that was set earlier is being fetched on doing getLocation()

Simple! Just get location value BEFORE change it :slight_smile:

// java-client 9.3.0
Location currentLoc = ((SupportsLocation) driver).getLocation();
((SupportsLocation) driver).setLocation(neededLocation);
((SupportsLocation) driver).setLocation(currentLoc);