Technology
9 minute read

Automation in Selenium: Page Object Model and Page Factory

Dejan is a senior QA with significant experience in web and mobile testing. He has also worked extensively on Android app development.

Writing automated tests is more than just a luxury for any agile software development team. It is a need, and is an essential tool to find bugs quickly during early phases of software development cycles. When there is a new feature that is still in development phase, developers can run automated tests and see how other parts of the system are affected by those changes. This article will explain how you can speed up automated testing using Page Object model in Selenium.

Through test automation, it is possible to lower the cost of bug fixing and bring overall improvement to the software quality assurance (QA) process. With proper tests, developers get a chance at finding and resolving bugs even before it gets to QA. Test automation further helps us to automate test cases and features that are constantly regressing. This way QAs have more time in testing other parts of the application. Moreover, this helps in ensuring quality of the product in production releases. As a result, we get products that are effectively more stable, and a QA process that is more efficient.

Selenium automation simplifies test automation for web applications

Selenium simplifies test automation for web applications

Although writing automated tests may seem like an easy task for developers and engineers, there is still the possibility of ending up with poorly implemented tests, and the high cost of code maintenance in any agile process. Trying to constantly deliver changes or features in any agile development project can prove to be costly when tests are involved. Changing one element on a web page that 20 tests rely on will require one to go through these 20 test routines and update each one to adapt to this newly introduced change. Not only can this be really time consuming, but a serious de-motivating factor when it comes to implementing automated tests early on.

But, what if we could make the change in one place only, and have every relevant test routine use it? In this article, we will take a look at automated tests in Selenium, and how we can use Page Object models to write maintainable and reusable test routines.

Page Object Model in Selenium

Page Object model is an object design pattern in Selenium, where web pages are represented as classes, and the various elements on the page are defined as variables on the class. All possible user interactions can then be implemented as methods on the class:

clickLoginButton();
setCredentials(user_name,user_password);

Since well-named methods in classes are easy to read, this works as an elegant way to implement test routines that are both readable and easier to maintain or update in the future. For example:

In order to support Page Object model, we use Page Factory. Page Factory in Selenium is an extension to Page Object and can be used in various ways. In this case we will use Page Factory to initialize web elements that are defined in web page classes or Page Objects.

Web page classes or Page Objects containing web elements need to be initialized using Page Factory before the web element variables can be used. This can be done simply through the use of initElements function on PageFactory:

LoginPage page = new LoginPage(driver);
PageFactory.initElements(driver, page);

Or, even simpler:

LoginPage page = PageFactory.intElements(driver,LoginPage.class)

Or, inside the web page class constructor:

public LoginPage(WebDriver driver) {           
         this.driver = driver; 
         PageFactory.initElements(driver, this);
}

Page Factory will initialize every WebElement variable with a reference to a corresponding element on the actual web page based on configured “locators”. This is done through the use of @FindBy annotations. With this annotation, we can define a strategy for looking up the element, along with the necessary information for identifying it:

@FindBy(how=How.NAME, using="username")
private WebElement user_name;

Every time a method is called on this WebElement variable, the driver will first find it on the current page and then simulate the interaction. In case we are working with a simple page, we know that we will find the element on the page every time we look for it, and we also know that we will eventually navigate away from this page and not return to it, we can cache the looked up field by using another simple annotation:

@FindBy(how=How.NAME, using="username")
@CacheLookup
private WebElement user_name;

This entire definition of the WebElement variable can be replaced with its much more concise form:

@FindBy(name="username")
private WebElement user_name;

The @FindBy annotation supports a handful of other strategies that make things a bit easier:

id, name, className, css, tagName, linkText, partialLinkText, xpath
@FindBy(id="username")
private WebElement user_name;


@FindBy(name="passsword")
private WebElement user_password;


@FindBy(className="h3")
 private WebElement label;


@FindBy(css=”#content”)
private WebElement text;

Once initialized, these WebElement variables can then be used to interact with the corresponding elements on the page. The following code will, for example:

user_password.sendKeys(password);

… send the given sequence of keystrokes to the password field on the page, and it is equivalent to:

driver.findElement(By.name(“user_password”)).sendKeys(password);

Moving on, you will often come across situations where you need to find a list of elements on a page, and that is when @FindBys comes in handy:

@FindBys(@FindBy(css=”div[class=’yt-lockup-tile yt-lockup-video’]”)))
private List<WebElement> videoElements;

