Skip to content

[WebDriverJS] - Control flow out of order inside forEach #444

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
juliemr opened this issue Apr 11, 2015 · 1 comment
Closed

[WebDriverJS] - Control flow out of order inside forEach #444

juliemr opened this issue Apr 11, 2015 · 1 comment
Assignees
Labels
I-defect Something is not working as intended

Comments

@juliemr
Copy link
Contributor

juliemr commented Apr 11, 2015

We've run into a complex case where the control flow can get out of order when using webdriver.WebElement.prototype.findElement inside a forEach. Here is the a reduced case using only the control flow:

var webdriver = require('selenium-webdriver');
var flow = webdriver.promise.controlFlow();

var FakeWebElement = function(text) {
  return {
    getText: function() {
      return flow.execute(function() {
        return webdriver.promise.delayed(200).then(function() {
          return text;
        });
      });
    },
    findElement: function() {
      var newElement = flow.execute(function() {
        return new FakeWebElement(text + '-child');
      })
      return new FakeWebElementPromise(newElement);
    }
  };
};

var FakeWebElementPromise = function(elementPromise) {
  this.then = elementPromise.then.bind(elementPromise);
};

var getFakeDriver = function() {
  var flow = webdriver.promise.controlFlow();
  return {
    findElements: function() {
      return flow.execute(function() {
        return webdriver.promise.delayed(500).then(function() {
          return webdriver.promise.fulfilled([
            new FakeWebElement('a'),
            new FakeWebElement('b'),
            new FakeWebElement('c'),
            new FakeWebElement('d')
          ]);
        })
      })
    }
  };
};

var driver = getFakeDriver();

driver.findElements().then(function(elems) {
  console.log('length: ' + elems.length);
  elems.forEach(function(webElem, index) {
    webdriver.promise.fulfilled(webElem).then(function(fElem) {
      return fElem;
    }).then(function(pElem) {
      console.log('index for pElem: ' + index);
      return pElem.findElement();
    }).then(function(webElem2) {
      webElem2.getText().then(function(text) {
        console.log('index for webElem2: ' + index);
      });
    });
  })
});

The output is:

length: 4
index for pElem: 0
index for pElem: 1
index for pElem: 2
index for pElem: 3
index for webElem2: 1 // Unexpected!!
index for webElem2: 0 // Unexpected!!
index for webElem2: 2
index for webElem2: 3

See angular/protractor#2026 for the practical use case that surfaced this issue.

WebDriverJS is version 2.45.1
This works as expected with version 2.44.0

@andreastt andreastt added C-js A-needs investigation TLC needs to do discovery labels Apr 12, 2015
@jleyba jleyba self-assigned this Apr 12, 2015
@jleyba jleyba added I-defect Something is not working as intended and removed A-needs investigation TLC needs to do discovery labels Apr 12, 2015
@jleyba
Copy link
Contributor

jleyba commented Apr 12, 2015

Further reduced to:

var assert = require('assert');
var webdriver = require('selenium-webdriver');
var flow = webdriver.promise.controlFlow();

var messages = [];
flow.on('idle', function() {
  assert.deepEqual(
    ['a.1', 'b.1', 'c.1', 'd.1',
     'a.2', 'b.2', 'c.2', 'd.2'],
    messages);
});

flow.execute(function() {
  return webdriver.promise.fulfilled(['a', 'b', 'c', 'd']);
}).then(function(steps) {
  steps.forEach(function(step) {
    webdriver.promise.fulfilled(step)
    .then(function(){})  // Passes if this is commented out.
    .then(function() {
      messages.push(step + '.1');
      return flow.execute(function() {});  // Passes if this is commented out.
    }).then(function() {
      flow.execute(function() {}).then(function(text) {
        messages.push(step + '.2');
      });
    });
  })
});

Which results in

/Users/jleyba/Development/test/node_modules/selenium-webdriver/lib/goog/async/nexttick.js:39
  goog.global.setTimeout(function() { throw exception; }, 0);
                                            ^
AssertionError: [ 'a.1', 'b.1', 'c.1', 'd.1', 'a.2', 'b.2', 'c.2', 'd.2' ] deepEqual [ 'a.1', 'b.1', 'c.1', 'd.1', 'b.2', 'a.2', 'c.2', 'd.2' ]
    at /Users/jleyba/Development/test/test3.js:7:10
    at webdriver.EventEmitter.emit (/Users/jleyba/Development/test/node_modules/selenium-webdriver/lib/webdriver/events.js:52:17)
    at promise.ControlFlow.shutdown_ (/Users/jleyba/Development/test/node_modules/selenium-webdriver/lib/webdriver/promise.js:1998:8)
    at null.<anonymous> (/Users/jleyba/Development/test/node_modules/selenium-webdriver/lib/webdriver/promise.js:2056:12)
    at goog.async.run.processWorkQueue (/Users/jleyba/Development/test/node_modules/selenium-webdriver/lib/goog/async/run.js:125:21)
    at runMicrotasksCallback (node.js:337:7)
    at process._tickCallback (node.js:355:11)
    at Function.Module.runMain (module.js:503:11)
    at startup (node.js:129:16)
    at node.js:814:3

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
I-defect Something is not working as intended
Projects
None yet
Development

No branches or pull requests

3 participants