0

I'm looking for more help in relation to the SO question get an array of elements from findElement(By.className())

This is about using the javascript implementation of the Selenium Webdriver to automate a website component.

From the example given in the referenced question, I can't figure out how to pass the allHtml array back out to the calling methods and up to the gherkin step definition where the test logic resides.

I've tried several approaches (too many to document), with many hours of Googling. I'm just not getting how to pass anything back from a promise (once it is resolved and we have allHtml defined). Yes, I can output to the console, but that doesn't help in a real world testing scenario where I need to assert a pass or fail based on a comparison of actual vs expected.

Promises are painful. They are new to me, and will hurt until I wrap my head around them.

As a last resort (and probably only solution) I'm going to look into using webdriver-sync in order to avoid promises which are native to the javascript version of webdriver.

Any help or guidance would be appreciated in understanding how to pass things back from a promise once it is fully resolved, if it's possible. Promises seem to me to be about using things when they're ready, and not before, or after.

Thank, Al.

AddApplicationPage.prototype.getFilteredAppLibraryTemplates = function (context) {
    var eleArray = this.getAppLibraryTemplateIcons(context);
    return eleArray;
}

AddApplicationPage.prototype.getAppLibraryTemplateIcons = function (context) {

    var pendingElements = context.driver.findElements(By.className('appLibrary-templateIcon'))

    pendingElements.then(function (elements) {
        var pendingHtml = elements.map(function (elem) {
            return elem.getInnerHtml();
        });
        promise.all(pendingHtml).then(function (allHtml) {
            // how do i pass allHtml back up the food chain 
            // so i can do some comparison to the expected list
        });
    });
}
Community
  • 1
  • 1

2 Answers2

0

You can't.

An asynchronous function is still an asynchronous function. You can't return the result from it. The result doesn't exist when findElements finishes executing.

A promise is just a convenient object that you can return, pass around, and assign callback functions to whenever you like.


You said you were using Gerkin, so I'm assuming you are using Cucumber.js. Look at its documentation:

  this.Given(/^I am on the Cucumber.js GitHub repository$/, function (callback) {
    // Express the regexp above with the code you wish you had.
    // `this` is set to a World instance.
    // i.e. you may use this.browser to execute the step:

    this.visit('https://github.com/cucumber/cucumber-js', callback);

    // The callback is passed to visit() so that when the job's finished, the next step can
    // be executed by Cucumber.
  });

The first argument passed to the function you pass to the step definition is a callback that you call when you have your result.

Don't worry about passing the result back. Just pass the callback function forward and call it when you are done.

Community
  • 1
  • 1
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • I have a solution of sorts, but I will definitely play with this as well. Thanks, Quentin. I'll mark an answer as best when I play with callbacks and know which works best for me. – Al Pieroway Sep 08 '16 at 14:51
  • I'm marking this one as correct despite my not understanding it well enough to make it work. My solution worked for me but doesn't follow the intended coding practices for cucumber.js. – Al Pieroway Sep 12 '16 at 15:12
0

Solved it, well enough. My desire was to do that validation of elements (compared to expected) in the gherkin step definition. I found that if I moved the conversion of the promise to the array out to the step definition it worked as well and didn't bury the validation process. Worse case I'll use this solution.

AddApplicationPage.prototype.getAppLibraryTemplateIcons = function (context) {
    return context.driver.findElements(appLibraryTemplateIcon);
}

this.Then(/^I should see matching filtered results$/, function () {

  var pedingElements = addApplicationPage.getAppLibraryTemplateIcons(this);

  pedingElements.then(function (elements) {

      var pendingHtml = elements.map(function (elem) {
          return elem.getInnerHtml();
      });

      promise.all(pendingHtml).then(function (allHtml) {
          var expectedHtml = ["Google Apps"];        
          expect(expectedHtml).to.deep.equal(allHtml);    
      })

  });                                                                   
});