The above code will find all the div elements having two class names “yt-lockup-tile” and “yt-lockup-video”. We can simplify this even more by replacing it with the following:

@FindBy(how=How.CSS,using="div[class=’yt-lockup-tile yt-lockup-video’]")
private List<WebElement> videoElements;

Additionally, you can use @FindAll with multiple @FindBy annotations to look for elements that match any of the given locators:

@FindAll({@FindBy(how=How.ID, using=”username”),
	@FindBy(className=”username-field”)})
private WebElement user_name;

Now that we can represent web pages as Java classes and use Page Factory to initialize WebElement variables easily, it is time we see how we can write simple Selenium tests using the Page Object pattern and Page Factory.

Simple Selenium Test Automation Project in Java

For our Page Object model tutorial, let’s automate developer sign up for Toptal. To do that, we need to automate the following steps:

  • Visit www.toptal.com

  • Click on the “Apply As A Developer” button

  • On Portal Page first check if it’s opened

  • Click on the “Join Toptal” button

  • Fill out the form

  • Submit the form by clicking on “Join Toptal” button

Setting Up a Project

  • Download and install Java JDK

  • Download and install InteliJ Idea

  • Create a new Maven project

  • Link “Project SDK” to your JDK, e.g.: on Windows “C:\Program Files\Java\jdkxxx”

  • Setup groupId and artifactId:

<groupId>SeleniumTEST</groupId>
<artifactId>Test</artifactId>
  • Add dependencies Selenium and JUnit Maven in your project POM file
   <dependencies>
        <!-- JUnit -->         
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- Selenium -->

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-firefox-driver</artifactId>
            <version>${selenium.version}</version>
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-support</artifactId>
            <version>${selenium.version}</version>
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>${selenium.version}</version>
        </dependency>

    </dependencies>

Replace Selenium version and JUnit Version with latest version numbers that can be found by searching for JUnit Maven on Google and on Selenium site.

At this point, if auto build is enabled, dependencies should start downloading automatically. If not, just activate Plugins > install > install:install under the Maven Projects panel on the right side of your IntelliJ Idea IDE.

selenium testing tutorial IDE screenshot

Once the project has been bootstrapped, we can start creating our test package under “src/test/java”. Name the package “com.toptal”, and create two more packages under it: “com.toptal.webpages” and “com.toptal.tests”.

selenium testing tutorial screenshot

We will keep our Page Object/Page Factory classes under “com.toptal.webpages” and the test routines under “com.toptal.tests”.

Now, we can start creating our Page Object classes.

HomePage Page Object

The very first one we need to implement is for Toptal’s homepage (www.toptal.com). Create a class under “com.toptal.webpages” and name it “HomePage”.

package com.toptal.webpages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import org.openqa.selenium.support.PageFactory;

public class HomePage {
   private WebDriver driver;

   //Page URL
   private static String PAGE_URL="https://www.toptal.com";

   //Locators

   //Apply as Developer Button
   @FindBy(how = How.LINK_TEXT, using = "APPLY AS A DEVELOPER")
   private WebElement developerApplyButton;

   //Constructor
   public HomePage(WebDriver driver){
       this.driver=driver;
       driver.get(PAGE_URL);
       //Initialise Elements
       PageFactory.initElements(driver, this);
   }

   public void clickOnDeveloperApplyButton(){

       developerApplyButton.click();

   }
}

Determining Element Locators

On Toptal’s homepage we are interested about one element in particular, and that is the “Apply as a Developer” button. We can find this element by matching the text, which is what we are doing above. While modeling web pages as Page Object classes, finding and identifying elements can often become a chore. With Google Chrome or Firefox’s debugging tools, this can be made easier. By right clicking on any element on a page, you can activate the “Inspect Element” option from the context menu to find out detailed information about the element.

One common (and my preferred) way is to find elements using Firefox’s FireBug extension, in combination with Firefox web driver in Selenium. After installing and enabling FireBug extension, you can right click on the page and select “Inspect element with FireBug” to open FireBug. From the HTML tab of FireBug, you can copy the XPath, CSS Path, Tag name or “Id” (if available) of any element on the page.

