8 Replies Latest reply on May 13, 2011 9:07 PM by Jeremiah Orr

    Problem with JSFServerSession.getComponentValue() and Seam

    Jeremiah Orr Newbie

      I am currently running Seam 2.2.1 on JBoss AS 4.2.3, and I'm trying to start using JSFUnit 1.3.0 for testing. While I'm very impressed with it so far, I've been unable to successfully test the UI components. Any time I use JSFServerSession.getComponentValue(), it returns null.

       

      I have a simple Ping component:

       

      @Name("ping")
      @Scope(ScopeType.CONVERSATION)
      public class Ping implements Serializable {
           String pingMessage;
      
           @Out(required = false)
           String pingResponse;
      
           public String getPingMessage() {
                return pingMessage;
           }
      
           public void setPingMessage(String pingMessage) {
                this.pingMessage = pingMessage;
           }
      
           public void sendPing() {
                pingResponse = pingMessage;
           }
      }
      

       

      And a simple view:

       

      <h:form id="pingForm">
           <rich:panel>
                <s:decorate id="pingMessageField" template="/layout/edit.xhtml">
                          <ui:define name="label">Message</ui:define>
                          <h:inputText id="pingMessage" value="#{ping.pingMessage}" />
                </s:decorate>
      
                <h:commandButton id="sendPing" value="Send Ping" action="#{ping.sendPing()}" />
      
                <s:decorate id="pingResponseDisplay" template="/layout/display.xhtml">
                          <ui:define name="label">Ping Response</ui:define>
                          <h:outputText id="pingResponseOut" value="#{pingResponse}" />
                </s:decorate>
      
                <div style="clear: left" />
           </rich:panel>
      </h:form>
      

       

      And a simple test class (snipped out some portions for brevity)

       

      public class PingTest extends ServletTestCase {
      
           public void setUp() throws IOException {
                // Initial JSF request
                JSFSession jsfSession = new JSFSession("/jsfUnit/ping.seam");
                this.client = jsfSession.getJSFClientSession();
                this.server = jsfSession.getJSFServerSession();
           }
      
           public void testSendPing() throws IOException, SAXException {
                String pingMessage = "Hello Ping component!";
      
                client.setValue("pingForm:pingMessageField:pingMessage", pingMessage);
                client.click("pingForm:sendPing");
      
                // First test that Seam component was set correctly and value was outjected
                assertEquals(
                     "#{seamconversation.ping.pingMessage} did not match expected value;",
                     pingMessage,
                     server.getManagedBeanValue("#{seamconversation.ping.pingMessage}"));
      
                assertEquals(
                     "#{seamconversation.pingResponse} did not match expected value;",
                     pingMessage,
                     server.getManagedBeanValue("#{seamconversation.pingResponse}"));
      
      
                // Then test UI components
                Object pingMessageInput = server
                     .getComponentValue("pingForm:pingMessageField:pingMessage");
      
                assertEquals(
                     "pingForm:pingMessageField:pingMessage did not match expected value;",
                     pingMessage, pingMessageInput);
      
                Object pingResponse = server
                     .getComponentValue("pingForm:pingResponseDisplay:pingResponseOut");
      
                assertEquals(
                     "pingForm:pingResponseDisplay:pingResponseOut did not match expected value;",
                     pingMessage, pingResponse);
                }
           }
      }
      
      

       

      When I run the application, it displays correctly in my browser.

       

      When I run the test, the two assertions on server.getManagedBeanValue() pass (so we can assume that it updated the model correctly). However, the server.getComponentValue() assertions fail:

       

      pingForm:pingMessageField:pingMessage did not match expected value; expected:<Hello Ping component!> but was:<null>

       

      And if I comment out the first server.getComponentValue(), the second one fails too:

       

      pingForm:pingResponseDisplay:pingResponseOut did not match expected value; expected:<Hello Ping component!> but was:<null>

       

      Searching around, I found some discussions on bugs with getComponentValue() and UIData components, but that shouldn't apply to <h:inputText> or <h:outputText>.

       

      I did notice that the Seam JSFUnit examples (jboss-jsfunit-examples-seam) don't actually call getComponentValue() anywhere, but I was unable to find any indication in the documentation or on a Google search that getComponentValue() doesn't work for Seam.

       

      I'd really appreciate any help with this, because I am really excited to use JSFUnit for our projects!

        • 1. Problem with JSFServerSession.getComponentValue() and Seam
          Jeremiah Orr Newbie

          Note: I can provide full source if necessary. There really isn't much more than this, but I omitted ping.page.xml and some surrounding layout stuff in ping.xhtml for brevity.

          • 2. Re: Problem with JSFServerSession.getComponentValue() and Seam
            Jeremiah Orr Newbie

            Another note: if I use JSFClientSession.getPageAsText(), I can successfully assert that the ping message was rendered as HTML:

             

            String pageAsText = client.getPageAsText();

            int firstOccurrance = pageAsText.indexOf(pingMessage);

            Assert.assertTrue("page text did not contain " + pingMessage,

                   firstOccurrance != -1);

             

            int secondOccurrance = pageAsText.indexOf(pingMessage, firstOccurrance);

            Assert.assertTrue("page text did not contain a second occurrance of "

                   + pingMessage, secondOccurrance != -1);

             

            So the JSF components are still rendering the reponse correctly, but JSFServerSession.getComponentValue() isn't finding the value.

            • 3. Problem with JSFServerSession.getComponentValue() and Seam
              Stan Silvert Master

              Hi Jeremiah,

               

              I think I answered this question a long time ago but I don't remember the answer.  I think if you search on "getComponentValue" in this forum you might find it.

               

              Also, take a look at DebugUtil, which has a couple of methods that let you dump the component tree:

              http://docs.jboss.org/jsfunit/apidocs/org/jboss/jsfunit/framework/DebugUtil.html

               

              That should give you a clue and at least you can make sure that you are referencing the component correctly. 

               

              And, make sure that JSFServerSession.findComponent() will return the component you are looking for.  That way you will know if it is a problem with the compoent search or if the component's value is not returned correctly.

               

              Stan

              • 4. Re: Problem with JSFServerSession.getComponentValue() and Seam
                Jeremiah Orr Newbie

                Thanks for the reply, Stan.

                I think I answered this question a long time ago but I don't remember the answer.  I think if you search on "getComponentValue" in this forum you might find it.

                 

                I've done pretty extensive searching on this, and the closest thing I found was http://community.jboss.org/message/70824. It was a problem with data tables, which you fixed. It mentioned that there was a Mojarra bug that was fixed in a newer version, so I tried upgrading just Mojarra on JBoss AS 4.2.3, even though I'm not using a data table. No luck.

                 

                Also, take a look at DebugUtil, which has a couple of methods that let you dump the component tree:

                http://docs.jboss.org/jsfunit/apidocs/org/jboss/jsfunit/framework/DebugUtil.html

                 

                That should give you a clue and at least you can make sure that you are referencing the component correctly. 

                 

                Nice utility! Using that, I can see that both pingForm:pingMessageField:pingMessage and pingForm:pingResponseDisplay:pingResponseOut are present.

                 

                And, make sure that JSFServerSession.findComponent() will return the component you are looking for.  That way you will know if it is a problem with the compoent search or if the component's value is not returned correctly.

                 

                I added this assertion:

                 

                 String pingMessageComponentId = "pingForm:pingMessageField:pingMessage";
                
                 UIComponent pingMessageComponent = server.findComponent(pingMessageComponentId);
                
                 assertNotNull(pingMessageComponentId + " should not be null;", pingMessageComponent);
                

                 

                And it got past the assertion, still failing on the value assertion. I also checked the class of the component, and it is org.richfaces.component.html.HtmlInputText, as I would expect.

                 

                So based on this additional debugging, it looks like I'm using the correct componentId, the component exists, and the value is being rendered correctly (see previous note about using getPageAsText), but for whatever reason, the value is returning as null.

                 

                Any other ideas?

                • 5. Re: Problem with JSFServerSession.getComponentValue() and Seam
                  Stan Silvert Master

                  OK, I think I figured it out.  When you call getComponentValue() it will retrieve the component from the tree.  Then it will call getValue() on the component which causes JSF to do an evaluation of the value expression #{ping.pingMessage}. 

                   

                  But there is a problem with doing this inside a JSFUnit test.  Notice that when you call getManagedBeanValue() on an EL expression that refers to the Seam conversation you have to prefix your EL expression with "seamconversation".  This is how we have to deal with conversation scope in JSFUnit, but the JSF UIComponent code doesn't know about it.  So without the "seamconversation" prefix the EL evaluation will return null in a JSFUnit test.

                   

                  The solution is to hack up the component's stored ValueExpression and call getManagedBeanValue() on it.  That will simulate what would happen if UIComponent.getValue() were called during a JSF request.  So it would look something like this:

                  UIComponent component = jsfServerSession.findComponent("pingForm:pingMessageField:pingMessage"); 
                  ValueExpression expression = component.getValueExpression("value");
                  String conversationScopeExpression = "#{seamconversation." + expression.getExpressionString().substring(2); 
                  Object value = jsfServerSession.getManagedBeanValue(conversatioionScopeExpression);
                  

                   

                  Let me know if that works.  I might be able to come up with a fix for the next version.

                   

                  Stan

                  • 6. Re: Problem with JSFServerSession.getComponentValue() and Seam
                    Jeremiah Orr Newbie

                    That did it! For the short term, I can write a utility method or something to do this.

                     

                    If you make this fix, any chance it would be a JSFUnit 1.3.1 release? I assume we can't go to JSFUnit 2 until we're on JSF 2, which won't happen for a while... our target production environment is WebSphere, which doesn't have a Java EE 6 version yet.

                     

                    Thanks a lot for the quick help! I've very excited about using this!

                    • 7. Problem with JSFServerSession.getComponentValue() and Seam
                      Stan Silvert Master

                      JSFUnit 2 will support JSF 1.1, 1.2, 2.0, and 2.1.  So you should be fine.  Without Servlet 3.0 you might not be able to use Arquillian, but all the old API's and the Cactus integration will still be supported.

                       

                      Stan

                      • 8. Problem with JSFServerSession.getComponentValue() and Seam
                        Jeremiah Orr Newbie

                        Ah, good to know! Thanks again for your help!