Protractor - Wait for async promise before doing next

16.8k views Asked by At

First of all, I've already checked various post and blogs concerning that point and I still can't figure out how to make it correctly.

I have tried many different combinaison of :

  • browser wait
  • protractor.controlFlow().execute
  • protractor.controlFlow().await(

...Still no success..

My problem

Within my beforeEach function, I'd like to call a protractor promise and wait for it to resolve before performing the rest of my code.

My Code

I've prepared this simple test for anyone willing to help me

describe('testAsync', function() {

  beforeEach(function() {
    console.log('beforeEach - step 1 ')

    browser.get("https://angularjs.org/");
    console.log('beforeEach - step 2 ')
    testFunc()
    console.log('beforeEach - after testFunc - step 3')

  });

  var testFunc = function(){

    console.log("testFunc - step 1")

    browser.wait(function() {
      var deferred = protractor.promise.defer();
      element(by.id('twitter-widget-1')).isPresent()
        .then(function (isPresent) {
          console.log("testFunc - step 2")
          deferred.fulfill(isPresent);
      });
      return deferred.promise;
    });

    console.log("testFunc - step 3")

  }

  it('test after BeforeEach', function() {
    console.log("Last trace")
  });

});

Current Output

[launcher] Running 1 instances of WebDriver
beforeEach - step 1
beforeEach - step 2
testFunc - step 1
testFunc - step 3
beforeEach - after testFunc - step 3
testFunc - step 2
Last trace

Expected Output

[launcher] Running 1 instances of WebDriver
beforeEach - step 1
beforeEach - step 2
testFunc - step 1
testFunc - step 2 // <------  This is within the promise resolve
testFunc - step 3
beforeEach - after testFunc - step 3
Last trace
2

There are 2 answers

2
P.T. On BEST ANSWER

I think this will get the output you want:

describe('testAsync', function() {

  beforeEach(function() {
    console.log('beforeEach - step 1 ');

    // `get` implicitly registers a promise with the control flow
    browser.get("https://angularjs.org/");

    console.log('beforeEach - step 2 '); // runs "before" get above returns!

    testFunc().then(function() {
       // use a then to explicitly chain a dependency off a promise
       console.log('beforeEach - after testFunc - step 3');
    })

    protractor.promise.controlFlow().execute(function() {
       console.log('beforeEach - after testFunc, via controlFlow - step 4');
    });

    console.log('beforeEach - end of beforeEach - everything registered, nothing done');
  });

  var testFunc = function(){

    console.log("testFunc - step 1")

    // return browser wait promise to caller
    // `wait` also implicitly registers with the control flow
    return browser.wait(function() {
      return element(by.id('twitter-widget-1')).isPresent()
        .then(function (isPresent) {
          console.log("testFunc - step 2")
          return true; // tell wait its done by resolving then promise->element promise->wait
      });
    });
  }

  it('test after BeforeEach', function() {
    console.log("Last trace")
  });

});
0
Brine On

The two console.logs (steps 1 & 3)in your testFunc, that are not wrapped in the promise, will fire immediately when you call the function. Which is proven by your output. Then your promise (which looks to be working great!), returns the step 2 log when the promise is resolved (but after the logs have already fired).

And thus, it looks like this is doing what you want? I.e. your beforeEach does indeed look like it's firing the async function before hitting your first spec.