8 Replies Latest reply on Jun 13, 2008 1:01 PM by ssilvert

    New JSFUnit broken?

    kragoth

      Ok, 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!

        • 1. Re: New JSFUnit broken?
          ssilvert

          Thanks for going through the pain as an early alpha tester!!

          Right now, the combination of RichFaces and HtmlUnit is broken. I've given some sample code to Marc Guillemot, the lead developer for HtmlUnit and he's working on the problem. Once that is fixed, I'll put out another beta of JSFUnit. Then when Seam support looks good, we'll go GA.

          The good news is that Marc and the rest of the HtmlUnit team are very interested in making sure that HtmlUnit works well with JSFUnit, RichFaces, and Seam. So I'm very optimistic that the problems will be worked out and at the end of the day we will have a very solid JSFClientSession that fully supports RichFaces as well as other JSF/AJAX component libraries.

          Stan

          • 2. Re: New JSFUnit broken?
            kragoth

            Ok...I knew that richfaces support was broken.... but are you saying that any page with a richfaces component wont work?

            Do we have any idea as to when the fix will be available? I'm basically stuck at the moment with JSFUnit. With the old version my drop down menus wont work, and with this version...well I can't go anywhere. hehe.

            I don't want to have to revert all these changes I've made and then redo them in a week's time if that can be helped.

            By the way can you give me a link to the issue in HTMLUnit that I can watch to see what is happening?

            Thanks,
            Tim

            • 3. Re: New JSFUnit broken?
              ssilvert

               

              "Kragoth" wrote:
              Ok...I knew that richfaces support was broken.... but are you saying that any page with a richfaces component wont work?

              Well, the first time Ajax4jsf goes to the server, you'll see a problem. Because of the way RichFaces/A4J fetches resources, that pretty much covers anything you could write.
              "Kragoth" wrote:

              Do we have any idea as to when the fix will be available? I'm basically stuck at the moment with JSFUnit. With the old version my drop down menus wont work, and with this version...well I can't go anywhere. hehe.

              The HtmlUnit lead told me today that he found the problem and now he's doing more testing and cleaning things up. It should be soon.

              "Kragoth" wrote:

              By the way can you give me a link to the issue in HTMLUnit that I can watch to see what is happening?

              There's this bug:
              https://sourceforge.net/tracker/?func=detail&atid=448266&aid=1969213&group_id=47038

              But that's probably not the one to watch. Since a lot of changes have been made to HtmlUnit, I doubt that particular bug is reproduceable any more.

              The HtmlUnit lead now has a good test that he is using to work through the RichFaces support. I don't think he's documenting everything in Bugzilla as he goes. I'll add a new announcement post to this forum as soon as we have something ready.

              Stan

              • 4. Re: New JSFUnit broken?
                kragoth

                Thanks for the quick reply.
                It's good to know that things are happening. I really hope that the fix is soon. I don't want to have to undo my changes and then redo them again! :P

                My team is really hoping to use this testing infrastructure to give us a better confidence level in the GUI part of our application. So I'm trying very hard to make sure we can achieve this :)

                I'll just not checkin for a couple of days and hopefully the fix will be out by then :)

                Thanks heaps for your support Stan, it is very much appreciated.

                • 5. Re: New JSFUnit broken?
                  l.jinok.l

                  I've opened http://jira.jboss.com/jira/browse/JSFUNIT-97, which is probably relevant to this discussion.

                  • 6. Re: New JSFUnit broken?
                    kragoth

                    I've noticed a large checkin in the Htmlunit codebase with comments containing your name Stan :P
                    I've been trying to build Htmlunit myself but I'm not having any luck! LOL.
                    Keep getting a bad protocol "data" error when running the tests.

                    So....have you had a chance to see if the bug has been fixed yet?

                    • 7. Re: New JSFUnit broken?
                      ssilvert

                      The checkin you noticed didn't quite fix the problem. Marc says it is working if you set the BrowserVersion to BrowserVersion.FIREFOX_2. But the RichFaces tests fail if set to the default. So he's looking at that.

                      I haven't had any problems building HtmlUnit.

                      Stan

                      • 8. Re: New JSFUnit broken?
                        ssilvert