Refactor-2

We will start this refactoring by creating a new package under the java folder of the solution called pages, illustrated here:

  1. Right-click on the pages, select New > Java Class, and enter the name LandingPage
  2. Copy the preceding code snippet of LandingPage and paste it
  3. We also need to implement wait for the visibility of elements to remove any flakiness in the test

We learned about test synchronization in the last chapter, and we also learned about the importance of a proper wait strategy in the test. So, instead of having each page class create its own implementation of WebDriverWait, we can extract it to a base page, which can be extended by different page classes and can utilize the common methods. So, the next step is to add a BasePage:

  1. Add another Java class to the pages package and name it as BasePage
  2. WebDriver wait needs a driver instance and for now, we will create only one method, waitForElementToBeVisible().
  3. Copy this code in the BasePage:
public class BasePage {
private AppiumDriver driver;
private WebDriverWait wait;

public BasePage(AppiumDriver driver) throws Exception {
this.driver = driver;
wait = new WebDriverWait(this.driver, 30);
}

public void waitForElementToBeVisible(WebElement element) {
wait.until(ExpectedConditions.visibilityOf(element));
}
}
  1. At this point, we need to make the LandingPage class extend the BasePage and add the method we just created to the LandingPage class method skipToHomePage(). This will make you add the constructor matching the superclass; go ahead and do that. Here's how it will look after the changes:
public void skipToHomePage() {
waitForElementToBeVisible(skipLink);
skipLink.click();
}

At this point, we can try running the code but it will throw a NullPointerException. PageFactory supports this pattern and helps cut down the code. Let's see what changes we need to make and where.

The reason the code threw up NullPointerException is because the fields are not instantiated; hence, we need to initialize the PageObject. Take a look at this code:

skipLink.click();

When PageFactory is initialized, it is equivalent to the following:

appiumDriver.findElement(By.id("skip")).click();

Now let's try to stabilize the code here. We have added a BasePage class, as shown just now. Let's navigate back to the LandingPage class; we need to add this PageFactory initialization:

PageFactory.initElements(appiumDriver,this);

We need to add a constructor that takes care of the PageFactory initialization. The code after extending BasePage class and adding initialization is as shown:

public class LandingPage extends BasePage {
AppiumDriver appiumDriver;

@FindBy(id = "skip")
private WebElement skipLink;

@FindBy(id = "login_register_view")
private WebElement mobileOrEmailField;

@FindBy(id = "continue_login")
private WebElement continueButton;

@FindBy(id = "fb")
private WebElement fbButton;

@FindBy(id = "sign_in_button")
private WebElement googleButton;

public LandingPage(AppiumDriver appiumDriver) throws Exception {
super(appiumDriver);
this.appiumDriver = appiumDriver;
PageFactory.initElements(appiumDriver, this);
}

public void skipToHomePage() {
waitForElementToBeVisible(skipLink);
skipLink.click();
}

public void registerByMobileOrEmail(String mobileorEmail) {
mobileOrEmailField.sendKeys(mobileorEmail);
continueButton.click();
}

public void signInByFacebook() {
fbButton.click();
}

public void signInByGoogle() {
googleButton.click();
}

}

To use the preceding code, we need to change the public void iChooseAsMyCity(String city) method and edit a couple of lines. Consider the following code:

Wait wait = new FluentWait(appiumDriver)
.withTimeout(10, TimeUnit.SECONDS)
.pollingEvery(250, TimeUnit.MILLISECONDS)
.ignoring(NoSuchElementException.class)
.ignoring(TimeoutException.class);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("skip")));

appiumDriver.findElement(By.id("skip")).click();

We can substitute it with the following line and run the same test again. It will pass seamlessly and look at the readability and code organization we have introduced:

new LandingPage(appiumDriver).skipToHomePage();

On similar lines, we can create a HomePage class that will have elements such as select city dropdown. Let's do the exercise of creating the HomePage class. In the HomePage class, we need not map everything that is present on the UI; it can just be those elements that you need interaction with. Here's the implementation of the same:

public class HomePage extends BasePage {
AppiumDriver appiumDriver;

@FindBy(id = "citySpinner")
private WebElement cityDropdown;

@FindBy(id = "search_ET")
private WebElement citySearchBox;

@FindBy(id = "city_name")
private WebElement cityName;

@FindBy(xpath = "//android.widget.TextView[@text='Cars']")
private WebElement mobileOrEmailField;

@FindBy(id = "sign_in_button")
private WebElement googleButton;

public HomePage(AppiumDriver appiumDriver) throws Exception {
super(appiumDriver);
this.appiumDriver = appiumDriver;
PageFactory.initElements(appiumDriver, this);
}

public void selectCity(String city) {
cityDropdown.click();
citySearchBox.click();
citySearchBox.sendKeys(city);
waitForElementToBeVisible(cityName);
cityName.click();
}
}

 

With the preceding piece of code, we can replace the following line:

appiumDriver.findElement(By.id("citySpinner")).click();
appiumDriver.findElement(By.id("search_ET")).click();
appiumDriver.findElement(By.id("search_ET")).sendKeys(city);

wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("city_name")));
appiumDriver.findElement(By.id("city_name")).click();

This is the line it will be replaced with:

new HomePage(appiumDriver).selectCity(city);

So, the iChooseAsMyCity(String city) method now looks like this:

@And("^I choose "([^"]*)" as my city$")
public void iChooseAsMyCity(String city) throws Throwable {
new LandingPage(appiumDriver).skipToHomePage();
try {
if (appiumDriver.findElement(By.xpath("//android.widget.Button[@text='Later']")).isDisplayed())
appiumDriver.findElement(By.xpath("//android.widget.Button[@text='Later']")).click();
} catch (Exception e) {
//Do nothing
}
new HomePage(appiumDriver).selectCity(city);
}

This code is much more readable and easy to maintain. We can even add this handling of pop up message to upgrade by clicking on Later to HomePage or BasePage itself so that the code will look much cleaner. Now that we have seen how to do this, I am leaving it to you to implement the same. Below is the pictorial difference in the code readability and structure:

The next exercise for you is to replace the existing code we have written and model it all on the Page Object concept.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.144.108