1 2 Previous Next 15 Replies Latest reply on Oct 23, 2008 6:20 AM by L Kr

    ClassCastException with HtmlCommandButton

    L Kr Newbie

      Hi,

      I'm using JsfUnit 1.0.0 beta 3 to test some pages with command button on it. Now when I click the button on the 1st page there's no problem, but when I click the button on a 2nd page I'm getting a ClassCastException:

      java.lang.ClassCastException: com.gargoylesoftware.htmlunit.UnexpectedPage cannot be cast to com.gargoylesoftware.htmlunit.html.DomNode
       at org.jboss.jsfunit.jsfsession.JSFClientSession.getElement(JSFClientSession.java:104)
       at org.jboss.jsfunit.jsfsession.JSFClientSession.click(JSFClientSession.java:188)
       at com.sunreader.web.PublicLinkJSFTest.testPublicLink(PublicLinkJSFTest.java:43)
      


      The page where the error is thrown contains a rich faces suggestion box. But the button itself is plain html button from the Apache tomahawk lib with no ajax stuff. But the site where it works it doesn't include any ajax component. Could that be the reason ? I have also redirect enableb in the HTMLUnit webclient.

      Thanks, Lothar



        • 1. Re: ClassCastException with HtmlCommandButton
          Stan Silvert Master

          You got this error because the previous request returned UnexpectedPage. According to the HtmlUnit javadoc, UnexpectedPage means that the server returned an unexpected content type.

          You should be able to find out what that unexpected content type is by saying:

          JSFClientSession.getContentPage().getWebResponse().getContentType()

          Stan

          • 2. Re: ClassCastException with HtmlCommandButton
            L Kr Newbie

            Hi Stan,

            thanks for your answer. ContentType is indeed "image/gif". But why ? I assume that the right page is loaded by

            assertEquals("/presentation/access_right_assoc.xhtml", JSFServerSession.getCurrentViewID());
            
            That page contains a command button with the id "edit_role_assocs_generatelink". I also check that the button is rendered with
            assertNotNull(JSFServerSession.findComponent(id))
            and
            assertTrue(JSFServerSession.findComponent(id).isRendered())
            So for me it looks like the button is rendered correctly, but when I ty to execute a click on that button with
            JSFClientSession.click(id)
            the exception occurs. So what I'm doing wrong ? Could it be the reason that I have to click on a gif to load the above page? I'm doing a similar test with a another with no problems.

            thanks, Lothar

            • 3. Re: ClassCastException with HtmlCommandButton
              Stan Silvert Master

              Are you setting the content type somewhere? Everything on the server side looks correct, but HtmlUnit is having a problem understanding the page sent back to the browser. If the content type is set to "image/gif" and it is really a "text/html" page then that is your problem. You would need to just set the correct content type.

              You can call JSFClientSession.getContentPage().getWebResponse() and use the WebResponse API to dump the content and all the headers to see everything that came back from the server.

              If you can post your xhtml page and your JSFUnit code I might be able to get a better idea of what is happening.

              Stan

              • 4. Re: ClassCastException with HtmlCommandButton
                L Kr Newbie

                Hi Stan,

                I don't set the content type by myself. I'll try to post a simplified example:

                public abstract class BaseJSFTestNew extends ServletTestCase {
                
                 public BaseJSFTestNew(String name) {
                 super(name);
                 }
                
                
                 @Override
                 protected final void setUp() throws Exception {
                 super.setUp();
                 this.afterSetUp();
                 }
                
                 protected void afterSetUp() throws Exception {
                 // Send an HTTP request for the initial page
                 jsfSession = new JSFSession("/faces/presentation/login.xhtml");
                 jsfSession.getWebClient().setRedirectEnabled(true);
                 client = jsfSession.getJSFClientSession();
                 server = jsfSession.getJSFServerSession();
                 }
                
                 protected void doLogin( ) throws IOException {
                 // plant_search
                 assertEquals("/presentation/login.xhtml", getCurrentViewName());
                 HtmlInputText login = (HtmlInputText)findComponent( "field_logon_username");
                 HtmlInputSecret pwd = (HtmlInputSecret)findComponent( "field_logon_password");
                 assertTrue(findComponent(login.getId()).isRendered());
                 assertTrue(findComponent(pwd.getId()).isRendered());
                
                 getClient().setValue(login.getId(), "xxx");
                 getClient().setValue(pwd.getId(), "xxx");
                 getClient().click("logon_logon");
                 assertEquals("/presentation/plant_search.xhtml", getCurrentViewName());
                 }
                
                 protected void validateComponent(String componentId, Class<? extends UIComponent> type) {
                 UIComponent component = findComponent(componentId);
                 assertNotNull(component);
                 if (type != null) {
                 assertTrue(component.getClass().equals(type) || type.isAssignableFrom(component.getClass()));
                 }
                 assertTrue(component.isRendered());
                 }
                ...
                
                public class PublicLinkJSFTest extends BaseJSFTestNew {
                
                 public PublicLinkJSFTest(String name) {
                 super(name);
                 }
                
                 public void testPublicLink() throws IOException {
                 doLogin();
                 String id = "search_search";
                 validateComponent(id, HtmlCommandButton.class);
                 getClient().click(id);
                 ...
                 id = "menu_nav1_item17_item22"; //it's a gif and the client id - but seems to works
                 getClient().click(id);
                 assertEquals("/presentation/access_right_assoc.xhtml", getCurrentViewName());
                 id = "edit_role_assocs_generatelink";
                 validateComponent(id, HtmlCommandButton.class);
                 getClient().getContentPage().getWebResponse().getContentType(); // image/gif
                // System.out.println(getClient().getPageAsText()); //causes IllegalStateException: This page can not be converted to text. Page type is com.gargoylesoftware.htmlunit.UnexpectedPage
                 getClient().click(id); //exception
                 }
                


                My facelets site looks like:
                <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
                
                <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:a="http://www.conergy.com/jsf"
                 xmlns:c="http://java.sun.com/jstl/core"
                 xmlns:t="http://myfaces.apache.org/tomahawk"
                 xmlns:core="http://www.conergy.de/jsf/core"
                 xmlns:ex="http://www.conergy.com/jsf/components"
                 xmlns:rich="http://richfaces.org/rich"
                 xmlns:a4j="http://richfaces.org/a4j">
                
                <f:loadBundle basename="resources.resource" var="bundle"/>
                
                <head>
                 <link rel="stylesheet" href="#{facesContext.externalContext.requestContextPath}/css/conergy/sunreader.css" type="text/css" />
                 <link rel="SHORTCUT ICON" href="#{facesContext.externalContext.requestContextPath}/image/conergy/favicon.ico" />
                 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
                 <meta http-equiv="expires" content="0" />
                 <!--
                 <t:div id="refresh" rendered="#{not authorizationController.jsfUnitRequest}">
                 <meta http-equiv="refresh" content="#{authorizationController.sessionTimoutInterval}; URL=#{facesContext.externalContext.requestContextPath}/loginExpired.jsp"/>
                 </t:div>
                 -->
                 <script language="javascript" src="#{facesContext.externalContext.requestContextPath}/js/sr2.js" type="text/javascript"></script>
                 <script language="javascript" src="#{facesContext.externalContext.requestContextPath}/js/alarms.js" type="text/javascript"></script>
                 <script language="javascript" src="#{facesContext.externalContext.requestContextPath}/js/common.js" type="text/javascript"></script>
                 <h:outputText value="#{authorizationController.ie7}" />
                 <script language="javascript" src="#{facesContext.externalContext.requestContextPath}/js/jquery.js" type="text/javascript"></script>
                 <script language="javascript" src="#{facesContext.externalContext.requestContextPath}/js/jquery.cookie.js" type="text/javascript"></script>
                 <script language="javascript" src="#{facesContext.externalContext.requestContextPath}/js/webtoolkit.jscrollable.js" type="text/javascript"></script>
                 <script language="javascript" src="#{facesContext.externalContext.requestContextPath}/js/webtoolkit.scrollabletable.js" type="text/javascript"></script>
                 <script>
                 jQuery.noConflict();
                 </script>
                 <title><ui:insert name="title">SunReader</ui:insert></title>
                </head>
                
                <body>
                ...
                
                <t:saveState id="save1" value="#{accessRightAssocController.plantAccess}" />
                
                <rich:messages globalOnly="false" errorClass="errorMessage" infoClass="infoMessage"/>
                
                 <c:choose>
                 <c:when test="#{accessRightAssocController.plantAccessAssocsExist}">
                 <ui:include src="components/plantaccess_assoc_list.xhtml"/>
                 </c:when>
                 <c:otherwise>
                 <h:outputText styleClass="text" value="#{bundle['accessrightassoc.noassocs']}" />
                 </c:otherwise>
                 </c:choose>
                
                <!-- some rich: components not shown here-->
                
                 <a:headerbox rendered="#{core:getWritePermission('rights')}">
                 <a:header title="Public link" />
                 <br />
                 <p>
                 <a:commandButton id="edit_role_assocs_generatelink" access="rights" value="Generate Link" styleClass="formbutton"
                 controller="#{accessRightAssocController}" action="generateLink" immediate="true"
                 disabled="#{accessRightAssocController.publicLinkAvailable}" />
                 <br/><br/>
                 <a:inputText id="text_role_assocs_generatelink" access="rights" rendered="#{accessRightAssocController.publicLinkAvailable}"
                 size="137" styleClass="text" value="#{accessRightAssocController.publicLink}" />
                 </p>
                 </a:headerbox>
                ...
                

                The associated controller looks like:
                public class AccessRightAssocController extends AbstractController {
                ...
                 public String generateLink() {
                 publicLink = SessionUtil.getAuthorizationController().getAuthorizationService().generatePublicLink(getPlant(),
                 getAccount());
                
                 return "access_right_assoc";
                 }
                }
                

                The a-components are only wrapper for tomahawk-t-components.

                I 've even tried to dump the content of the webresponse to a file/image, but getting only 1kb data. With IrfanView it looks like an transparent pixel of 1x1 pixel size .

                Lothar

                • 5. Re: ClassCastException with HtmlCommandButton
                  Stan Silvert Master

                   

                  id = "menu_nav1_item17_item22"; //
                  it's a gif and the client id - but seems to works
                  
                   getClient().click(id);
                   assertEquals("/presentation/access_right_assoc.xhtml", getCurrentViewName());
                   id = "edit_role_assocs_generatelink";
                   validateComponent(id, HtmlCommandButton.class);
                   getClient().getContentPage().getWebResponse().getContentType(); // image/gif
                  // System.out.println(getClient().getPageAsText()); //causes IllegalStateException: This page ca
                  n not be converted to text. Page type is com.gargoylesoftware.htmlunit.UnexpectedPage
                   getClient().click(id); //exception


                  It looks to me like getClient().click("menu_nav1_item17_item22") returns a single gif in the browser. Since this is not an HTML page, you can't click on it with JSFUnit/HTMLUnit.

                  Stan

                  • 6. Re: ClassCastException with HtmlCommandButton
                    L Kr Newbie

                    That sounds really strange to me. I've just tested it in the browser and it works perfectly. Also getCurrentViewName() returns the right view name (access_right_assoc.xhtml) and also the component with the id "edit_role_assocs_generatelink" (the command button) is rendered. I've tried it with JSFServerSession.findComponent(id).isRendered(). Even JSFClientSession.getContentPage().getWebResponse().getStatusCode() returns 200 ok. So I don't understand where the content type "gif" is generated and why.
                    What I just realised is that we have some phase-listener registered in the faces-config. But even without it, the exception occurs.

                    Lothar

                    • 7. Re: ClassCastException with HtmlCommandButton
                      L Kr Newbie

                      In addition to my previous post I just did some more test:

                      
                      assertEquals("/presentation/plant_overview.xhtml", getCurrentViewName());
                      id = "menu_nav1_item17";
                      getClient().click(id);
                      String source = getCurrentViewSource(); //this works
                      System.out.println(source);
                      
                      assertEquals("/presentation/plant_data.xhtml", getCurrentViewName());
                      id = "menu_nav1_item17_item22";
                      getClient().click(id);
                      assertEquals("/presentation/access_right_assoc.xhtml", getCurrentViewName());
                      source = getCurrentViewSource(); //IllegalStateException: This page can not be converted to text. Page type is com.gargoylesoftware.htmlunit.UnexpectedPage
                      System.out.println(source);
                      
                      id = "edit_role_assocs_generatelink";
                      getClient().click(id); //without the call of getViewSource here the ClassCastException occurs
                      


                      As I already told in the previous post the view name is correct and the component id is found but it seems that at that point already an error occured which was not detected. But how can I find out the error ?
                      All "menu_nav1_xxx" id's are generated automatically and are text links generated by the tomahawk t:panelNavigation2 and t:navigationMenuItems components.

                      Lothar

                      • 8. Re: ClassCastException with HtmlCommandButton
                        Stan Silvert Master

                         

                        "merlin-hst" wrote:
                        That sounds really strange to me. I've just tested it in the browser and it works perfectly. Also getCurrentViewName() returns the right view name (access_right_assoc.xhtml)

                        Yes, it is strange.

                        I wouldn't be looking too much at JSFServerSession to find the answer. JSFServerSession looks at things from a JSF server-side point of view. So When you say getCurrentViewName() returns the right view then what you are telling me is that JSF (and JSFUnit) is working correctly on the server side.

                        What is not working correctly is the client side. JSFClientSession wraps HtmlUnit. It is your application's interaction with HtmlUnit that is causing a problem. One thing you might try for debugging is to add a RequestListener and examine each request and response made by HtmlUnit.

                        I've just written a new wiki article that tells you how to do that:
                        http://www.jboss.org/community/docs/DOC-12845

                        Also, if you can come up with a simple example that reproduces this problem I'll be happy to take a look at it.

                        Stan

                        • 9. Re: ClassCastException with HtmlCommandButton
                          L Kr Newbie

                          I got it "working" by removing all richfaces components from the site. But of course it's not a real solution to me. So why causes richfaces components problems if I try to click a "plain old" html command button ?

                          Another point I've just seen, I always get the following line in the log output:
                          INFO - org.apache.commons.httpclient.HttpMethodDirector:814 - Redirect requested but followRedirects is disabled

                          I'm not sure if it's needed, but I tried to enable redirect with the command:

                          JSFSession.getWebClient().setRedirectEnabled(true);
                          

                          Because of some problems with JSF we registered a PostRedirectGetListener as described http://balusc.blogspot.com/2007/03/post-redirect-get-pattern.html. So after a form submit the client will get a redirect - except for ajax requests:
                          AjaxContext.getCurrentInstance(facesContext).isAjaxRequest(facesContext)
                          

                          But even with that message it seems to work - but only without richfaces. Of course I've included the jboss-jsfunit-richfaces-1.0.0.Beta3.jar file in my test project.

                          Lothar

                          • 10. Re: ClassCastException with HtmlCommandButton
                            Stan Silvert Master

                            I'm sorry you are having this trouble but at least it sounds like you've narrowed it down to RichFaces. If you can figure out which RichFaces component is causing the problem (and under which circumstances), I'll open up a bug report with the HtmlUnit team so we can get this fixed. I know that they are very interested in having good support for RichFaces.

                            Stan

                            • 11. Re: ClassCastException with HtmlCommandButton
                              L Kr Newbie

                              I did some more tests using a RequestListener as described earlier and found out an (maybe) explanation for the exception:

                              When I call the "plant_data" site which contains no RichFaces or ajax stuff I see the request (and response) for the site itself and some myFacesXX js files:

                              faces/myFacesExtensionResource/org.apache.myfaces.renderkit.html.util.MyFacesResourceLoader/12246809/inputTextHelp.HtmlTextHelpRenderer/inputTextHelp.js
                              


                              Now the next page "access_right_assoc" - where the error occurs - contains a rich:suggestionbox surrounded by a a4j:region tag:
                              <a4j:region renderRegionOnly="true" id="accessrightassoc_accountNamesGroup">
                              ....
                              <rich:suggestionbox id="suggestionBoxId"
                               for="field_accessrightassoc_table_account"
                               suggestionAction="#{adminAccountNameController.accountNames}"
                               var="result"
                               fetchValue="#{result.userName}">
                               <h:column>
                               <h:outputText value="#{result.userName}" />
                               </h:column>
                               <h:column>
                               <h:outputText value="#{result.completePersonName}"/>
                              </h:column>
                              </rich:suggestionbox>
                              ...
                              </a4j:region>
                              
                              


                              Now I see a lot more js files in the request
                              a4j/g/3_2_2.GAscripts/suggestionbox.js
                              


                              and at last a request for a dummy gif:
                              a4j/g/3_2_2.GAorg/richfaces/renderkit/html/images/spacer.gif
                              


                              For me it looks like that this gif "stays in mind" of JsfUnit/HtmlUnit and will used further. I've tried also to dump the content of the WebResponse after requesting the site to a file:
                              FileUtils.writeByteArrayToFile(new File("test1.gif"),JSFClientSession.getContentPage().getWebResponse().getResponseBody());
                              FileUtils.writeByteArrayToFile(new File("test2.gif"),IOUtils.toByteArray(JSFClientSession.getContentPage().getWebResponse().getContentAsStream()));
                              


                              The FileUtils + IOUtils class are from the apache commons project.

                              When I now compare the hex view of these two files with the above "spacer.gif" they are absolute identically. That's why the content type is "gif". Also the file size is identically. But what can I do to avoid it ? For now I don't need the dummy image really in my test case.

                              Lothar

                              • 12. Re: ClassCastException with HtmlCommandButton
                                Stan Silvert Master

                                I can change JSFUnit to ignore an UnexpectedPage, but I'm a little worried about breaking something else. I'd feel better if I had something that demonstrates the problem so I can add a new test to the JSFUnit test suite.

                                Is there any way you can post a simple example?

                                Stan

                                • 13. Re: ClassCastException with HtmlCommandButton
                                  L Kr Newbie

                                  I'll try it.

                                  But maybe it's enough if you construct a site with just a rich:suggestionbox and a command button on it and try to click the button.

                                  • 14. Re: ClassCastException with HtmlCommandButton
                                    Stan Silvert Master

                                    I made the change to JSFUnit if you want to build from SVN and try it out.

                                    Stan

                                    1 2 Previous Next