Sequence of execution with selenium-webdriver (for Node JS)

I am a little confused about the sequence of execution of selenium-webdriver commands.

What is the correct encoding for the next example. I want to:

  • FIRST, enter text in the text box
  • Then press the button

Does the following code provide the correct sequence?

   // 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); 
        }
      );

      

or should I do something like this?

// 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); 
    }
  );

      

If the second case is correct, how should I write the code when more than two actions are required per line? Iw would be very sophisticated and had to be supportive.

UPDATE:

Let's say I now want to clear the "txt" element found in the first findElement and do this before typing. Based on Louis' answer, I suspect it should be something like this: / p>

   // 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...

      

I do not find this very pleasant, it is too long and awkward, especially if there are more operations on one element. Is there a general way to shorten this to make it compact?

Something like chaining:

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

      

+3


source to share


1 answer


The first way you do it is correct. Some of the information that you seem to be missing is that the Java WebDriver implementation uses a "promise manager" to sequence promises for you. This is explained in "Flows of Control" in the manual. Here's an example:

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);

      

This will print the following lines to the console, always in the same order:

created foo! 5639
here 5657
found foo! 5670

      

The numbers will change, but they will always be> 5000 and will follow each other very closely (unless running on an overloaded or ridiculously slow system). First performed executeAsyncScript

to illustrate how an operation that takes time to complete, not to allow subsequent operations with the same driver to go ahead. Except that it executes the script and does not find the element, it is no different from findElement

: the promise manager waits until the operation is complete before the next operation can advance, even if the two operations are not explicitly sequenced with .then()

.

If the promise manager did not execute the sequence of operations one by one, then it .findElement(webdriver.By.tagName("body"))

will execute before the asynchronous script is executed and it will print "here"

before it "created foo!"

is printed to the console because the page has an element body

.



In addition, if the promise manager did not sequentially execute operations one after another, then the latter .findElement

would not be able to find the item with the id

value foo

. At the beginning of the script, I'll disable implicit waits, so the call findElement

certainly doesn't wait to appear foo

.

There are times when you might want to do it more like you do in the second snippet, but you don't include in your question any clear reason why it should be done this way.

Also, if it weren't for the Selenium promise manager, you would need to do something like the second snippet, because in general there is no sequence of promises for you.

Regarding your question on how to execute the sequence clear

and sendKeys

, you can do:

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

      

This structure uses the "framing" function of the "threads of control" function.

+5


source







All Articles