lundi 2 mai 2016

Having troubles with Arquillian Graphene page objects

I am having troubles following the guide of Arquillian to make functional tests: http://ift.tt/1mCNCFK. Concretely at the last steps of the guide, with the Page Object abstraction.

I have all the java classes exactly like in the guide, but when i run the test it throws this exception:

org.jboss.arquillian.graphene.enricher.exception.PageObjectInitializationException: Can not instantiate Page Object class org.arquillian.example.HomePage declared in: org.arquillian.example.LoginScreenGrapheneTest

Those are my classes, xhtmls and test classes:

Java Classes:

User.java:

package org.arquillian.example;

public class User {

    private String username;

    public User() {
    }

    public User(String username) {
        this.username = username;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

Credentials.java:

package org.arquillian.example;

import javax.enterprise.inject.Model;

@Model
public class Credentials {

    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

LoginController.java:

package org.arquillian.example;

import java.io.Serializable;

import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Produces;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;


@Named
@SessionScoped
public class LoginController implements Serializable {

    private static final long serialVersionUID = 1L;

    private static final String SUCCESS_MESSAGE = "Welcome";
    private static final String FAILURE_MESSAGE = "Incorrect username and password combination";

    private User currentUser;
    private boolean renderedLoggedIn = false;

    @Inject
    private Credentials credentials;

    public String login() {
        if ("demo".equals(credentials.getUsername())
                && "demo".equals(credentials.getPassword())) {
            currentUser = new User("demo");
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(SUCCESS_MESSAGE));
            return "home.xhtml";
        }

        FacesContext.getCurrentInstance().addMessage(
                null,
                new FacesMessage(FacesMessage.SEVERITY_WARN, FAILURE_MESSAGE,
                        FAILURE_MESSAGE));
        return null;
    }

    public boolean isRenderedLoggedIn() {
        if (currentUser != null) {
            return renderedLoggedIn;
        }
        else {
            return false;
        }
    }

    public void renderLoggedIn() {
        this.renderedLoggedIn = true;
    }

    @Produces
    @Named
    public User getCurrentUser() {
        return currentUser;
    }
}

XHTMLS:

Login.xhtml:

<!DOCTYPE html>
<html xmlns="http://ift.tt/lH0Osb"
    xmlns:ui="http://ift.tt/KsEgXx"
    xmlns:h="http://ift.tt/HjFrZb"
    xmlns:f="http://ift.tt/HcrI1S">
<head>
<title>Log in</title>
</head>
<body>
    <h:messages />
    <h:form id="loginForm" prependIds="false">
        <h:panelGrid columns="2">
            <h:outputLabel for="userName">Username:</h:outputLabel>
            <h:inputText id="userName" value="#{credentials.username}" />
            <h:outputLabel for="password">Password:</h:outputLabel>
            <h:inputSecret id="password" value="#{credentials.password}" />
            <h:commandButton id="login" value="Log in"
                action="#{loginController.login}" />
        </h:panelGrid>
    </h:form>
</body>
</html>

Home.xhtml:

<!DOCTYPE html>
<html xmlns="http://ift.tt/lH0Osb"
    xmlns:ui="http://ift.tt/KsEgXx"
    xmlns:h="http://ift.tt/HjFrZb"
    xmlns:f="http://ift.tt/HcrI1S">
<h:head>
    <title>Home</title>
</h:head>
<h:body>
    <h:messages />
    <h:form prependIds="false">
        <h:commandButton value="Who Am I ?"
            action="#{loginController.renderLoggedIn}">
            <f:ajax render="whoami" />
        </h:commandButton>
        <h:panelGroup id="whoami">
            <h:panelGroup rendered="#{loginController.renderedLoggedIn}">
                <p>You are signed in as #{currentUser.username}.</p>
            </h:panelGroup>
        </h:panelGroup>
    </h:form>
</h:body>
</html>

Test Classes:

LoginPage.java:

package org.arquillian.example;

import static org.jboss.arquillian.graphene.Graphene.guardHttp;

import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.graphene.page.Location;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;


@Location("login.jsf")
public class LoginPage {

    @Drone
    private WebDriver browser;

    @FindBy(id = "loginForm:userName")
    private WebElement userName;

    @FindBy(id = "loginForm:password")
    private WebElement password;

    @FindBy(id = "loginForm:login")
    private WebElement loginButton;

    @FindBy
    private LoginForm loginForm;        // locates the root of a page fragment on a particular page

    public LoginForm getLoginForm() {   // we can either manipulate with the login form or just expose it
       return loginForm;
    }

    public void login(String userName, String password) {
        this.userName.sendKeys(userName);
        this.password.sendKeys(password);
        guardHttp(loginButton).click();
    }

}

HomePage.java:

package org.arquillian.example;

import static org.jboss.arquillian.graphene.Graphene.guardAjax;

import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.graphene.GrapheneElement;
import org.jboss.arquillian.graphene.findby.FindByJQuery;
import org.jboss.arquillian.graphene.page.Location;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

import static org.junit.Assert.assertEquals;


@Location("home.jsf")
public class HomePage {

    @Drone
    private WebDriver browser;

    @FindBy(tagName = "li")
    private WebElement facesMessage;

    @FindByJQuery("whoami p:visible")
    private WebElement signedAs;

    @FindBy(css = "input[type=submit]")
    private GrapheneElement whoAmI;

    public void assertOnHomePage() {
        assertEquals("We should be on home page", "Welcome", getMessage());
    }

    public String getMessage() {
        return facesMessage.getText().trim();
    }

    public String getUserName() {
        if (!((GrapheneElement) signedAs).isPresent()) {
          whoAmI();
        }
        return signedAs.getText();
    }

    private void whoAmI() {
        guardAjax(whoAmI).click();
    }
}

LoginScreenGrapheneTest.java:

package org.arquillian.example;

import java.io.File;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.jboss.arquillian.drone.api.annotation.Drone;
import org.openqa.selenium.WebDriver;

import java.net.URL;

import org.jboss.arquillian.test.api.ArquillianResource;

import static org.jboss.arquillian.graphene.Graphene.guardHttp;
import static org.jboss.arquillian.graphene.Graphene.waitAjax;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.jboss.shrinkwrap.api.Filters;
import org.jboss.shrinkwrap.api.GenericArchive;
import org.jboss.shrinkwrap.api.importer.ExplodedImporter;
import org.jboss.arquillian.graphene.findby.FindByJQuery;
import org.jboss.arquillian.graphene.page.InitialPage;
import org.jboss.arquillian.graphene.page.Page;

import static org.jboss.arquillian.graphene.Graphene.guardAjax;
import static org.jboss.arquillian.graphene.Graphene.waitModel;

@RunWith(Arquillian.class)
public class LoginScreenGrapheneTest {

    private static final String WEBAPP_SRC = "src/main/webapp";

    @Deployment(testable = false)
    public static WebArchive createDeployment() {
        return ShrinkWrap
                .create(WebArchive.class, "login.war")
                .addClasses(Credentials.class, User.class,
                        LoginController.class)
                .merge(ShrinkWrap.create(GenericArchive.class)
                        .as(ExplodedImporter.class).importDirectory(WEBAPP_SRC)
                        .as(GenericArchive.class), "/",
                        Filters.include(".*\\.xhtml$"))
                .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
                .addAsWebInfResource(
                        new StringAsset("<faces-config version=\"2.0\"/>"),
                        "faces-config.xml");
    }

//    @Drone
//    private WebDriver browser;
//    @ArquillianResource
//    private URL deploymentUrl;


//    @FindBy(id = "loginForm:userName")          // 1. injects an element by default location strategy ("idOrName")
//    private WebElement userName;
//
//    @FindBy(id = "loginForm:password")
//    private WebElement password;
//
//    @FindBy(id = "loginForm:login")
//    private WebElement loginButton;
//
//    @FindBy(tagName = "li")                     // 2. injects a first element with given tag name
//    private WebElement facesMessage;
//
//    @FindByJQuery("p:visible")                  // 3. injects an element using jQuery selector
//    private WebElement signedAs;
//
//    @FindBy(css = "input[type=submit]")
//    private WebElement whoAmI;

    @Page
    private HomePage homePage;

    @Test
    public void should_login_successfully( @InitialPage LoginPage loginPage ) {

//        browser.get(deploymentUrl.toExternalForm() + "login.jsf"); // first page load doesn't have to be synchronized
//
//        userName.sendKeys("demo");
//        password.sendKeys("demo");
//
//        guardHttp(loginButton).click();                            // 1. synchronize full-page request
//        assertEquals("Welcome", facesMessage.getText().trim());
//
//        guardAjax(whoAmI).click();                                 // 2. synchronize AJAX request
//        assertTrue(signedAs.getText().contains("demo"));
        loginPage.login("demo", "demo");
        homePage.assertOnHomePage();
        assertEquals(homePage.getUserName(), "demo");
    }
}

There is a lot of code commented in the class above, is the code pre abstraction using page objects.

Aucun commentaire:

Enregistrer un commentaire