title: How to implement WebDriver PageObject methods that can return different PageObjects
body: <p>I've just started using <a href="http://seleniumhq.org/docs/03_webdriver.html" rel="noreferrer">WebDriver</a>, and I'm trying to learn the best practices, in particular using <a href="http://code.google.com/p/selenium/wiki/PageObjects" rel="noreferrer">PageObjects</a> and <a href="http://code.google.com/p/selenium/wiki/PageFactory" rel="noreferrer">PageFactory</a>.</p>
  
  <p>It's my understanding that PageObjects should expose the various operations on a web page, and isolate the WebDriver code from the test class. Quite often, the same operation can result in navigating to different pages depending on the data used.</p>
  
  <p>For example, in this hypothetical Login scenario, providing admin credentials takes you to the AdminWelcome page, and providing Customer credentials takes you to the CustomerWelcome page.</p>
  
  <p>So the easiest way to implement this is to expose two methods which return different PageObjects...</p>
  
  <h2>Login PageObject</h2>
  
  <pre><code>package example;
  
  import org.openqa.selenium.WebDriver;
  import org.openqa.selenium.WebElement;
  import org.openqa.selenium.support.FindBy;
  import org.openqa.selenium.support.PageFactory;
  
  public class Login {
  
      @FindBy(id = "username")
      private WebElement username;
  
      @FindBy(id = "password")
      private WebElement password;
  
      @FindBy(id = "submitButton")
      private WebElement submitButton;
  
      private WebDriver driver;
  
      public Login(WebDriver driver){
          this.driver = driver;
      }
  
      public AdminWelcome loginAsAdmin(String user, String pw){
          username.sendKeys(user);
          password.sendKeys(pw);
          submitButton.click();
          return PageFactory.initElements(driver, AdminWelcome.class);
      }
  
      public CustomerWelcome loginAsCustomer(String user, String pw){
          username.sendKeys(user);
          password.sendKeys(pw);
          submitButton.click();
          return PageFactory.initElements(driver, CustomerWelcome.class);
      }
  
  }
  </code></pre>
  
  <p>And do the following in the test class:</p>
  
  <pre><code>Login loginPage = PageFactory.initElements(driver, Login.class);
  AdminWelcome adminWelcome = loginPage.loginAsAdmin("admin", "admin");
  </code></pre>
  
  <p>or</p>
  
  <pre><code>Login loginPage = PageFactory.initElements(driver, Login.class);
  CustomerWelcome customerWelcome = loginPage.loginAsCustomer("joe", "smith");
  </code></pre>
  
  <h2>Alternative approach</h2>
  
  <p>Instead of duplicating code, I was hoping there was a cleaner way of exposing a single <code>login()</code> method which returned the relevant PageObject.</p>
  
  <p>I thought about creating a hierarchy of pages (or having them implement an interface) so that I could use that as the return type, but it feels clumsy. What I came up with was the following:</p>
  
  <pre><code>public &lt;T&gt; T login(String user, String pw, Class&lt;T&gt; expectedPage){
      username.sendKeys(user);
      password.sendKeys(pw);
      submitButton.click();
      return PageFactory.initElements(driver, expectedPage);
  }
  </code></pre>
  
  <p>Which means you can do the following in the test class:</p>
  
  <pre><code>Login loginPage = PageFactory.initElements(driver, Login.class);
  AdminWelcome adminWelcome = 
      loginPage.login("admin", "admin", AdminWelcome.class);
  </code></pre>
  
  <p>or</p>
  
  <pre><code>Login loginPage = PageFactory.initElements(driver, Login.class);
  CustomerWelcome customerWelcome = 
      loginPage.login("joe", "smith", CustomerWelcome.class);
  </code></pre>
  
  <p>This is flexible - you could add an ExpiredPassword page and not have to change the <code>login()</code> method at all - just add another test and pass in the appropriate expired credentials and the ExpiredPassword page as the expected page.</p>
  
  <p>Of course, you could quite easily leave the <code>loginAsAdmin()</code> and <code>loginAsCustomer()</code> methods and replace their contents with a call to the generic <code>login()</code> (which would then be made private). A new page (e.g. the ExpiredPassword page) would then require another method (e.g. <code>loginWithExpiredPassword()</code>).</p>
  
  <p>This has the benefit that the method names actually mean something (you can easily see that there are 3 possible results of logging in), the PageObject's API is a bit easier to use (no 'expected page' to pass in), but the WebDriver code is still being reused.</p>
  
  <p><strong>Further improvements...</strong></p>
  
  <p>If you did expose the single <code>login()</code> method, you could make it more obvious which pages can be reached from logging in by adding a marker interface to those pages (this is probably not necessary if you expose a method for each scenario).</p>
  
  <pre><code>public interface LoginResult {}
  
  public class AdminWelcome implements LoginResult {...}
  
  public class CustomerWelcome implements LoginResult {...}
  </code></pre>
  
  <p>And update the login method to:</p>
  
  <pre><code>public &lt;T extends LoginResult&gt; T login(String user, String pw, 
      Class&lt;T&gt; expectedPage){
      username.sendKeys(user);
      password.sendKeys(pw);
      submitButton.click();
      return PageFactory.initElements(driver, expectedPage);
  }
  </code></pre>
  
  <p>Either approach seems to work well, but I'm not sure how it would scale for more complicated scenarios. I haven't seen any code examples like it, so I'm wondering what everyone else does when actions on a page can result in different outcomes depending on the data? </p>
  
  <p>Or is it common practice to just duplicate the WebDriver code and expose lots of different methods for each permutation of data/PageObjects?</p>