selenium-webdriver 的执行顺序(对于 Node JS)

Execution sequence with selenium-webdriver (for Node JS)

我对 selenium-webdriver 命令的执行顺序有点困惑。

以下示例的正确编码是什么。 我想:

  1. 首先,在文本框中输入文字
  2. 然后,单击按钮

以下代码是否保证顺序正确?

   // Enter the text
    driver.findElement(webdriver.By.id('txt'))
      .sendKeys('bla bla')
      .then(
        function() {},
        function(err) {
          console.log(err);
          done(err); 
        }
      );

    // Press the button
    driver.findElement(webdriver.By.id('btn'))
      .click()
      .then(
        function() {
          done();
        },
        function(err) {
          console.log(err);
          done(err); 
        }
      );

或者我应该这样做吗?

// Enter the pass
driver.findElement(webdriver.By.id('txt_pass'))    
  .sendKeys('sifra')
  .then(
    function() {
      // Press the login button
      driver.findElement(webdriver.By.id('btn_login'))
        .click()
        .then(
          function() {
            done();
          },
          function(err) {
            console.log(err);
            done(err); 
          }
        );
    },
    function(err) {
      console.log(err);
      done(err); 
    }
  );

如果第二种情况是正确的,当连续需要2个以上的动作时,代码应该怎么写?我会很复杂,必须维护。

更新:

假设现在我想清除在第一个 findElement 中找到的元素 "txt",并在我输入文本之前执行此操作。根据 Louis 的回答,我怀疑它应该是什么像这样:

   // Clear the textbox
    driver.findElement(webdriver.By.id('txt'))
      .clear()
      .then(
        function() {},
        function(err) {
          console.log(err);
          done(err); 
        }
      );

    // Enter the text
    driver.findElement(webdriver.By.id('txt'))
      .sendKeys('bla bla')
      .then(
        function() {},
        function(err) {
          console.log(err);
          done(err); 
        }
      );

    // go on with the further sequence...

我觉得这不是很好,它太长而且笨拙,尤其是在同一元素上有更多操作的情况下。有没有一种通用的方法可以缩短它,使其更紧凑?

类似链接的东西:

findElement('txt').clear().sendKeys('bla, bla'); // This does not work, as clear is a void

你的第一种方法是正确的。您似乎缺少的信息是 WebDriver 的 JavaScript 实现使用 "promise manager" 为您排序承诺。 这在 "Control Flows" 指南部分。这是一个例子:

var webdriver = require('selenium-webdriver');

var driver = new webdriver.Builder().
   withCapabilities(webdriver.Capabilities.chrome()).
   build();

// Do not implicitly wait for anything.
driver.manage().timeouts().implicitlyWait(0);

// Set the script wait timeout to 10 seconds.
driver.manage().timeouts().setScriptTimeout(10 * 1000);

driver.get('http://www.example.com');

function err() {
    console.log("ERR", arguments);
}

var start = Date.now();
driver.executeAsyncScript(
    "var done = arguments[0];" +
    "setTimeout(function () { document.body.innerHTML = '<p id=\"foo\"></p>'; done() }, 5000)")
    .then(function () {
        console.log("created foo!", Date.now() - start);
    },
          err);

driver.findElement(webdriver.By.tagName("body")).then(function () {
    console.log("here", Date.now() - start);
});

driver.findElement(webdriver.By.id("foo")).then(function () {
    console.log("found foo!", Date.now() - start);
}, err);

这将向控制台输出以下行,始终以相同的顺序:

created foo! 5639
here 5657
found foo! 5670

数字会有所不同,但它们总是 > 5000,并且彼此非常接近(除非 运行 在超载或慢得离谱的系统上)。首先执行的 executeAsyncScript 是为了说明需要一段时间才能完成的操作 而不是 将允许对同一驱动程序进行后续操作。除了它执行脚本而不是查找元素之外,它与 findElement 没有任何不同:promise 管理器等待直到操作完成,然后才能继续下一个操作,even 如果两个操作没有使用 .then().

明确排序

如果 promise 管理器没有一个接一个地对操作进行排序,那么 .findElement(webdriver.By.tagName("body")) 将在异步脚本完成之前执行,并且它会在 "created foo!" 之前打印 "here"打印到控制台,因为该页面确实有一个 body 元素。

另外,如果承诺管理器没有一个接一个地对操作进行排序,那么最后一个 .findElement 将无法找到 id 值为 foo 的元素。在脚本的早期,我关闭了隐式等待,因此 findElement 调用肯定不会 等待 等待 foo 出现。

种情况下,您更希望像在第二个代码段中那样做,但您没有在问题中包含任何明确的理由应该这样做方式。

此外,如果不是 Selenium 的承诺管理器,那么您 必须 执行类似于您的第二个代码段的操作,因为通常没有任何顺序承诺适合您。

关于您关于如何对 clearsendKeys 进行排序的问题,您可以这样做:

driver.findElement(webdriver.By.id('txt')).then(function (el) {
    el.clear();
    el.sendKeys('bla bla');
});

此结构使用 "control flows" 功能的 "framing" 特性。