Search code examples
seleniuminternsaucelabsleadfoot

Leadfoot + sauce: mapping a collection of elements using getAttr fails in mobile only


My use case varies for this, but in general i'm trying to collect a bunch of elements and then apply _.map() to each. The problem is that this series of .getAttribute() calls can cause a test that works locally to fail against a remote server like sauce/android.

One example: collecting all <div class='article'><a href='articles/{id}'> on a page and then getting the hrefs. it might look something like this, and this approach will work until i test on a mobile (android) sauce environment. then I get a timeout.

Is it possible this is an issue related to my android environment capabilities? To piling up so many requests? I've tried scaling my test down from using 75 articles to only 45 and i've upped the timeout to 60s and still the mobile test fails. locally with chromedriver is fine, chrome desktop + sauce is fine.

Not my actual test but an approximation of the code i'm talking about:

/// ... return this.remote
.findAllByTagName('div.article a')
    .then(function (articles) {
      var promises = articles.map(function(article) {
        return article.getAttribute('href');
      });
      Promise.all(promises)
      .then(function (hrefs) {
        uniques = _.uniq(hrefs);
        assert(hrefs.length === uniques.length);
      });
    });

Solution

  • Since you're seeing a timeout error, I'd suggest continuing to increase the test timeout until the test passes. The mobile testing environments on Sauce are both slower to initialize and slower to operate than the desktop environments, so it's quite possible that a test with many requests is simply very slow.

    One way to speed things up would be to use an execute block to gather the references, like:

    .then(function (articles) {
        return this.parent.execute(function (articles) {
            return articles.map(function (node) {
                return node.getAttribute('href');
            });
        }, [ articles ]);
    })
    

    In the above snippet, the articles element array is passed as an argument to the execute block. The remote WebDriver will deserialize the element references into actual DOM elements that can be operated on in the execute code. This is significantly more efficient than using individual getAttribute requests for each element since only a single request will be made to the remote browser.