Selenium: Как мне написать синхронную автоматизацию Selenium? - PullRequest
0 голосов
/ 26 июня 2018

В настоящее время я становлюсь все более и более разочарованным, и я надеюсь найти некоторую помощь по stackexchange.

Перво-наперво: я не опытный разработчик Javascript, возможно, вообще не опытный разработчик, ноНаверное, я знаю, как работать с базовыми сценариями - я немного знаю C #, Java и co. Для моего текущего сценария веб-автоматизации я подумал, что было бы неплохо догнать и попробовать написать на Javascript, но сейчасЯ нахожусь в точке, где я считаю, что начинать с нуля с другого, не столь запутанного языка.

Пожалуйста, кто-нибудь может сказать мне, как, черт возьми, я могу позволить моему коду выполняться синхронно сверху вниз?

После долгих часов поисков в Google, я попробовалдо сих пор:

  • начинайте строку 1 с #! /usr/bin/env node и начинайте в терминале, используя ./app.js
  • , делайте каждую функцию () функцией async ()
  • использовать await во всех методах ()

Но даже сейчас, когда я запускаю скрипт, он бросает мне много UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'isDisplayed' of undefined и подобных вещей, что позволяет мне догадаться, что этот узелвыполняет некоторые из моих методов / функций асинхронно.Эти исключения появляются в консоли задолго до того, как окна браузера открываются и загружаются.

Я использую: * selenium-webdriver 3.6.0 * Firefox 60.0.2 * узел 8.10.0

Мой код выглядит примерно так:

const {Builder, By, Key, until, manage} = require('selenium-webdriver');
const firefox   = require('selenium-webdriver/firefox');
const webdriver = require('selenium-webdriver');
const fs        = require('fs');

//
// declaring lots of global variables, I need in my functions
//

async function init(){
    let options = await new firefox.Options()
    .setProfile('/home/ruphus/.mozilla/firefox/selenium_profile.backtesting');

    let driver = await new webdriver.Builder()
        .forBrowser('firefox')
        .setFirefoxOptions(options)
        .build();
    await driver.get('https://www.someurl.com/')
        .then(openStrategySettings())
        .then(btnStrategySettings.click());

// ... defining webelements/locations to the previously created objects - using xpath

inputPeriod = await driver.findElement(By.xpath("//div[@id='header-toolbar-intervals']/div/div/div"));
}


async function openStrategySettings() {
    if (!someWebelement.isDisplayed()){
        await tabStrategyTester.click();
    }
}
async function inputValue(element, value) {
    await element.sendKeys(Key.BACK_SPACE + Key.BACK_SPACE + value.toString());
}
async function run(){
// this is the main function with a couple of for loops and array.forEach(function()... things
}

init();
run();

Итак, насколько я понимаю, я запускаю webdriver и firefox с моей функцией async init().Здесь я использую await для всех этих методов.После запуска webdriver / firefox я определяю переменные Object для местоположений (я хочу, чтобы это происходило, когда браузер запущен и загружен).

Но почему-то я не понимаю, почему, кажется, скрипт запускает всемои функции и весь код, который он может найти сразу после запуска скрипта.На самом деле кажется, что он ждет загрузки браузера последним.Перед окончательной загрузкой я получаю несколько (8) UnhandledPromiseRejectionWarning ..

  • UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'sendKeys' of undefined
  • UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'click' of undefined
  • UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'isDisplayed' of undefined

Я был бы очень признателен за помощь здесь.

Ответы [ 3 ]

0 голосов
/ 08 июля 2018

Ваше использование await почти правильно.Но метод .then ожидает функцию (или две) в качестве аргумента.Вы выполняете вызовы функций внутри then() и фактически передаете результат вызова этой функции в then() вместо самой функции.

async function init(){
    let options = await new firefox.Options()
    .setProfile('/home/ruphus/.mozilla/firefox/selenium_profile.backtesting');

    let driver = await new webdriver.Builder()
        .forBrowser('firefox')
        .setFirefoxOptions(options)
        .build();
    await driver.get('https://www.someurl.com/')
        .then(openStrategySettings)  // <-- XXX pass function
        .then(() => btnStrategySettings.click());  // <-- XXX if the argument isn't a plain function name, arrow functions come handy 

// ... defining webelements/locations to the previously created objects - using xpath

inputPeriod = await driver.findElement(By.xpath("//div[@id='header-toolbar-intervals']/div/div/div"));
}


async function openStrategySettings() {
    if (! await someWebelement.isDisplayed()){  // <-- XXX isDisplayed() is async (returns Promise), await its settlement
        return await tabStrategyTester.click();  // <-- XXX never ignore a Promise
    }
}
async function inputValue(element, value) {
    return await element.sendKeys(Key.BACK_SPACE + Key.BACK_SPACE + value.toString());  // <-- XXX never ignore a Promise
}

Когда return выводит результат асинхронной функции внутриАсинхронная функция, await может быть опущена, так как Обещание внутри Обещания автоматически разворачивается.Так что return element.sendKeys( будет работать так же, но использование await может быть менее запутанным.

0 голосов
/ 08 июля 2018
async function surrounding_function(){
    for(value of array){
        for(){
            for(){
                await driver.sleep(1000);
            }
        }
    }
}

driver.sleep() возвращает объект Promise, который выполняется после истечения времени ожидания.await останавливает выполнение до тех пор, пока Обещание не будет выполнено (выполнено или отклонено).Интерпретатор выполняет другие задачи из очереди задач.Игровое значение оператора await в порядке, поскольку оно игнорирует только значение Обещания;не само обещание.асинхронные функции возвращают обещание.Метод .forEach игнорирует возвращаемое значение функции, которую вы передаете в качестве обратного вызова, и, таким образом, игнорирует обещание и продолжает выполнение, не дожидаясь завершения обещания.Вызов асинхронных функций помещает новые задачи в очередь задач в первую очередь.Без await эти задачи выполняются в неожиданном порядке.

0 голосов
/ 26 июня 2018

Ответ, позволяющий функциям async / await работать исключительно синхронно, состоит в том, чтобы позволить запускать только ОДНУ функцию.

Под этим я подразумеваю, что нельзя сначала init(); инициализировать браузер и переменные и прочее и после , что вызывает run(); для самой автоматизации.

Скорее следует построить небольшую функцию main (), которая вызывает эти две функции:

async main(){
  await init;
  await run();
}
main();

Это, похоже, помогает при асинхронных запусках.Тем не менее, я все еще беспокоюсь о await driver.sleep(1000);, который, кажется, не работает должным образом.

При дальнейшем поиске я также прочитал здесь о webdriver-sync .Но это довольно старый комментарий на эту тему.Я не слишком уверен, насколько актуальным является webdriver-sync .Я, вероятно, попробую это когда-нибудь.

Если у кого-то есть дополнительная информация о том, как решить, например, неработающий метод await driver.sleep(1000);, используемый в

array.forEach(async function(entry){
  for(){
    for(){
      await driver.sleep(1000);
    }
  }
}

, я был бы очень рад прочитать о.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...