page object model in selenium: determining element locators

By copying the XPath of the element in the screenshot above, we can create a WebElement field for it in our Page Object as follows:

@FindBy(xpath = "/html/body/div[1]/div/div/header/div/h1")
WebElement heading;

Or to keep things simple, we can use the tag name “h1” here, as long as it uniquely identifies the element we are interested in:

@FindBy(tagName = "h1")
WebElement heading;

DeveloperPortalPage Page Object

Next, we need a Page Object that represents the developer portal page, one that we can reach by clicking on the “Apply As A Developer” button.

On this page, we have two elements of interest. To determine if the page has loaded, we want to verify the existence of the heading. And we also want a WebElement field for the “Join Toptal” button.

package com.toptal.webpages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class DeveloperPortalPage {
   private WebDriver driver;

   @FindBy(xpath = "/html/body/div[1]/div/div/header/div/h1")
   private WebElement heading;

   @FindBy(linkText = "JOIN TOPTAL")
   private WebElement joinToptalButton;

   //Constructor
   public DeveloperPortalPage (WebDriver driver){
       this.driver=driver;

       //Initialise Elements
       PageFactory.initElements(driver, this);
   }

   //We will use this boolean for assertion. To check if page is opened
   public boolean isPageOpened(){
       return heading.getText().toString().contains("Developer portal");
   }

   public void clikOnJoin(){
       joinToptalButton.click();
   }
}

DeveloperApplyPage Page Object

And finally, for our third and last page object for this project, we define one that represents the page containing developer application form. Since we have to deal with a number of form fields here, we define one WebElement variable for every form field. We find each field by their “id” and we define special setter methods for every field that simulate keystrokes for the corresponding fields.

package com.toptal.webpages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class DeveloperApplyPage {
   private WebDriver driver;

   @FindBy(tagName = "h1")
   WebElement heading;

   @FindBy(id="developer_email")
   WebElement developer_email;

   @FindBy(id = "developer_password")
   WebElement developer_password;

   @FindBy(id = "developer_password_confirmation")
   WebElement developer_password_confirmation;

   @FindBy(id = "developer_full_name")
   WebElement developer_full_name;

   @FindBy(id = "developer_skype")
   WebElement developer_skype;

   @FindBy(id ="save_new_developer")
   WebElement join_toptal_button;


   //Constructor
   public DeveloperApplyPage(WebDriver driver){
       this.driver=driver;

       //Initialise Elements
       PageFactory.initElements(driver, this);
   }

   public void setDeveloper_email(String email){
       developer_email.clear();
       developer_email.sendKeys(email);
   }

   public void setDeveloper_password(String password){
       developer_password.clear();
       developer_password.sendKeys(password);
   }

public void  setDeveloper_password_confirmation(String password_confirmation){
       developer_password_confirmation.clear();
       developer_password_confirmation.sendKeys(password_confirmation);
   }

   public void setDeveloper_full_name (String fullname){
       developer_full_name.clear();
       developer_full_name.sendKeys(fullname);
   }

   public void setDeveloper_skype (String skype){
       developer_skype.clear();
       developer_skype.sendKeys(skype);
   }

   public void clickOnJoin(){
       join_toptal_button.click();
   }
   public boolean isPageOpened(){
       //Assertion
       return heading.getText().toString().contains("Apply to join our network as a developer");
   }
}

Writing a Simple Selenium Test

With Page Object classes representing our pages, and user interactions as their methods, we can now write our simple test routine as a series of simple method calls and assertions.

package com.toptal.tests;

import com.toptal.webpages.DeveloperApplyPage;
import com.toptal.webpages.DeveloperPortalPage;
import com.toptal.webpages.HomePage;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;

import java.net.URL;
import java.util.concurrent.TimeUnit;

public class ApplyAsDeveloperTest {
   WebDriver driver;

   @Before
   public void setup(){
       //use FF Driver
       driver = new FirefoxDriver();
       driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
   }

