0

With protractor we can do this:

beforeEach(function() {
  browser.get(myLoginUrl);
  this.username = element(by.model('username'));
  this.password = element(by.model('password'));
  this.loginButton = element(by.css('[ng-click="login()"]'));

  this.username.sendKeys(...);
  this.password.sendKeys(...);
  this.loginButton.click();

  // i'm logged in
});

And this will all just work, because each of the above methods, will for all practical purposes run in serial waiting each in turn to run.

Now I've built a PageObject model object to model my login page which needs to be used to test other pages. I'm trying to figure out how to get my PageObject model methods to work like the protractor methods, running in 'series'.

As part my login process, a session id is returned that is needed for subsequent HTTP gets/posts. After login, I want to test the home page, so I have test code like this using a Login PageObject:

beforeEach(function() {
  // code from above has been refactored into a page object. here i can just
  // call loginPage.loginAs(...) and it will log the user in and return the
  // session id
  var sessionId = loginPage.loginAs('testuser@example.com', 'mypassword');

  // construct the home PageObject with a sessionId because homePage.get() will
  // need to put the sessionId in the url
  homePage = new HomePage(sessionId);
});

// test we can access the page
it('is accessible', function() {
  homePage.get();

  expect(browser.getCurrentUrl()).toMatch(homePage.homePageRegex);
});

I want

homePage = new HomePage(sessionId)

to wait and not run until

var sessionId = loginPage.loginAs(...)

has successfully completely and returned a valid sessionId. Similar to how the protractor elements themselves work.

Using something like:

loginPage.loginAs('testuser@example.com', 'mypassword').then(function(sessionId) {
  homePage = new HomePage(sessionId);
});

fails because this will the beforeEach function will exit and the first it() will run and try to perform homePage.get() before the sessionId has been set.

I've been toying around with:

browser.driver.controlFlow().execute(function() {...});

to somehow get the code syncing up and executing in parallel but I have quite got the recipe down.

Does anyone know to accomplish what I'm trying to do?

I'm trying to avoid a lot of then() chaining per the Control Flow section of the doc:

https://code.google.com/p/selenium/wiki/WebDriverJs#Understanding_the_API

lostdorje
  • 6,150
  • 9
  • 44
  • 86

2 Answers2

0

Protractor tries to hide the fact that most of the interesting methods do not actually do what they say, but just enqueue a promise to do what you've asked. So, while the code looks like its running serially, its not.

In your case, you want to use the then() approach to initialize the HomePage:

loginPage.loginAs('testuser@example.com', 'mypassword').then(function(sessionId) {
  homePage = new HomePage(sessionId);
});

But, you need to make the code in the subsequent it wait for that then to complete. The then method returns a promise for this reason (see the WebDriverJS doc).

So, save the promise from the then. You can also use this promise to pass the result along, so I'm going to call the promise homePage (but read it, like most Protractor results as "home page promise").

var homePage;

...

homePage = loginPage.loginAs('testuser@example.com', 'mypassword').then(function(sessionId) {
  return new HomePage(sessionId);  // return the page via the promise
});

And then chain off that promise in your test:

homePage.then(function(page) {
   page.get();

   expect(browser.getCurrentUrl()).toMatch(page.homePageRegex);
});

I was pretty confident in my answer until the last part (where you also want to use the page's "homePageRegex" in the expect). I think you can include that inside the then, but I guess I wouldn't be too surprised if it didn't work...

Also, I don't think there are any special caveats on sharing promises across it/beforeEach blocks. But I might be missing something ...

P.T.
  • 24,557
  • 7
  • 64
  • 95
0

have you made loginAs return a promise? Then you can do

beforeEach(function() {
  loginPage.loginAs('testuser@example.com', 'mypassword').
     then(function(sessionId) {
       homePage = new HomePage(sessionId);
     });
});
Zach Folwick
  • 893
  • 10
  • 18