【问题标题】:Selenium: How do I write a synchronous Selenium automation?Selenium:如何编写同步 Selenium 自动化?
【发布时间】:2018-12-04 13:05:40
【问题描述】:

我现在越来越沮丧,希望能在stackexchange上找到一些帮助。

首先要做的事情:我不是经验丰富的 Javascript 开发人员,可能根本不是经验丰富的开发人员,但我想我知道如何使用基本脚本 - 我知道一点 C#、Java 和 co.. 对于我的当前的网络自动化脚本我认为赶上并尝试用 Javascript 编写是一个好主意,但现在我正处于一个阶段,我考虑从头开始使用一种不同的、不太容易混淆的语言。

请问,谁能告诉我,我怎么能让我的代码从上到下以同步方式执行?

经过大量的谷歌搜索,到目前为止,我已经尝试了以下方法:

  • #! /usr/bin/env node 开始第1 行,并在终端使用./app.js 开始
  • 将每个 function() 设为 async function()
  • 在所有方法上使用await()

但即使是现在,当我运行脚本时,它也会向我抛出很多 UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'isDisplayed' of undefined 和类似的东西,这让我猜想,该节点正在异步运行我的一些方法/函数。在浏览器窗口启动和加载之前,这些异常就会在控制台中弹出。

我正在使用: * 硒网络驱动程序 3.6.0 * 火狐 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();

据我所知,我正在使用 async init() 函数启动 webdriver 和 firefox。在这里,我对所有这些方法都使用了 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

我真的很感谢这里的一些帮助。

【问题讨论】:

  • 我似乎找到了一种方法,可以解决很多问题。通过在run() 函数中调用init(); 函数,它的运行大部分是同步的,正如我所期望的那样。尽管如此,driver.sleep(1000); 并没有像我想要的那样触发。该脚本似乎完全忽略了一秒钟的等待时间,并继续 forarray.forEach(){}loops 的所有步骤而不识别 1 秒睡眠。有什么方法可以强制脚本等待?我正在运行的站点使用了大量的 Javasctipt,我需要等待一段时间(可能不到 1 秒),站点才能完全显示新结果。

标签: javascript selenium ubuntu asynchronous selenium-webdriver


【解决方案1】:

async/await 函数纯粹同步运行的答案似乎是让它只运行一个函数。

我的意思是,不能先用init(); 初始化浏览器、变量和其他东西,然后之后调用run(); 来实现自动化本身。

不如构建一个小函数main(),调用这两个函数:

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

这似乎与异步运行有关。尽管如此,我仍然对await driver.sleep(1000); 感到困扰,这似乎没有按预期工作。

通过进一步的谷歌搜索,我还阅读了here 关于webdriver-sync。但这是关于该主题的相当古老的评论。我不太确定 webdriver-sync 的更新程度。我可能会尝试一段时间。

如果有人有关于如何解决的更多信息,例如不工作的await driver.sleep(1000); 方法,在

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

我真的很高兴阅读。

【讨论】:

    【解决方案2】:

    您对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 可以省略,因为 Promise 中的 Promise 会自动解包。所以return element.sendKeys( 的工作原理是一样的,但使用await 可能不会那么混乱。

    【讨论】:

      【解决方案3】:
      async function surrounding_function(){
          for(value of array){
              for(){
                  for(){
                      await driver.sleep(1000);
                  }
              }
          }
      }
      

      driver.sleep() 返回一个 Promise 对象,该对象在休眠时间过去后实现。 await 停止执行,直到 Promise 得到解决(履行或拒绝)。解释器同时执行任务队列中的其他任务。忽略 await 语句的值是可以的,因为这只会忽略 Promise 的值;而不是 Promise 本身。异步函数返回一个 Promise。 .forEach 方法会忽略作为回调传入的函数的返回值,因此忽略 Promise 并继续执行而不等待 Promise 解决。调用异步函数首先将新任务推送到任务队列中。如果没有await,这些任务会以意外的顺序执行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-06
        • 1970-01-01
        • 2018-05-28
        • 2018-03-28
        • 1970-01-01
        • 2018-06-10
        相关资源
        最近更新 更多