14

Meta :-

  • iOS emulator device v10.3
  • Appium java-client v5.0.0 BETA8
  • Selenium v3.4.0

Actually I'm trying to set GeoLocation in iOS device using Appium XCUITest automation. I've tried with below code which is working fine on Android device while throw exception on iOS :

import org.openqa.selenium.html5.Location;

AppiumServiceBuilder builder = new AppiumServiceBuilder().usingAnyFreePort().withAppiumJS("path/to/appium/main.js");

DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("automationName", "XCUITest");
IOSDriver driver= new IOSDriver(builder, capabilities);

//Here this code working fine with AndroidDriver
Location location = new Location(latitude, longitude, altitude);    
driver.setLocation(location);

Exception:

org.openqa.selenium.WebDriverException: Method has not yet been implemented (WARNING: The server did not provide any stacktrace information)

And when I am trying using JavascriptExecutor as :

Map<String, String> args = new HashMap<String, String>();
args.put("address", "Address");
((JavascriptExecutor)webDriver).executeScript("mobile:setLocation", args);

Exception:

org.openqa.selenium.UnsupportedCommandException: Unknown mobile command "setLocation". Only scroll,swipe,pinch,doubleTap,twoFingerTap,touchAndHold,tap,dragFromToForDuration,selectPickerWheelValue,alert commands are supported. (WARNING: The server did not provide any stacktrace information)

And when I am trying as :

import org.openqa.selenium.remote.DriverCommand;

Map<String, String> args = new HashMap<String, String>();
args.put("location", "Address");
driver.execute(DriverCommand.SET_LOCATION, args);

Exception:

org.openqa.selenium.WebDriverException: Method has not yet been implemented (WARNING: The server did not provide any stacktrace information)

Is there anyway to set GeoLocation on iOS using appium?

Appium Log:

[debug] [JSONWP Proxy] Got response with status 200: "{\n \"value\" : {\n \"state\" : \"success\",\n \"os\" : {\n \"name\" : \"iOS\",\n \"version\" : \"10.3.1\"\n },\n \"ios\" : {\n \"simulatorVersion\" : \"10.3.1\",\n \"ip\" : \"192.168.1.17\"\n },\n \"build\" : {\n \"time\" : \"Aug 29 2017 15:40:09\"\n }\n },\n \"sessionId\" : \"10A97A93-D13A-4888-A536-0D62E0674A2B\",\n \"status\" : 0\n}"

