WebDriver + GeoAPI

Всем привет,
столкнулся с такой проблемой: нужно сделать эмуляцию входа пользователя с определенно точки на карте. после общения с гуглом нашел простое решение

    @Test
    public void getLocation() throws InterruptedException {
        driver.get("https://www.google.com/maps");
        Thread.sleep(10000);
        FirefoxProfile profile = new FirefoxProfile();
        profile.setEnableNativeEvents(false);
        profile.setPreference("geo.wifi.uri", "file://D:/trash/location.json");
        driver = new FirefoxDriver(profile);
    }

+JSON файл

{ 
    "status": "OK",
    "accuracy": 10.0,
    "location": {
        "lat": 50.850780,
        "lng": 4.358138,
        "latitude": 50.850780,
        "longitude": 4.358138,
        "accuracy": 10.0
    }
}

но в открывшейся карте все равно указывает на текущее местоположение, а не на заданное.
что я не так понял?

Мочить геолокацию и ее возможные ошибки лучше всего через нативные функции, переопределяя нужные значения.

https://gist.github.com/fat-troll/82caf02fa3bcc85db113

Все что нужно - переопределить возвращаемые значения в window.navigator.geolocation.getCurrentPosition().
Если конкретно по вашей проблеме, не все так просто, припоминаю что там еще пару флагов было, в стиле geo.***.testing.

а чтото похожее только на Java есть? а то js немного не подходит?))

Почему не подходит жс? Просто вызываете в executejs (или как там он у вас называется?) js код, который переназначает все координаты. По сути вы просто мОчите вызовы браузера. Вообще в многих фреймворках, которые я видел это уже реализовано, т.к. метод давно доступен по JsonWireProtocol ( GitHub - SeleniumHQ/selenium-google-code-issue-archive: Archive, please see main selenium repo ). Но у каждого метода есть нюансы. С антивными методами не получится симулировать отсутствие геолокации, с мОканием жс-а нужно запускать браузер с “always ask geolocation”, в хроме это

{ profile.default_content_settings.geolocation': 0 }

У меня в данный момент написан огромный тестовый метод не просто для изменения, но и для отслеживания изменения, изменения скорости, accuracy и тд и тп

Если рассматривать чуть более сложный вариант чем я кидал выше, то это выглядит примерно так. Аттачишь жс к своей странице (я добавляю ее на этапе запуска сервера, можно просто жс-ку добавить перманентно) и работаешь с ними. Мок основных функций примерно вот такой:

   var obs = [],
        geo = navigator.geolocation,
        point = {
          coord: {
              latitude: {{lat}},
              longitude: {{lon}},
              accuracy: 15
          }
        };

    window.setPosition = function(lat, lon) {
      point.coord.latitude = lat;
      point.coord.longitude = lon;
      for (var idx=0; idx < obs.length; idx++) {
          obs[idx](point);
      }
    };

    geo.clearWatch = function(obsIdx) {
      obs.splice(obsIdx, 1);
    };

    geo.watchPosition = function(success) {
      obs.push(success);
      setTimeout(success, 0, point);
      return obs.length-1;
    };

    geo.getCurrentPosition = function(success) {
      setTimeout(success, 0, point);
    };

Можно заменить значения координат плейсхолдерами и менять их “на лету”, или жсом через window.setPosition(), в примере как раз реализованны оба варианта сразу.

1 лайк

та да , ето задача API-шки или JS екзекютора…сомневаюсь что webdriver “сам по себе” как то тут поможет

взял кусок js

    var obs = [],
    point = {
        coord: {
            latitude: 5.2145, longitude: 52.2145, accuracy: 15}
    };
    setPosition = function(lat, lon) {
    point.coord.latitude = lat;
    point.coord.longitude = lon;
    for (var idx=0; idx < obs.length; idx++) {
    obs[idx](point);
    }
    };

вызвал это в Java:

    ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript");
        engine.eval(new FileReader("src/jscripts/geolocation.js"));
        Invocable invocable = (Invocable) engine;
        Object result = invocable.invokeFunction("setPosition", "5.2145, 52.2145");
        System.out.println(result);
        driver = new FirefoxDriver();
        //driver.manage().deleteAllCookies();
        driver.get("http://www.msn.com/");

и все равно у меня не меняются координаты, меня бросает на текущие

хм…почему то result null

А почему именно этот кусок? Сам по себе он ничего не делает :slight_smile:

еще один момент, при чтении js файла с java у меня естественно ругается на отсутствие либ для js:

javax.script.ScriptException: sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: “describe” is not defined. (#4) in at line number 4

не подскажете как это решается, в js просто npn инсталит это все…а как тут быть хз…

какой describe? ты его из первого самого примера взял? тебе не нужны никакие жс либы, мой пример на чистом js.

это я вижу, но когда вызываю его из java кода то мне выдает ошибку, ошибка логичная, ибо оно не видит либ с жс…либо я чегото неправвильно понимаю либо чтото неправильно делаю

Тебе не нужен describe() из первого примера по ссылке. Этот пример чисто для mocha, жс-ного тестового фреймворка.
Все что тебе надо - замОкать несколько нативных функций в жс-е (выше в моем примере с кодом). Вызови этот код в контексте страницы, в которой выполняется тест. Ты все правильно сделал в предыдущем комменте, но вызвал только тебе нужен не только setPosition (который по сути не делает ничего), тебе нужно еще и переназначить clearWatch, watchPosition и getCurrentPosition (последняя по сути самая главная, которая и отвечает за нахождение в данный момент).

все равно это как то сложно, пока сроки не поджимают попробую поискать какое то решение попроще
наткнулся на такую либу

может это оно?

    FirefoxProfile profile = new FirefoxProfile();
    profile.setPreference("geo.prompt.testing", true);
    profile.setPreference("geo.prompt.testing.allow", true);
    profile.setPreference("geo.enabled", true);
    profile.setPreference("geo.wifi.uri", "file:///D:/trash/location.json");

работает
осталось разобратся как это настроить на chrom

c хромом с версии 29 не получится :slight_smile: они к урлу добавляют GET параметры, которые ломают json.

да уж, то что есть работает только с сайтом bestvpn.org
на msn и картах гугл не работает…бред бредовый, теперь бы узнать заработает ли это с нашим внутренним апи которое пишеться (

Карты гугла используют свои мОки встроенного апи, поэтому там есть воркэраунды. Чтобы не париться что и как надо переназначать, уже есть готовое решение (проверял, работает):

и сново уперся в ту же ошибку
после

        WebDriver driver = new FirefoxDriver();
    
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("JavaScript");
    // read script file
    engine.eval(Files.newBufferedReader(Paths.get("src/jscripts/min.js"), StandardCharsets.UTF_8));
    Invocable inv = (Invocable) engine;
    // call function from script file
    inv.invokeFunction("GeoSim", "param");
    driver.get("https://www.google.com.ua/maps");

}

Exception in thread “main” javax.script.ScriptException: sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: “window” is not defined

min.js -geolocation-simulator/geolocation-simulator.js at master · russellsamora/geolocation-simulator · GitHub

как то не сложилось у меня с JS

Потому что никакого контекста window у тебя нет. Тебе сначала надо перейти на нужную страницу и только потом в ее контексте выполнять жс.

пробовал и такой вариант, те. сначала делаю “driver.get…” а потом запускаю скрипт…результат тот же
Исправлено
проблема была в том что я вызывал независимо скрипт, после вызова с под вебдрайвера все заработало.

и еще вопрос, я в упор не вижу в библиотеке geoАpi метода который будет делать чтото похожее на setPosition…