Friday 27 April 2012

Navigation in Page Objects method returning different pages

Page Objects would now appear to be the standard way to approach test automation when using open source tools such as Selenium.

Of the accepted rules, this one can cause problems;





What happens if the login method returns you to different pages dependent on the page you have logged in from or if the login is unsuccessful?

Proposed solutions are to create different methods dependent on the return type;

public HomePage LoginFromHomePage(string email, string password)
{
     .......
     return new HomePage(driver);
}


public PurchaseFlowLoginFromProductPage(string email, string password)
{
     .......
     return new PurchaseFlowPage(driver);
}



public LoginPage UnsuccessfulLogin(string email, string password)
{
     .......
     return new LoginPage(driver);
}






I wasn't happy with this approach, especially if the AUT can return login to lots of different pages.

By using Generics (this example is C# but I assume can be done in Java too), I am able to create one method;

public T Login<T>(string email, string password) 
{
   .....


   return (T)Activator.CreateInstance(typeof(T), base.Driver);
}



I can then write tests like this;

HomePage page = page1.Login<HomePage>("sello", "password");


OR


PurchaseFlowPage page = productPage.Login< PurchaseFlowPage>("sello", "password");


OR


ErrorPage page = page1.Login<ErrorPage>("sello", "");


I think this is a much better way of appraoching page object navigation

5 comments:

  1. Shouldn't the pages all have the same super-type?

    Couldn't you return that, that assert it's what you expect? Then, you'd cast it and carry on.

    ReplyDelete
  2. Yes, all pages extend from the same base class BUT i do not recommend casting within the test.

    For example, if the BasePage class had an abstract method called "WaitForPageToLoad", then the page object method which instantiates the class could also call "WaitForPageToLoad" before returning control to the test. "WaitForPageToLoad" may contain some funky code snippets to deal with post-page load ajax calls etc.

    If you were to cast in the test, then control would be returned before the page was ready and the test would have to be aware that it may need to call "WaitForPageToLoad" before continuing.

    I prefer the test to be unaware of things such dealing with race conditions.

    ReplyDelete
  3. So you're just passing the type of the expected page class into the method? It seems like this would require the calling code to know more of the implementation details of the of the Page being called so the caller would know what the possible page class types were supported.

    ReplyDelete
    Replies
    1. Sometimes trade-offs have to be made. Do you have a better alternative?

      Delete
  4. Here's another blog post with similar recommendation but different solution/approach:

    http://watirmelon.com/2012/05/29/page-objects-returning-page-objects/

    ReplyDelete