   @Test
   public void applyAsDeveloper() {
       //Create object of HomePage Class
       HomePage home = new HomePage(driver);
       home.clickOnDeveloperApplyButton();

       //Create object of DeveloperPortalPage
       DeveloperPortalPage devportal= new DeveloperPortalPage(driver);

       //Check if page is opened
       Assert.assertTrue(devportal.isPageOpened());

       //Click on Join Toptal
       devportal.clikOnJoin();

       //Create object of DeveloperApplyPage
       DeveloperApplyPage applyPage =new DeveloperApplyPage(driver);

       //Check if page is opened
       Assert.assertTrue(applyPage.isPageOpened());

       //Fill up data
       applyPage.setDeveloper_email("[email protected]");
       applyPage.setDeveloper_full_name("Dejan Zivanovic Automated Test");
       applyPage.setDeveloper_password("password123");
       applyPage.setDeveloper_password_confirmation("password123");
       applyPage.setDeveloper_skype("automated_test_skype");

       //Click on join
       //applyPage.clickOnJoin(); 
   }

    @After
    public void close(){
          driver.close();
       }
   }

Running the Test

At this point, your project structure should look like this:

selenium testing example

If you want to run the test, select “ApplyAsDeveloperTest” from the tree, right click on it and then select Run ‘ApplyAsDeveloperTest’.

selenium testing example

Once the test has been run, you can see the results in the lower-left corner of your IDE:

selenium testing example

Conclusion

Page Object and Page Factory make it easy to model web pages in Selenium and test them automatically and make the life of both developers and QAs much more simpler. When done right, these Page Object classes can be reused across your entire test suite and to give yourself the opportunity to implement automated Selenium tests for your projects early on, without compromising agile development. By abstracting away user interactions in your page object models and keeping your test routines light and simple, you can adapt your test suite to changing requirements with little effort.

I hope I have managed to show you how to write nice and clean test code that is easy to maintain. I will end the article with my favorite QA quote:

Think twice, code once!

Understanding the basics

What is Page Object model in Selenium?
Page Object model is an object design pattern in Selenium. Web pages are represented as classes, and elements on the page are defined as variables on the class, so user interactions can then be implemented as methods on the class.
Why do we use Selenium?
Selenium is designed to automate web browsers, thus enabling software engineers to greatly speed up and automate testing. While test automation is its primary use, Selenium can also be used to automate certain repetitive actions, such as basic administration tasks.
What is Selenium testing?
Selenium testing is the process of using a set of Selenium software tools to facilitate test automation. In most cases, software engineers choose one to two Selenium tools for this task, but additional tools can be employed to meet different needs.
What's the difference between Page Object model and Page Factory?
Page Object model is a design pattern, as previously outlined in this section. Page Factory expands on Page Object model functionality by introducing more advanced features. It allows users to initialize specific elements within the Page Object model, using annotations.

Comments

