Как я скажу Графене загрузить мою @Page?
TL;DR: Как мне сообщить Graphene, какой (относительный) URL-адрес загружать для объекта, введенного @Page?
Я пытаюсь настроить свои интеграционные тесты веб-интерфейса, используя "современное состояние", а именно сочетание Arquillian, Arquillian Drone, Selenium 2 и Graphene 2.
С Arquillian, Drone и простым Selenium WebDriver (т.е. без каких-либо специфических графеновых компонентов) тест может выглядеть следующим образом:
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);
}
}
(Мне потребовалось некоторое время, чтобы получить правильное развертывание из-за устаревшей документации для ShrinkWrap.)
Этот простой тест просто проверяет, перенаправлены ли мы с домашней страницы на страницу входа и правильно ли ее название. Оно работает.
Graphene 2 добавляет новую важную функцию, "автоматическую разводку" абстракций страницы. Тогда мой тест может выглядеть так (без импорта и части развертывания, как указано выше):
@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);
}
}
Используя этот объект "Абстракция страницы":
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();
}
}
Это на самом деле работает, мой тест не проваливается и даже выводит правильный заголовок. Но это не работает вообще (я не знаю, почему я, кажется, думал, что это работает, я должен был посмотреть на результаты предыдущего теста) ...
Я получаю "org.openqa.selenium.NoSuchElementException: не удается найти элемент с именем: заголовок" с очень длинной трассировкой стека (через все Arquillian, Graphene, Java Reflection API, плагин Maven Surefire и две строки моего кода).
Отладка в методе показывает, что он, наконец, пытается получить доступ к Html-элементу, а под рукой находится HtmlPage about:blank
страница, а не моя страница входа.
Это как это должно работать? И почему это не работает для меня?
Затем я хочу протестировать другие страницы, кроме страницы входа, и для этого мне нужно использовать другие стартовые URL.
С простым Drone+ Selenium Webdriver я бы просто использовал
driver.get(deploymentUrl + "/otherPage");
в качестве первой строки теста. Но что делать с графеновой 2-страничной аннотацией?
Как мне сообщить Graphene, какой URL (по отношению к deployUrl) загружать для объекта, внедренного в @Page?
2 ответа
Поведение ожидается. Графен инициализирует поля Page Objects.
Для автоматической загрузки страницы вы можете инкапсулировать местоположение объекта страницы в @Location
аннотаций. Вместе с @InitialPage
Вы можете достичь желаемого поведения.
Ваше объявление объекта страницы будет выглядеть так:
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import import org.jboss.arquillian.graphene.page.Location;
@Location("login.html")
public class LoginPage {
@FindBy(tagName = "title")
private WebElement titleElement;
public String getTitle() {
return titleElement.getText();
}
}
Ваш тест:
@Test
@RunAsClient
public void testLoginPage(@InitialPage LoginPage loginPage) {
String title = loginPage.getTitle();
LOG.info("title: " + title);
Assert.assertEquals("Login page title is wrong",
"Zalando General Purchasing – Login", title);
}
Теперь login.html
будет загружен автоматически относительно вашего contextRoot
как первое действие во время выполнения теста. Вы можете прочитать больше об этой функции в документации.
Я лично использую наследование и дженерики для достижения этой цели (однако, возможно, это не лучшее решение). Вы можете посмотреть, например, здесь. Вам нужно определить AbstractPage следующим образом
public interface AbstractPage {
public abstract String getURL();
}
@RunWith(Arquillian.class)
public abstract class AbstractWebDriverTest<P extends AbstractPage> {
@Page
private P page;
@Before
public void goToUrl() {
driver.get(deploymentURL + page.getURL());
}
}
Затем каждый тестовый класс собирается реализовать AbstractPage
со страницей, указанной в <>
, Взгляните на этот пример проекта, надеюсь, это поможет!