Introduction
What is NEO PageFactory?
Intro to SeleniumQA PageFactory
Selenium QA PageFactory is a well known utility that enables developers and testers to implement automated web / mobile tests based on the Page Object Pattern. In a nutshell, all pages under test are individually (1:1) mapped to a phyical (Java,C# .NET,...) page test class. An instance of a page test class is refered to as a Page Object. This object is typically used to programmically interact with the page under test, for example, by automatically filling in a form.
Page objects contain getters and setters which prepresent page elements of the page under test. These getters/setters are typeically used to set/get data to/from these elements. There are also methods in the class which are used to fire of a physical page events, such as click, doubleClick etc.
Problems when using SeleniumQA PageFactory
Using Selenium QA PageFactory out of the box, all page classes are created manually by the tester (or developer). This can often lead to complications especially in cases where pages under test are rich with page elements (i.e. where the number of elements on pages is significantly large). Problems can also occur around the initial stage of development from a testers perspective, where element id's, names, xpath locations etc are frequently changed by developers (especially when these changes are not expected).
SeleniumQA problems can be minimised using NEO PageFactory
NEO PageFactory was developed to (at least) minimise these issues. It does so by by going one step further and GENERATES all page classes being used for all tests. This a. reduces time taken in creating page classes (as these classes can be used straight away within the test) and can also be used at the UNIT testing stage for every build as a diff between page class generations. The latter becomes very useful because it minimises (dev page modification) issues during the acceptance testing phase (which is normally the stage that page modification issues are generally discovered).
How does it work?
Neo PageFactory works by scanning all HTML documents (via HTTP or a local HTML text file) for standard (or tailored) elements such as, input, a, select etc and, based on elements discovered, generates page object pattern class files containing getters and setters, etc. These getters/setters (and action methods, such as click, doubleClick etc) represent the elements found. The naming convension of each method is determined either by their element id's, name's or text used to display the element.
Usage
1. Clone and Install neopagefactory
(NOTE: This step need only be done once)
cd ~/projects
git clone https://github.com/desmccarter/neopagefactory
cd neopagefactory
mvn clean install
2. Generate Your POP (Page Object Pattern) Classes
cd ~/project/myproject
~/project/nopagefactory/generateclasses -url https://www.google.com
Page class output
Page classes are (by default for now) created in the current working directory under src/main/java/com/dmcc/sample/pages. The naming convention is NameOfPagePage.java, where NameOfPage is formed from the URL name. For example, a page class generated from www.google.com would have the name GooglePage.java, under src/main/java/com/dmcc/sample/pages/google.
Example Classes Generated by NEO PageFactory
The following page classes shown were generated from NEO PageFactory.
Google.com
package com.dmcc.sample.pages.google;
import com.dmcc.pagegen.exceptions.PageException;
import com.dmcc.sample.pages.google.GoogleField;
import com.dmcc.pagegen.page.mccarterp.McCarterPage;
public class GooglePage extends McCarterPage{
private final String url="https://www.google.com";
private final String rRoot="../pgenexamples/src/test/resources";
public GooglePage navigate()throws PageException {
this.setResourcesRoot(rRoot);
this.navigate(url);
return this;
}
public void setQ(final String value) throws PageException{
this.setValue(GoogleField.Q, value);
}
public void clickQ()throws PageException{
this.click(GoogleField.Q);
}
public void clickGoogleSearch()throws PageException{
this.click(GoogleField.GoogleSearch);
}
public void clickIMFeelingLucky()throws PageException{
this.click(GoogleField.IMFeelingLucky);
}
}
Facebook.com
package com.dmcc.sample.pages.facebook;
import com.dmcc.pagegen.exceptions.PageException;
import com.dmcc.sample.pages.facebook.FacebookField;
import com.dmcc.pagegen.page.mccarterp.McCarterPage;
public class FacebookPage extends McCarterPage{
private final String url="https://www.facebook.com";
private final String rRoot="../pgenexamples/src/test/resources";
public FacebookPage navigate()throws PageException {
this.setResourcesRoot(rRoot);
this.navigate(url);
return this;
}
public void setEmail(final String value) throws PageException{
this.setValue(FacebookField.Email, value);
}
public void clickEmail()throws PageException{
this.click(FacebookField.Email);
}
public void setPass(final String value) throws PageException{
this.setValue(FacebookField.Pass, value);
}
public void clickPass()throws PageException{
this.click(FacebookField.Pass);
}
public void clickLogIn()throws PageException{
this.click(FacebookField.LogIn);
}
public void setFirstname(final String value) throws PageException{
this.setValue(FacebookField.Firstname, value);
}
public void clickFirstname()throws PageException{
this.click(FacebookField.Firstname);
}
public void setLastname(final String value) throws PageException{
this.setValue(FacebookField.Lastname, value);
}
public void clickLastname()throws PageException{
this.click(FacebookField.Lastname);
}
public void setRegEmail(final String value) throws PageException{
this.setValue(FacebookField.RegEmail, value);
}
public void clickRegEmail()throws PageException{
this.click(FacebookField.RegEmail);
}
...
Lastminute.com
package com.dmcc.sample.pages.lastminute;
import com.dmcc.pagegen.exceptions.PageException;
import com.dmcc.sample.pages.lastminute.LastminuteField;
import com.dmcc.pagegen.page.mccarterp.McCarterPage;
public class LastminutePage extends McCarterPage{
private final String url="https://www.lastminute.com";
private final String rRoot="../pgenexamples/src/test/resources";
public LastminutePage navigate()throws PageException {
this.setResourcesRoot(rRoot);
this.navigate(url);
return this;
}
public void setDpSearchFrom(final String value) throws PageException{
this.setValue(LastminuteField.DpSearchFrom, value);
}
public void clickDpSearchFrom()throws PageException{
this.click(LastminuteField.DpSearchFrom);
}
public void setDpSearchTo(final String value) throws PageException{
this.setValue(LastminuteField.DpSearchTo, value);
}
public void clickDpSearchTo()throws PageException{
this.click(LastminuteField.DpSearchTo);
}
public void setDpCheckIn(final String value) throws PageException{
this.setValue(LastminuteField.DpCheckIn, value);
}
public void clickDpCheckIn()throws PageException{
this.click(LastminuteField.DpCheckIn);
}
public void setDpCheckOut(final String value) throws PageException{
this.setValue(LastminuteField.DpCheckOut, value);
}
public void clickDpCheckOut()throws PageException{
this.click(LastminuteField.DpCheckOut);
}
public void setGoingTo(final GoingToEnum value) throws PageException{
this.setValue(LastminuteField.GoingTo, value.toString());
}
public void clickGoingTo()throws PageException{
this.click(LastminuteField.GoingTo);
}
public void setLeavingFrom(final LeavingFromEnum value) throws PageException{
this.setValue(LastminuteField.LeavingFrom, value.toString());
}
public void clickLeavingFrom()throws PageException{
this.click(LastminuteField.LeavingFrom);
}
}
References