Abhresh
Is it possible to implement Explicit wait or Fluent wait in Page object when trying to handle method calling from Page object to test class?
Igor Khrol
https://github.com/yandex-qatools/htmlelements There is a nice library which greatly extends described approach.
Uros Gavric
Excellent article about POM. Thank you!
Dejan Zivanovic
Thanks
Melissa Pontes
Really nice article.
Dejan Zivanovic
Thanks
Dejan Zivanovic
Thank you
muhin
Thanks for the nice article. But one point if multiple @Test present than I have to again create the same page object? like DeveloperPortalPage devportal= new DeveloperPortalPage(driver) in my second test?
Radek
Good article. I'm just putting your advice into practice :) Thanks One question, doesn't getText() already return String so no need for getText().toString()
Bruno Santos
Great article and good example on Selenium and PageObjects infrastructure. The test though, is in my opinion, a bad test example: 1. Test method is too long 2. More than one single feature is being tested in the same method This is a normal issue when TDD/BDD is not in place. I would recommend writing your requirements in Gherkin first. If you are writing Acceptance Tests (which is what Selenium tests are supposed to do), then use a Gherkin based framework such as Cucumber, JBehave or COLA Tests. If you are just writing normal tests, Gherkin based frameworks are still a good option, but it might be simpler to just use a normal JUnit test with some simple comments to identify the Given, When, Then structure. In time this becomes very simple to use and follow. Here is an example of an Acceptance Test using COLA Tests: https://github.com/bmsantos/cola-tests/wiki/Tutorial-%28Java-&-Selenium%29 And here is an example of a simple unit tests still following the Given, When, Then structure: https://github.com/bmsantos/cola-tests/blob/master/cola-tests/src/test/java/com/github/bmsantos/core/cola/filters/FilterProcessorTest.java Disclaimer: I'am the developer of COLA Tests and I've provided such examples without trying to be biased about it. I'm really just trying to show good practices. It's important to get tests right, not only because they test a given feature, but also because they are the entry point for any future developer to understand what a given feature is trying to do... a huge part of the so called "living documentation".
Nikolay Advolodkin
Sweet article, I learned a good bit from it!
Nikolay Advolodkin
Dejan, what do you think is the advantage of using the PageFactory with InitElements over something like: By button = Driver.FindElement(By.Id("pooper")); button.Click(); adn then performing actions without the page factory?
Dejan Zivanovic
Hi Yes
Dejan Zivanovic
maybe :)
Dejan Zivanovic
Yes Cucumber is great, I use it, and it's best practice. My topic was PO and PF. You can see nice article in here https://jamesheppinstall.wordpress.com/2012/09/24/behavioural-testing-in-net-with-specflow-and-selenium-part-1/ for .NET, Gerhin....
Dejan Zivanovic
Use it !
Dejan Zivanovic
Changing one element on a web page that 20 tests rely on will require one to go through these 20 test routines and update each one to adapt to this newly introduced change.
Sinaru Gunawardena
Nice article on POM.
Dejan Zivanovic
thanks
Prasanna K C Dommalapati
This article is really helped me in Creating and maintaining POM. Thanq very much.
Dejan Zivanovic
Thanks :)
Swapnil Kamble
With the help of above articles i have done the implementation with c# for my application since facing some issue in element not found as my some element is populated using service call, So require guidance to maintained the element not found or visible exception in page factory pattern with c# or Java
Oktar
Nice article, look very useful and plan to try it, but I need it for testing a native application (I guess there is not prolem with this and it's not exclusive for web apps) which for Android and iOS. Can I use the same tests for both platforms?
ClownCombat
Pretty Good Article. I liked it. Just tell me please, why the static String PAGE_URL in the HomePage - pageObject should be private ? That way, you cannot call it in other PageObjects, which could invoke a "go_to_home_button".
Paul Bañuelos Sahagun
Excellent article, this POM is really helpfull, @dejan_zivanovic:disqus , I have a doubt, is there a difference between @FindBy(How.ID,using="ID") and @FindBy(id="id")?? I see is easier to use just id="id" but not sure whats the advantgae of "HOW"
Dejan Zivanovic
yes it's needs to be private. Thanks!
Dejan Zivanovic
There is no difference.It's same. I like and use short version :)
Dejan Zivanovic
For iOS and Android I recommend appium.io/
Dejan Zivanovic
Point is that POM is level before cucumber and Gerhin. So you first write pom and then on top of it you write Cucumber test. https://github.com/cheezy/page-object
Bruno Santos
Dejan, Not sure what makes you say that, but Gherkin feature/stories must be written before anything else as their real purpose is to provide a specification to serve as baseline or requirements between business needs and wants. I would recommend reading "Specification by example" by Gojko Adzic. https://www.manning.com/books/specification-by-example
Dejan Zivanovic
read this: https://github.com/cheezy/page-object
Bruno Santos
So, what you are actually saying is that: 1. Write your Gherkin features/stories <--- This still comes first 2. Write the POM 3. Write the features/stories implementation ...
Dejan Zivanovic
yes
Bruno Santos
So we are actually discussing the same point of view! :)
Dejan Zivanovic
here is project: https://[email protected]/dejanzivanovic/biser-test.git
Bruno Santos
Dejan, this is not public.
mahendra sonavane
Thanks Dejan .. i am aware about POM and using but i stuck one place and your blog solved .. thanks from heart :)
Dejan Zivanovic
No problem :)
Dejan Zivanovic
Use this for initialization of elements: PageFactory.initElements(new AjaxElementLocatorFactory(driver, 30), this); You can try with Explicit Wait. For example: WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid"))); Or ExpectedConditions.visibilityofelementlocated
sona
When I trying to run a testsuite some testcases are failed they are unstable.Is the POM and page factory solution for that
Ramesh
Thanks very much for the article. This is very informative on the POM pattern and PF. I have a query. Can the @findBys used to get list of elements from a drop-down element similarly? Thanks
JT
Thanks for the great article. Had a question about @FindBys @FindAll. I'm working with a page that has profiles dynamically added and deleted in a table form. There are edit buttons, delete buttons, and information about the profile within the table. Needing to get all parts of the table so I may delete or edit a profile, but here's what we get to work with: .//*[@id='profile_Profile']/table/tbody/tr[1]/td[1] that is the first row, first column upon inspection here is the first row, second column: .//*[@id='profile_Profile']/table/tbody/tr[1]/td[2] then the first row, third column: .//*[@id='profile_Profile']/table/tbody/tr[1]/th then the second row, first column is: .//*[@id='profile_Profile']/table/tbody/tr[2]/td[1] and so forth...how would we be able to get all of these with pagefactory and reference them?
Dejan Zivanovic
Sorry I miss understand your question. Problem with PF is that selector must be final. It can't be dynamic. Generally it's not good to implement on Calendar and Tables.
Dejan Zivanovic
For @FindBys it's just two or more @FindBy that needs to be true in order to define element. If you use @FindAll with many @FindBy in it. Only one of those @FindBy needs to be true to define element. And I think it's not going to be a problem to use it in drop down.
Dejan Zivanovic
Hi. POM and PF and this tutorial will help you out to write clean and more readable tests that are more easy to maintain. If your test fails or they are unstable it can be from some other issues. -For example you shouldn't use Thread.Sleep(); You should use Explicit,Fluent, Implicit Waits. Or to use Ajax initialization of PF and PO with: PageFactory.initElements(new AjaxElementLocatorFactory(driver, 15), this); -Maybe your Assertions are not good. In TestNG there are Soft Asserts. Maybe you can use them -Maybe you are using static methods in your tests or manipulate same data in same time... that prevent parallel execution of test and memory issues. I don't know help you more.
Andrejs88
Hi Dejan. I appreciated the the post and information sharing, and I certainly understand that it's meant as a basic example, but even a simple example should promote best practices where appropriate. This post, however, demonstrates several important issues: - "Flaky test": Using text to click on element (buttons) + "isPageOpened" method: text changes often (and it did) so it's better to use other ways - "Not DRY": Not abstracting setup and teardown into @beforeclass and @afterclass to run with every test - "Unclear diagnostics": If the test fails, you just get "java.lang.AssertionError" and you have to go through the stack to understand what went wrong. Using an "asssertTrue" with a different signature --> (String message, boolean condition) and adding a custom message makes debugging much easier. Of course there are many many other things that are outside of the scope for an "intro" article, but the above require little extra code but would avoid several anti-patterns. Regards
Sanchit kumar
Please help that how we can handle Dropdown and Radio in pagefactory
Teresa Kelvani
xpath of the element is like below one: Counter is a incremental variable "html/body/main/div/div/div[2]/div[3]/ol/li[" + counter + "]/h2/a") Question: How to use page objects in that case?
Christina Hunt
I want to know that how to choose the best power supply for my ASR9100 certification. <a href="http://qcamfg.com/">Automated Testing</a>
Raghavendra Prasad
Hi Dejan, Can you please help me know how efficiently i can use action class in the Page Object Model. For Example : In your applyAsDeveloper class do you write Action class to perform some Mouse or keyboard actions if so can you please help me know how can we do this. Also I have used similar framework and in your applyAsDeveloper class you have all tests till you submit form, You have created objects now if i have to show each of the steps in my extent report using testNG how can i do that. Like : //Click on Join Toptal and //Create object of DeveloperApplyPage -- I am want these two objects which have created in my extent report. Please tell me know can you do that. Thanks in Advance
Venkat Ramana
Hi..Nice Article. How do we handle fluent waits, explicit waits on expected conditions when using page factory...when some elements appear dynamically.
Dejan Zivanovic
Thanks for suggestions! I can see that you don't need this blog to tell you "how to run a test" or "how to install dependency" :) This is tutorial from scratch as you can see, and explains basic concepts and setup.
Dejan Zivanovic
Hi you can't dynamically assign PF. PF must be static. Skip PF for this use case.....
Dejan Zivanovic
Try to initialize elements like this : PageFactory.initElements(new AjaxElementLocatorFactory(driver, 30), this);
Dejan Zivanovic
try with this : https://www.w3.org/TR/xpath/
Dejan Zivanovic
Please use Cucumber and Selenium. Here is tutorial. https://www.youtube.com/watch?v=WBk1tLjph-0
Dejan Zivanovic
Learn XPath well. There is a search like functions: https://www.w3.org/TR/xpath/ Here is another example: @FindBy(how = How.CSS, using = "[type='radio'][value='roundtrip']") public WebElement roundTrip; @FindBy(how = How.CSS, using = "[type='radio'][value='oneway']") public WebElement oneWay;
aman singhal
This Article is very productive to me, thank you so much I have one concern, below is same: 1. String value = "ApplyFilter"; WebElement loc = driver.findElement(By .xpath("//button[contains(text(), " + value + ")]")); How to achieve same using page-factory pattern, below is my sample code: String value = "ApplyFilter" @FindBy(how=How.NAME, using="//span[contains(text()," + value + ")]") private WebElement portFolioAvailabilit1y;
Dejan Zivanovic
Hi, unfortunately @FindBy must be static. So you can use variables that are final. You can't dynamical address it. Closes thing that you can use in this case is something like this: private final String title="VIDEO TITLE"; @FindBy (how=How.XPATH, using = "//*[@id=\"video-title\" and contains(text()," +"\""+ title + "\""+")]") private WebElement linkwithTitle; Skip PF in this case. Thanks!
Dejan Zivanovic
You don't need to.If you setup pages like I did. You just call it once. If next time new element exist on the page. It will initialize it when you call specific method that use it. I hope this helps...
Dejan Zivanovic
I just wanted to share a good article that will be good if you can read about PO,PF and Page Fragments. http://www.testautomationguru.com/arquillian-graphene-page-fragments/ Happy Coding :)
Dejan Zivanovic
Sorry I really don't know nothing about this certification. Can't help you.
Dejan Zivanovic
Check this out: http://www.testautomationguru.com/arquillian-graphene-page-fragments/
sheetal singh
Hi, This is really a great article, i have few questions: 1. If i am using PF model, do i need to use explicit/fluent wait in my test cases. Dont PF automatically take care of all Web element. 2 In which cases we have to use AjaxElementLocatorFactory initialization. If any one element in page coming through Ajax then do we need to use this? 3. In case i have to use explicit wait in my test cases, then how to get WebElement from a page. case A: All WebElements in Page are private, do i need to add getters for all WebElements present inside a Page. If yes then page will become too big with getters @Test public void test1(){ ExpectedConditions.elementToBeClickable(homePage.getWebElement()) } case B: In some explicit wait we need By locator to be passed, how to get By locator in case of PF pattern @Test public void test1(){ ExpectedConditions.visibilityOfElementLocated(RequireABylocator) }
Mr. Satanicat
It's generally better to set your elements to Private, and then use getters and setters, but to customize them based on how the page uses methods. Like, you only click Buttons. You only swipe on certain areas. Your getters and setters end up shaping your methods.
Sagun Pandey
Excellent Article.
Logic Town
I need to skip the interaction with an element element if it was not found. I did find out that an element is injected as a Proxy that will throws a "NoSuchElementException" when interacting with it. Any cleaner way than catching and ignoring the exception?
Dejan Zivanovic
You can't use PF for dynamic elements
Dejan Zivanovic
Hi. Try to use annotations @ for exception handling
Dejan Zivanovic
Thanks. I appreciate !
Dejan Zivanovic
Hi. For 1,2) If you use AjaxElementLocatorFactory then you don't have a need for Implicit wait on element. PF will try to load element every time when it's used in method. homepage.clickOnButton(). When this is called, PF will try to load button. You can user AjaxElementLocatorFactory always, it's just a async method for element initialization. 3. I personally don't user PF for Explicit wait in general. But that doesn't mean that is the right way :) Problem is that element must be static on the page. If some div that is Loading is dynamically created in any case you can't use PF. I hope that helps!
Dejan Zivanovic
Guys! If you are QA Eng and you want to join Toptal, or if you are company looking for talent here is my referral link to Toptal: https://www.toptal.com/#employ-10x-freelancers ! Thanks!
Vikas Singh
Thanks man, I was strugling with loading Page objects classes, but you knowledge shraring really helped. Hope to see more of such articles from experts. Thanks !!
comments powered by Disqus