Я научился создавать функции обратного вызова Javascript, и у меня есть базовое понимание «функционального программирования», поскольку это кажется достаточно простым. Однако я новичок в javascript и его синтаксисе, и я не могу найти хороший способ проверить указанный синтаксис в моей IntelliJ IDE.
Я создаю инструмент на основе Selenium, чтобы щелкнуть веб-элемент, дождаться, пока он перезагрузит страницу, станет устаревшим или дождаться тайм-аута. Причина, по которой я делаю это, - разделить веб-элементы на три категории: вызывает перезагрузку страницы, становится устаревшей, не изменяется. Для этого я сделал простой скрипт javascript с JavascriptExecutor, который поставляется с Java. Большая часть моего кода написана на java, и это язык, которым я владею. Я хочу узнать, как использовать javascript с java, чтобы делать то, что я хочу с веб-страницами.
У меня есть функция обратного вызова javascript:
function test(callback) {callback();}
function Return() {SeleniumTest.isPageReloaded.JavascriptWorking}
window.addEventListener('onload', test(Return));
который выполняется внутри Javascript Executor следующим образом:
System.setProperty("webdriver.chrome.driver",
"C:\\chromedriver_win32\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
String script = "function test(callback) {callback();}" +
"function Return()" +
"{SeleniumTest.isPageReloaded.JavascriptWorking}" +
"window.addEventListener('onload', test(Return));";
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript(script);
Это в основном сценарий Javascript из предыдущего, выполняемый как String. Как видите, я пытаюсь вызвать класс java. SeleniumTest - мой пакет, isPageReloaded - текущий класс, а JavascriptWorking - статический метод внутри этого класса. Этот статический метод выглядит так:
public static void JavascriptWorking(){
System.out.println("Javascript ran here");
}
Это должно было быть простым способом получить что-то из javascript в мой код Java. Причина, по которой я попробовал это, заключается в том, что я прочитал это:
Но потом я понял, что это не сработает, и стал копать глубже. Я прочитал, что Javascript и Java разделены по серверу и клиенту, и я получил некоторое представление об этом вопросе:
вызов java-методов в javascript-коде
Однако я не уверен на 100%, что это соответствует моему случаю, поскольку Javascript, который я выполняю, не поступает с веб-страницы, которую я тестирую, скорее я сам сделал это внутри кода Java как String. Кроме того, я все еще очень не понимаю, действительно ли ответ на этот вопрос относится ко мне. Есть только один, и он в основном просто говорит: «Установите что-нибудь, потому что java находится на стороне клиента, а javascript - на стороне сервера». Я (вроде как) понимаю, что означают эти термины, но не уверен, что javascript, который я создал в своем классе, будет считаться серверным, на самом деле, похоже, что это не так. Мне нужно пояснение по A: действительно ли javascript, который я запускаю / создаю в своем java-коде, находится на стороне сервера? B: если да, то может ли кто-нибудь дать мне базовое изложение того, как я буду вызывать Java-код с сервера? для этого требуются разрешения? Я предполагаю, что мне нужно связаться с указанным сервером, значит ли это, что я использую запросы GET и POSt? C: Если Javascript не является серверной частью, тогда он должен быть клиентским, и я могу легко назвать его, верно? Как мне это сделать?
Я хочу уметь бегать:
System.setProperty("webdriver.chrome.driver",
"C:\\chromedriver_win32\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
String script = "function test(callback) {callback();}" +
"function Return()" +
"{//insert callback code here}" +
"window.addEventListener('onload', test(Return));";
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript(script);
и получить либо запуск статического java-метода, что-то напечатанное на консоли, либо какое-либо другое средство, связывающее код javascript с javacode. Так, например, если я вставил правильный код для вызова своего статического метода:
SeleniumTest.IsPageReloaded.JavascriptWorking
(что снова выглядит так):
public static void JavascriptWorking(){
System.out.println("Javascript ran here");
}
Тогда я бы хотел увидеть «Здесь запущен Javascript» на моей консоли java. Используемый драйвер является взаимозаменяемым, я просто сначала использовал хром, потому что он быстрый. Все, что для этого нужно, - это включающий основной класс, и он ((должен)) запускаться, но никаких обещаний.
Цель состоит в том, чтобы получить что-то на java, которое я затем могу использовать в качестве флага, чтобы знать, что мой асинхронный javascript выполнен на java, и я могу продолжить выполнение программы. Я могу получить асинхронную часть javascript, и я это понимаю, мне просто нужна ссылка на мой код java.
Мне сказали, что обычный способ предоставить флаг для вашего java-кода - это создать определенный веб-элемент на странице с javascript и проверить его на java (отсюда и ссылка). Мне не хочется добавлять к тестируемым веб-страницам, потому что я хочу протестировать их, не редактируя / не изменяя их. Я, как правило, открыт для других простых решений, но самое большое, что мне нужно, - это разъяснение всей проблемы на стороне клиента, поскольку она специфична для моей настройки (Selenium java -> javascript -> java), где большинство вопросов касается только (javascript -> java) или наоборот.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Ссылка, которую вы упомянули о JS-вызове Java, предназначена для конкретного приложения, которое предназначено для этого. Я не говорю, что это невозможно (я писал плагины FF, основанные на аналогичном принципе), но в данном случае это не применимо. Это также требует специальной поддержки приложений (по умолчанию Javascript, выполняемый в браузере, сильно изолирован - он не может получить доступ к чему-либо за пределами его собственной области действия. Вызов других приложений сам по себе большой недостаток).
Скрипты, которые вы вводите, всегда находятся на стороне клиента, они выполняются только в браузере, который изолирован от самого кода Java. При этом нет ничего невозможного.
Хотел бы упомянуть две интересные особенности библиотеки Selenium, которые могут вам пригодиться.
executeAsyncScript. Webdriver предоставляет этот метод прямо из коробки, в значительной степени для той цели, с которой вы хотите его использовать.Когда вы используете executeScript, он вернется практически сразу после завершения - в вашем случае он просто вставит ваш слушатель с вашим кодом, а затем вернется. Используя executeAsyncScript, вы можете получить обратный вызов - именно то, что вы делаете. При вызове executeAsyncScript в ваш код добавляется метод callback по умолчанию в качестве последнего аргумента, который должен быть вызван вашим кодом JS для возврата метода.
Простой пример:
String script = "var callback = arguments[arguments.length - 1];" + //the last argument is the callback function
"var classToCall = 'SeleniumTest.IsPageReloaded';" + //the classname you want to return to call from Java in case of success)
"window.addEventListener('onload', callback(classToCall));";
//you can give any supported return value to the callback function. Here I assume that you want to call a static method. This is the class name that can be used later.
try {
JavascriptExecutor js = (JavascriptExecutor)driver;
//classToCall has the value we passed to the callback function
String classToCall = js.executeAsyncScript(script);
} catch (ScriptTimeoutException e) {
System.err.println("Uhhh... this failed I guess");
e.printStackTrace();
}
ExecuteAsyncScript не возвращается, пока не будет вызван обратный вызов - чтобы избежать бесконечных зависаний, вы можете установить свойство WebDriver.Timeouts.setScriptTimeout для управления этим. Если сценарий занимает больше времени, JavascriptExecutor выдаст исключение. После возврата вы можете создать экземпляр возвращенного класса и напечатать как
Class clazz = Class.forName(classToCall); //it is only necessary if the classname is dynamic. If it is the same always, you can just go ahead with that.
((IsPageReloaded)clazz.newInstance()).JavascriptWorking();
Конечно, вы можете вернуть более сложную структуру данных также из JS, где вы также указываете имя метода, но использование отражения здесь действительно оффтоп.
EventFiringWebdriver. Это полезный класс, который использует WebDriverEventListener для создания настраиваемых оболочек Webdriver с перехватчиками для многих событий, позволяя выполнять настраиваемый код до / после щелчка, до / после загрузки страницы ... и, помимо некоторых других, что более важно, до / после выполнения javascript в веб-драйвере. Вы можете использовать это, чтобы всегда вызывать один и тот же код при выполнении javascript - просто создайте свой собственный WebDriverEventListener.Вы можете найти больше информации о js-исполнителе здесь и о WebDriverEventListener здесь.