New JSFUnit broken?
kragoth Jun 10, 2008 3:42 AMOk, I was really hoping that this new implementation of JSFUnit would help solve many of the problems I have with richfaces components..... and maybe it will. After downloading from SVN and building... I went through the relativly painful task of changing all the api calls expecting that all should be ok. BUT, now even the most simple of tests refuses to run due to the fact that almost all navigation is broken.
Here is the basic idea of my test:
-Create session, server,client - start at home/login page (home.xhtml)
-Click the login button (we have an automatic login for now early dev time)
**UP to this point everything looks good**
-Once the login button is clicked it should navigate to the assigned tasks page via the string returned from clicking on the button. (assignedCertificates.xhtml)
**Now everything goes wrong....
- server.getCurrentViewID() - returns: jobs.xhtml (yay!!)
- client.getContentPage() - returns: HtmlPage(javascript:'')@25799710 (This aint right I'm thinking)
- From now on nothing works because every call to getElement fails. Obviously because it can't find anything in the HtmlPage (as you would expect when it is just the word javascript)
I'm gonna try give as much code as possible but.....There is a lot of it!!!
We have our own tag library(if this means anything) our tags are prefixed with gekko: and they are all straight subclasses of the jsf components.
ok, the login page
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:s="http://jboss.com/products/seam/taglib" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:rich="http://richfaces.org/rich" xmlns:gekko="http://gekkoTagLibs.com" template="/layout/loginTemplate.xhtml"> <ui:define name="body"> <style type="text/css"> .LoginTextCells { padding:5px; } </style> <div> <h:panelGrid columns='1' columnClasses="LoginTextCells"> <gekko:inputText id="username" label="Login ID" gekkoRequired="true" value="#{identity.username}" /> <gekko:inputText id="password" label="Password" gekkoRequired="true" value="#{identity.password}" /> <h:panelGroup> <h:selectBooleanCheckbox value="#{LoginController.agreedToPrivacy}" /> I have read and agree to the <h:commandLink id="privacy" value="Privacy Statement" action="/privacy.xhtml" /> </h:panelGroup> <gekko:commandButton id="submitLogin" large="true" mode="minor" value="LOGIN NOW" action="#{identity.login}" /> <s:div rendered="#{not empty facesContext.maximumSeverity}"> <gekko:messages globalOnly="false"/> </s:div> </h:panelGrid> </div> </ui:define> </ui:composition>
pages.xml - login action defined here
<?xml version="1.0" encoding="UTF-8"?> <pages xmlns="http://jboss.com/products/seam/pages" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.0.xsd"> <page view-id="*"> <navigation from-action="#{identity.logout}"> <redirect view-id="/home.xhtml"/> </navigation> <navigation> <rule if-outcome="userEnquiry"> <redirect view-id="/user/userEnquiry.jsf"/> </rule> <rule if-outcome="userMaintenance"> <redirect view-id="/user/userMaintenance.jsf"/> </rule> <rule if-outcome="endUserMaintenance"> <redirect view-id="/user/userEnquiry.jsf"/> </rule> <rule if-outcome="openTenureDetails"> <redirect view-id="/tenure/tenureDetails.jsf"/> </rule> </navigation> </page> <page view-id="/home.xhtml"> <description>This is the login page</description> <navigation> <rule if="#{identity.loggedIn}"> <redirect view-id="/certificates/assignedCertificates.xhtml"/> </rule> </navigation> </page> <!-- No Login Capture Yet - as no bookmarking for users allowed --> <exception class="org.jboss.seam.security.NotLoggedInException"> <redirect view-id="/home.xhtml"> <message severity="warn">You must be logged in to use this feature</message> </redirect> </exception> <exception> <end-conversation /> <redirect view-id="/error/error.jsf"> <message>Unexpected failure</message> </redirect> </exception> </pages>
assignedCertificates.xhtml
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:rich="http://richfaces.org/rich" xmlns:a4j="https://ajax4jsf.dev.java.net/ajax" xmlns:s="http://jboss.com/products/seam/taglib" xmlns:gekko="http://gekkoTagLibs.com"> <ui:composition template="/layout/template.xhtml"> <ui:define name="body"> <ui:include src="/layout/panelHeader.xhtml"/> <gekko:formHeading value="Welcome to LTL #{CertificateMasterController.currentUser.firstName}"/> <gekko:formPanel id="mainPanel" header="Assigned Certificates"> <p> <gekko:commandButton value="Get Next Escalated" id="GetNextEsc" large="true" rendered="#{CertificateMasterController.escalationOfficer}" action="#{CertificateMasterController.findNextEscalatedCertificate()}"/> <gekko:commandButton value="Get Next" id="GetNextBtn" large="true" action="#{CertificateMasterController.findNextCertificate()}"/> <gekko:commandButton value="Get Next Submitted" id="GetNextSub" large="true" rendered="#{CertificateMasterController.authorizingOfficer}" action="#{CertificateMasterController.findNextSubmittedCertificate()}"/> <h:commandLink action="#{CertificateMasterController.goActivateCertificate(cert)}" value="#{cert.certificateNumber}"/> </p> <rich:dataTable value="#{CertificateMasterController.hackDataSingle}" var="lbl"> <f:facet name="header"> <rich:columnGroup> <rich:column>Status</rich:column> <rich:column>Certificate Number</rich:column> <rich:column>Description</rich:column> <rich:column>Status</rich:column> <rich:column>Due Date</rich:column> <rich:column>Original Due Date</rich:column> </rich:columnGroup> </f:facet> <rich:subTable rendered="#{not empty AssignedCertificatesActionBean.escalatedCertificates}" value="#{AssignedCertificatesActionBean.escalatedCertificates}" var="cert"> <rich:column> <f:facet name="header">Escalated </f:facet> </rich:column> <rich:column sortable="false"> <h:commandLink action="#{CertificateMasterController.goActivateCertificate(cert)}" value="#{cert.certificateNumber}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{cert.reason.description}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{cert.status.code}"/> <h:outputText value=" (Active)" rendered="#{CertificateMasterController.isActiveCertificate(cert)}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{FormatUtils.date(cert.dueDate)}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{FormatUtils.date(cert.originalDueDate)}"/> </rich:column> </rich:subTable> <rich:subTable rendered="#{not empty AssignedCertificatesActionBean.assignedCertificates}" value="#{AssignedCertificatesActionBean.assignedCertificates}" var="cert"> <rich:column sortable="false"> <f:facet name="header">To Action</f:facet> </rich:column> <rich:column sortable="false"> <h:commandLink action="#{CertificateMasterController.goActivateCertificate(cert)}" value="#{cert.certificateNumber}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{cert.reason.description}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{cert.status.code}"/> <h:outputText value=" (Active)" rendered="#{CertificateMasterController.isActiveCertificate(cert)}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{FormatUtils.date(cert.dueDate)}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{FormatUtils.date(cert.originalDueDate)}"/> </rich:column> </rich:subTable> <rich:subTable rendered="#{not empty AssignedCertificatesActionBean.submittedCertificates}" value="#{AssignedCertificatesActionBean.submittedCertificates}" var="cert"> <rich:column sortable="false"> <f:facet name="header">To Authorise:</f:facet> </rich:column> <rich:column sortable="false"> <h:commandLink action="#{CertificateMasterController.goActivateCertificate(cert)}" value="#{cert.certificateNumber}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{cert.reason.description}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{cert.status.code}"/> <h:outputText value=" (Active)" rendered="#{CertificateMasterController.isActiveCertificate(cert)}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{FormatUtils.date(cert.dueDate)}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{FormatUtils.date(cert.originalDueDate)}"/> </rich:column> </rich:subTable> <rich:subTable rendered="#{not empty AssignedCertificatesActionBean.otherCertificates}" value="#{AssignedCertificatesActionBean.otherCertificates}" var="cert"> <rich:column> <f:facet name="header">Other (Dead Certs TBD)</f:facet> </rich:column> <rich:column sortable="false"> <h:commandLink action="#{CertificateMasterController.goActivateCertificate(cert)}" value="#{cert.certificateNumber}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{cert.desc}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{cert.status.code}"/> <h:outputText value=" (Active)" rendered="#{CertificateMasterController.isActiveCertificate(cert)}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{FormatUtils.date(cert.dueDate)}"/> </rich:column> <rich:column sortable="false"> <h:outputText value="#{FormatUtils.date(cert.originalDueDate)}"/> </rich:column> </rich:subTable> </rich:dataTable> <gekko:commandButton value="REFRESH" id="refresh" action="#{CertificateMasterController.gotoCertificateWelcomePage()}"/> <rich:spacer height="10"/> </gekko:formPanel> </ui:define> </ui:composition> </html>
GekkoWebTest.java - This is the superclass of all tests - here is where login is done
Please note that the SeamClient is not used at the moment...just an artifact i'm getting rid of
package gekko.web.jsfunit.pages; import org.apache.cactus.ServletTestCase; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.jboss.jsfunit.jsfsession.JSFClientSession; import org.jboss.jsfunit.jsfsession.JSFServerSession; import org.jboss.jsfunit.jsfsession.JSFSession; import org.jboss.jsfunit.seam.SeamClient; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import gekko.util.SpringUtils; import gekko.web.jsfunit.pages.root.HomePageDriver; import gekko.web.jsfunit.util.JsfUnitTestUtils; public class GekkoWebTest extends ServletTestCase { protected SeamClient sclient; protected JSFSession jsfSession; protected JSFClientSession client; protected JSFServerSession server; private static final Logger log = LogManager.getLogger(GekkoWebTest.class); @Override protected final void setUp() throws Exception { super.setUp(); WebApplicationContext ctx = WebApplicationContextUtils .getWebApplicationContext(session.getServletContext()); SpringUtils.injectBeanProperties(ctx.getAutowireCapableBeanFactory(), this); this.afterSetUp(); } public void afterSetUp() throws Exception { HomePageDriver homePageDriver; log.debug("GekkoWebTest.afterSetUp(): Request page: " + HomePageDriver.PAGE); // Send an HTTP request for the initial page jsfSession = new JSFSession(HomePageDriver.PAGE); client = jsfSession.getJSFClientSession(); // A JSFServerSession gives you access to JSF state server = jsfSession.getJSFServerSession(); //Logging in should probably be done differently but...this will do for now log.debug("GekkoWebTest.afterSetUp(): Loging in"); homePageDriver = new HomePageDriver(jsfSession, server, client); assertTrue(homePageDriver.isDisplayed()); homePageDriver.clickSubmit(); log.debug("After login the page is:" + server.getCurrentViewID()); } public void beforeTearDown() throws Exception { } @Override protected final void tearDown() throws Exception { this.beforeTearDown(); super.tearDown(); } /** * Navigate to the requested page in your current session. * @deprecated * @param page * @throws Exception */ @Deprecated protected void navigateTo(String page) throws Exception { JsfUnitTestUtils.navigateTo(jsfSession, server, client, page); } }
The HomePageDriver.java - this is just abstract away the ids etc from tests
package gekko.web.jsfunit.pages.root; import java.io.IOException; import org.jboss.jsfunit.jsfsession.JSFClientSession; import org.jboss.jsfunit.jsfsession.JSFServerSession; import org.jboss.jsfunit.jsfsession.JSFSession; import org.jboss.jsfunit.seam.SeamClient; import org.xml.sax.SAXException; import gekko.web.jsfunit.pages.AbstractGekkoPageDriver; public class HomePageDriver extends AbstractGekkoPageDriver { public static final String PAGE = "/home.jsf"; public static final String FILE = "/home.xhtml"; public HomePageDriver(JSFSession session, JSFServerSession server, JSFClientSession client) { super(session, server, client); } public HomePageDriver(JSFSession session, JSFServerSession server, SeamClient sclient) { super(session, server, sclient); } @Override public boolean isDisplayed() { return super.isDisplayed(FILE); } public void clickSubmit() throws IOException, SAXException { // sclient.clickCommandLink("submitLogin"); // client.submit("MasterPageForm:submitLogin"); client.click("submitLogin"); } }
Hopefully that is enough to work out the problem. Thanks for any help!