[debug] [XCUITest] WebDriverAgent running on ip '192.168.1.17' [debug] [XCUITest] WebDriverAgent successfully started after 16121ms [debug] [BaseDriver] Event 'wdaSessionAttempted' logged at 1504013035278 (18:53:55 GMT+0530 (IST)) [debug] [XCUITest] Sending createSession command to WDA [debug] [JSONWP Proxy] Proxying [POST /session] to [POST http://localhost:8100/session] with body: {"desiredCapabilities":{"bundleId":"com.example.apple-samplecode.UICatalog","arguments":[],"environment":{},"shouldWaitForQuiescence":true,"shouldUseTestManagerForVisibilityDetection":false,"maxTypingFrequency":120,"shouldUseSingletonTestManager":true}} [debug] [JSONWP Proxy] Got response with status 200: {"value":{"sessionId":"43710C7E-2FDE-4A35-A2E0-4D309EE2CE9C","capabilities":{"device":"iphone","browserName":"UICatalog","sdkVersion":"10.3.1","CFBundleIdentifier":"com.example.apple-samplecode.UICatalog"}},"sessionId":"43710C7E-2FDE-4A35-A2E0-4D309EE2CE9C","status":0} [debug] [BaseDriver] Event 'wdaSessionStarted' logged at 1504013038184 (18:53:58 GMT+0530 (IST)) [debug] [XCUITest] Found WDA derived data folder: '/Users/omprakash.mishra/Library/Developer/Xcode/DerivedData/WebDriverAgent-dikkwtrisltbeobjmfvpthwwekvs' [XCUITest] Setting '555' permissions to '/Users/omprakash.mishra/Library/Developer/Xcode/DerivedData/WebDriverAgent-dikkwtrisltbeobjmfvpthwwekvs/Logs/Test/Attachments' folder [debug] [XCUITest] Found WDA derived data folder: '/Users/omprakash.mishra/Library/Developer/Xcode/DerivedData/WebDriverAgent-folfazwwukpzfkegdblpnfuwlvfn' [XCUITest] Setting '555' permissions to '/Users/omprakash.mishra/Library/Developer/Xcode/DerivedData/WebDriverAgent-folfazwwukpzfkegdblpnfuwlvfn/Logs/Test/Attachments' folder [debug] [BaseDriver] Event 'wdaPermsAdjusted' logged at 1504013038192 (18:53:58 GMT+0530 (IST)) [debug] [BaseDriver] Event 'wdaStarted' logged at 1504013038193 (18:53:58 GMT+0530 (IST)) [debug] [XCUITest] Setting initial orientation to 'PORTRAIT' [debug] [JSONWP Proxy] Proxying [POST /orientation] to [POST http://localhost:8100/session/43710C7E-2FDE-4A35-A2E0-4D309EE2CE9C/orientation] with body: {"orientation":"PORTRAIT"} [debug] [JSONWP Proxy] Got response with status 200: {"value":{},"sessionId":"43710C7E-2FDE-4A35-A2E0-4D309EE2CE9C","status":0} [debug] [BaseDriver] Event 'orientationSet' logged at 1504013038453 (18:53:58 GMT+0530 (IST)) [Appium] New XCUITestDriver session created successfully, session 6909c363-12a5-4a21-9298-c7f750ba7e09 added to master session list [debug] [BaseDriver] Event 'newSessionStarted' logged at 1504013038456 (18:53:58 GMT+0530 (IST)) [debug] [MJSONWP] Responding to client with driver.createSession() result: {"webStorageEnabled":false,"locationContextEnabled":false,"browserName":"","platform":"MAC","javascriptEnabled":true,"databaseEnabled":false,"takesScreenshot":true,"networkConnectionEnabled":false,"app":"src/test/resources/executor/UICatalog.app","maxTypingFrequency":"120","newCommandTimeout":0,"platformVersion":"10.3","automationName":"XCUITest","platformName":"iOS","udid":"0A41ECE4-6D03-4FEA-A82A-858FDBA6620E","deviceName":"iPhone 6"} [HTTP] <-- POST /wd/hub/session 200 46915 ms - 512 [HTTP] --> GET /wd/hub/session/6909c363-12a5-4a21-9298-c7f750ba7e09 {} [debug] [MJSONWP] Calling AppiumDriver.getSession() with args: ["6909c363-12a5-4a21-9298-c7f750ba7e09"] [debug] [XCUITest] Executing command 'getSession' [debug] [JSONWP Proxy] Proxying [GET /] to [GET http://localhost:8100/session/43710C7E-2FDE-4A35-A2E0-4D309EE2CE9C] with no body [debug] [JSONWP Proxy] Got response with status 200: "{\n \"value\" : {\n \"sessionId\" : \"43710C7E-2FDE-4A35-A2E0-4D309EE2CE9C\",\n \"capabilities\" : {\n \"device\" : \"iphone\",\n \"browserName\" : \"UICatalog\",\n
\"sdkVersion\" : \"10.3.1\",\n \"CFBundleIdentifier\" : \"com.example.apple-samplecode.UICatalog\"\n }\n },\n \"sessionId\" : \"43710C7E-2FDE-4A35-A2E0-4D309EE2CE9C\",\n \"status\" : 0\n}" [XCUITest] Merging WDA caps over Appium caps for session detail response [debug] [MJSONWP] Responding to client with driver.getSession() result: {"udid":"","app":"src/test/resources/executor/UICatalog.app","maxTypingFrequency":120,"newCommandTimeout":0,"platformVersion":"10.3","automationName":"XCUITest","platformName":"iOS","deviceName":"iPhone 6","device":"iphone","browserName":"UICatalog","sdkVersion":"10.3.1","CFBundleIdentifier":"com.example.apple-samplecode.UICatalog"} [HTTP] <-- GET /wd/hub/session/6909c363-12a5-4a21-9298-c7f750ba7e09 200 110 ms - 406 [HTTP] --> GET /wd/hub/session/6909c363-12a5-4a21-9298-c7f750ba7e09 {} [debug] [MJSONWP] Calling AppiumDriver.getSession() with args: ["6909c363-12a5-4a21-9298-c7f750ba7e09"] [debug] [XCUITest] Executing command 'getSession' [debug] [JSONWP Proxy] Proxying [GET /] to [GET http://localhost:8100/session/43710C7E-2FDE-4A35-A2E0-4D309EE2CE9C] with no body [debug] [JSONWP Proxy] Got response with status 200: "{\n \"value\" : {\n \"sessionId\" : \"43710C7E-2FDE-4A35-A2E0-4D309EE2CE9C\",\n \"capabilities\" : {\n \"device\" : \"iphone\",\n \"browserName\" : \"UICatalog\",\n
\"sdkVersion\" : \"10.3.1\",\n \"CFBundleIdentifier\" : \"com.example.apple-samplecode.UICatalog\"\n }\n },\n \"sessionId\" : \"43710C7E-2FDE-4A35-A2E0-4D309EE2CE9C\",\n \"status\" : 0\n}" [XCUITest] Merging WDA caps over Appium caps for session detail response [debug] [MJSONWP] Responding to client with driver.getSession() result: {"udid":"","app":"src/test/resources/executor/UICatalog.app","maxTypingFrequency":120,"newCommandTimeout":0,"platformVersion":"10.3","automationName":"XCUITest","platformName":"iOS","deviceName":"iPhone 6","device":"iphone","browserName":"UICatalog","sdkVersion":"10.3.1","CFBundleIdentifier":"com.example.apple-samplecode.UICatalog"} [HTTP] <-- GET /wd/hub/session/6909c363-12a5-4a21-9298-c7f750ba7e09 200 103 ms - 406 [HTTP] --> POST /wd/hub/session/6909c363-12a5-4a21-9298-c7f750ba7e09/location {"location":{"altitude":0,"latitude":20.672267,"hCode":1751403001,"class":"org.openqa.selenium.html5.Location","longitude":83.1649}} [debug] [MJSONWP] Calling AppiumDriver.setGeoLocation() with args: [{"altitude":0,"latitude":20.672267,"hCode":1751403001,"class":"org.openqa.selenium.html5.Location","longitude":83.1649},"6909c363-12a5-4a21-9298-c7f750ba7e09"] [debug] [XCUITest] Executing command 'setGeoLocation' [HTTP] <-- POST /wd/hub/session/6909c363-12a5-4a21-9298-c7f750ba7e09/location 501 30 ms - 122 org.openqa.selenium.WebDriverException: Method has not yet been implemented (WARNING: The server did not provide any stacktrace information) Command duration or timeout: 58 milliseconds Build info: version: '3.4.0', revision: 'unknown', time: 'unknown' System info: host: 'Abhays-MacBook-Air.local', ip: 'fe80:0:0:0:4fc:aa3c:d673:369e%en0', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.12.5', java.version: '1.8.0_131' Driver info: io.appium.java_client.ios.IOSDriver Capabilities [{app=src/test/resources/executor/UICatalog.app, networkConnectionEnabled=false, databaseEnabled=false, deviceName=iPhone 6, platform=MAC, maxTypingFrequency=120, newCommandTimeout=0, platformVersion=10.3, webStorageEnabled=false, locationContextEnabled=false, automationName=XCUITest, browserName=, takesScreenshot=true, javascriptEnabled=true, platformName=iOS, udid=0A41ECE4-6D03-4FEA-A82A-858FDBA6620E}] Session ID: 6909c363-12a5-4a21-9298-c7f750ba7e09 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:215) at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:167) at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:671) at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:42) at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:1) at io.appium.java_client.ios.IOSDriver.execute(IOSDriver.java:1) at io.appium.java_client.AppiumExecutionMethod.execute(AppiumExecutionMethod.java:46) at org.openqa.selenium.remote.html5.RemoteLocationContext.setLocation(RemoteLocationContext.java:50) at io.appium.java_client.AppiumDriver.setLocation(AppiumDriver.java:400) at org.openqa.selenium.html5.LocationContext$setLocation.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:110) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:122) at executor.com.bqurious.keyword.mobile.ios.BqIosSetLocationTest.setLocation(BqIosSetLocationTest.groovy:72) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) [HTTP] --> DELETE /wd/hub/session/6909c363-12a5-4a21-9298-c7f750ba7e09 {} [debug] [MJSONWP] Calling AppiumDriver.deleteSession() with args: ["6909c363-12a5-4a21-9298-c7f750ba7e09"] [debug] [BaseDriver] Event 'quitSessionRequested' logged at 1504013038955 (18:53:58 GMT+0530 (IST)) [debug] [JSONWP Proxy] Proxying [DELETE /session/6909c363-12a5-4a21-9298-c7f750ba7e09] to [DELETE http://localhost:8100/session/43710C7E-2FDE-4A35-A2E0-4D309EE2CE9C] with no body [debug] [JSONWP Proxy] Got response with status 200: "{\n \"value\" : {\n\n },\n \"sessionId\" : \"28E97E0B-DF47-4325-8991-A28B77134EDB\",\n \"status\" : 0\n}" [XCUITest] Shutting down sub-processes [XCUITest] Shutting down xcodebuild process (pid 37304) [XCUITest] xcodebuild exited with code 'null' and signal 'SIGTERM' [debug] [XCUITest] Found WDA derived data folder: '/Users/omprakash.mishra/Library/Developer/Xcode/DerivedData/WebDriverAgent-dikkwtrisltbeobjmfvpthwwekvs' [XCUITest] Setting '755' permissions to '/Users/omprakash.mishra/Library/Developer/Xcode/DerivedData/WebDriverAgent-dikkwtrisltbeobjmfvpthwwekvs/Logs/Test/Attachments' folder [debug] [XCUITest] Found WDA derived data folder: '/Users/omprakash.mishra/Library/Developer/Xcode/DerivedData/WebDriverAgent-folfazwwukpzfkegdblpnfuwlvfn' [XCUITest] Setting '755' permissions to '/Users/omprakash.mishra/Library/Developer/Xcode/DerivedData/WebDriverAgent-folfazwwukpzfkegdblpnfuwlvfn/Logs/Test/Attachments' folder [debug] [XCUITest] Not clearing log files. Use clearSystemFiles capability to turn on. [debug] [iOSLog] Stopping iOS log capture [Appium] Removing session 6909c363-12a5-4a21-9298-c7f750ba7e09 from our master session list [debug] [BaseDriver] Event 'quitSessionFinished' logged at 1504013039408 (18:53:59 GMT+0530 (IST)) [debug] [MJSONWP] Received response: null [debug] [MJSONWP] But deleting session, so not returning [debug] [MJSONWP] Responding to client with driver.deleteSession() result: null [HTTP] <-- DELETE /wd/hub/session/6909c363-12a5-4a21-9298-c7f750ba7e09 200 461 ms - 76

Daniel
  • 3,312
  • 1
  • 14
  • 31
Om Prakash
  • 793
  • 7
  • 14
  • why the question tagged with Android? and Java? What as a Java and Android developer I need to do with it? – Vladyslav Matviienko Aug 23 '17 at 06:05
  • @VladMatvienko actually OP trying to do automation on `Android` and `iOS` device using selenium Java. that's why..:) – Saurabh Gaur Aug 23 '17 at 08:17
  • @Omi What does your appium server logs read at the time you get an exception in `Location location = new Location(latitude, longitude, altitude); driver.setLocation(location);` ? – Naman Aug 29 '17 at 04:02
  • @nullpointer - I have edit my question and add Appium log please check once. – Om Prakash Aug 29 '17 at 10:33
  • @Omi I am hoping there would be more logs than just these DEBUGs. Please share complete logs for the event when you try to execute the code for iOS. – Naman Aug 29 '17 at 12:08
  • @nullpointer - Please check once again i have update all the log. – Om Prakash Aug 29 '17 at 13:30
  • @Omi One thing for sure, you missed [tag:groovy] there – Naman Aug 29 '17 at 15:13

4 Answers4

1

This AppleScript will work.

public static void setLocation(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 static String simulatorAppName() {
    return "Simulator";
}
Tan Su
  • 71
  • 7
0

It seems you need a AppiumDriver instead. According to this comment.

Gabain1993
  • 181
  • 1
  • 1
  • 14
0

You can use the setLocation method to set the latitude and longitude in Android emulator or iOS simulator:

import org.openqa.selenium.html5.Location;

Location loc = new Location(20.0, 12.5, 1000); // latitude, longitude, altitude driver.setLocation(loc);

Jayprakash Singh
  • 1,343
  • 3
  • 15
  • 28
0

I agree with solution to use apple script for setting custom geolocation for iOS simulator because Appium is not supporting such method for iOS (Apple is not providing API for XCTest framework to simulate GPS location)

Apple script:

#!/usr/bin/env bash

osascript -e 'tell application "System Events"
    tell process "Simulator"
        set frontmost to true
        click menu item "Custom Location…" of menu of menu item "Location" of menu "Debug" of menu bar 1
        set popup to window "Custom Location"
        set value of text field 1 of popup to (system attribute "Latitude")
        set value of text field 2 of popup to (system attribute "Longitude")
        click button "OK" of popup
    end tell
end tell'

I'm using python so here is my solution for Android and iOS:

    def set_geo_location(self, latitude, longitude, altitude):

    logging.info("set geo location")
    try:
        # Currently Apple does not provide any API for XCTest framework to simulate GPS location
        self.driver.set_location(latitude=latitude, longitude=longitude, altitude=altitude)
    except WebDriverException:
        # this will launch Apple Script to automatically set custom GPS location on iOS simulator
        subprocess.call([os.path.join(PROJECT_ROOT, "set_geolocation_for_iOS.sh")],
                        env={"Latitude": latitude, "Longitude": longitude})  # bash cli command for iOS simulator
    sleep(2)

And I'm passing GPS cordinates into that method:

set_geo_location("-77.85", "166.66", "10")