TL;DR: How do I tell Graphene which (relative) URL to load for the @Page-injected object?
I'm trying to setup my web frontend integration tests using the "State of the art", namely a combination of Arquillian, Arquillian Drone, Selenium 2 and Graphene 2.
With Arquillian, Drone and plain Selenium WebDriver (i.e. without any Graphene specific stuff), a test can look like this:
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.jboss.shrinkwrap.resolver.api.maven.Maven;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RunWith(Arquillian.class)
public class LoginIT {
private static final Logger LOG = LoggerFactory.getLogger(LoginIT.class);
@Deployment
public static WebArchive createDeployment() {
return Maven.resolver().loadPomFromFile("pom.xml")
.resolve("de.zalando:purchasing-frontend-general:war:?")
.withoutTransitivity().asSingle(WebArchive.class);
}
@Drone
WebDriver driver;
@ArquillianResource
URL deploymentUrl;
@Test
@RunAsClient
public void testLoginPage() {
LOG.info("executing test!");
driver.get(deploymentUrl + "");
final String title = driver.getTitle();
LOG.info("title: " + title);
Assert.assertEquals("Login page title is wrong",
"Zalando General Purchasing – Login", title);
}
}
(It took me a while to get the deployment right, because of non-current documentation for ShrinkWrap.)
This simple test just checks if we are redirected from the home page to the login page, and that its title is right. It works.
Graphene 2 adds an important new Feature, "autowiring" Page abstractions. Then my test could look like this (omitting imports and the deployment part as above):
@RunWith(Arquillian.class)
public class LoginIT {
private static final Logger LOG = LoggerFactory.getLogger(LoginIT.class);
@Deployment
public static WebArchive createDeployment() {
// as above
}
@Page
LoginPage loginPage;
@Test
@RunAsClient
public void testLoginPage() {
String title = loginPage.getTitle();
LOG.info("title: " + title);
Assert.assertEquals("Login page title is wrong",
"Zalando General Purchasing – Login", title);
}
}
Using this "Page abstraction" object:
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class LoginPage {
@FindBy(tagName = "title")
private WebElement titleElement;
public String getTitle() {
return titleElement.getText();
}
}
This actually works, my test doesn't fail and even outputs the right title.
But this doesn't work at all (I don't know why I seemed to think it does, I must have looked at the output of the previous test) ...
I get an "org.openqa.selenium.NoSuchElementException: Unable to locate element with name: title" with a really long stack trace (through all of Arquillian, Graphene, the Java Reflection API, the Maven Surefire Plugin and two lines of my code).
Debugging into the method shows that it finally tries to access the Html-Element, and the HtmlPage at hand is an about:blank
-page, not my login page.
Is this how it is supposed to work? And why doesn't it work for me?
Then I want to test other pages than the login page, and for this I need to use other start URLs.
With plain Drone+ Selenium Webdriver, I would simply use
driver.get(deploymentUrl + "/otherPage");
as the first line of the test. But what to do with the Graphene 2 @Page-Annotation?
How do I tell Graphene which URL (relative to the deploymentUrl) to load for the @Page-injected object?
I personally use inheritance and generics to achieve this (however it's maybe not the best solution). You can look for example here. You need to define AbstractPage like this
Then each test class is going to implement
AbstractPage
with the page specified in<>
. Take a look at that sample project, I hope that helps!