Page Objects pattern is very well described here.
Graphene comes with support for this pattern. The main additions are:
-
Better support for initialization of the Page Objects. Graphene automatically enrich the Page Object's injection points (e.g. @FindBy).
-
Page Objects can contain Page Fragments and they are also properly initialized.
-
Page Objects can contain any injection point which Arquillian supports - e.g. @Drone WebDriver for injecting browser instance
-
Page Objects can encapsulate their location
You have already saw the default way of initializing Page Objects in the parent Page Abstractions page. Let's showcase Graphene way of doing this!
-
Implement a Page Object.
-
Declare it in the test.
-
Annotate it with org.jboss.arquillian.graphene.spi.annotations.Page annotation.
-
And that's all! No need to initialize Page Object via any factory method.
To see it in action, consider please code snippets below, which demonstrates testing of a simple web page with progress bar and two buttons.
Implement Page Object
TestingPage.java
import org.openqa.selenium.support.FindBy;
public class TestPage {
@Drone
private WebDriver browser;
@FindBy(className = "start-button")
private WebElement startButton;
@FindBy(className = "stop-button")
private WebElement stopButton;
@FindBy(id = "progress")
private WebElement progressBar;
@FindBy(className = "foo-bar")
private List<WebElement> listOfElements;
//getters for all fields of this Page Object
public long start() {
startButton.click();
return System.currentTimeMillis();
}
public void stop() {
stopButton.click();
}
/**
* Returns the progress, that is, on how many percents it is completed.
*/
public int getProgress() {
//parse string which contains % sign to an int value
//you may use also injected browser instance
}
public long waitUntilCompleted() {
while(getProgress() != 100) {
//do nothing
}
return System.currentTimeMillis();
}
//other handy methods used with testing of the page
}
Page Objects can be declared also as nested classes. However, to better decouple test logic from the structure of the tested page, it is recommended to declare Page Objects as standalone classes.
Your are not limited just with injecting WebElement instances. You can in the same way inject your Page Fragments, or even java.util.List of Page Fragments/WebElements.
Note that you have to use private fields for all Graphene initialized WebElement/Page Fragments etc. Use their getters from tests.
Declare it in the test and annotate it with @Page annotation.
Test.java
import org.jboss.arquillian.graphene.page.Page;
//other imports
@RunWith(Arquillian.class)
public class TestClass {
//ommitting all the other Arquillian related methods for deployment etc.
@Page
private TestingPage testingPage;
@Test
public void test1() {
long startedAt = testingPage.start();
long endedAt = testingPage.waitUntilCompleted();
long lastInSeconds = (endedAt - startedAt) / 1000
assertTrue(lastInSeconds < 20, "It took: " + lastInSeconds + ", its too much!");
}
@Test
public void test2() {
//other test which can also call methods from already initialized {{TestingPage}}
}
}
Deployment and browser determination
The deployment according to which the @Location value will be resolved, and the browser into which the page will be loaded can be determined in the following way:
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.OperateOnDeployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.graphene.page.InitialPage;
import org.jboss.arquillian.graphene.page.Location;
//other imports
@RunWith(Arquillian.class)
@RunAsClient
public class TestLocation {
@Drone
private WebDriver browser;
@Drone
@Browser2
private WebDriver browser2;
@Deployment
public static WebArchive createTestArchive() {
//returning default war
}
@Deployment(name = "deployment1")
public static WebArchive createTestArchive1() {
//returning some different war
}
@Test
@OperateOnDeployment("deployment1")
public void test1(@InitialPage MyPageObject1 obj) {
//testing the page with help of MyPageObject1
}
@Test
public void test2(@Browser2 @InitialPage MyPageObject2 obj) {
//Graphene will load as the first action MyPageObject2 location value to the browser2
//testing the page with help of MyPageObject2
}
}
You can read more about multiple deployments Arquillian feature here. Graphene support for parallel browsers for more information about this subject.