7 Replies Latest reply on Sep 22, 2008 12:08 PM by Tilman Rossmy

    multiple requests

    Tilman Rossmy Newbie

      I can't seem to figure out how to do multiple requests in one test. Background is that our webapp has a PhaseListener that checks if the user is logged in and redirects to the login page if that is not the case. So in order to test any action I need to execute the login action first.

       HtmlPage htmlPage;
       WebClientSpec wcSpec;
       wcSpec = new WebClientSpec("/login.action?bank=5&lang=de&path=layout/bekb");
       htmlPage = (HtmlPage) wcSpec.doInitialRequest();
      FacesContext facesContext = FacesContextBridge.getCurrentInstance();
       UIViewRoot root = facesContext.getViewRoot();
      
       assertEquals("/jspx/login/login.jspx", root.getViewId());
       HtmlInput inputText = (HtmlInput) htmlPage.getElementById("loginForm:name");
       inputText.setValueAttribute(useerName);
       HtmlInput pass = (HtmlInput) htmlPage.getElementById("loginForm:password");
       pass.setValueAttribute(password);
       HtmlSubmitInput submit = (HtmlSubmitInput) htmlPage.getElementById("loginForm:loginSubmit");
       submit.click();
       facesContext = FacesContextBridge.getCurrentInstance();
       ValueExpression identity = facesContext.getApplication().getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{identity}", Contract.class);
      assertNotNull(identity.getValue(facesContext.getELContext()));
      
      


      So far so good. How do I issue another request from here, while guaranteeing that the #{identity} ValueExpression is still available?

        • 1. Re: multiple requests
          Stan Silvert Master

          This wiki should help you out:
          http://wiki.jboss.org/wiki/JSFUnitTestingSecurePages

          You'll probably just want to extend SimpleInitialRequestStrategy and insert your special login logic. That will get you past the login page each time you want to start a new JSFSession.

          Let us know how it goes.

          Stan

          • 2. Re: multiple requests
            Tilman Rossmy Newbie

            so I tried that strategy, i could use a slightly modified FormAuthentificationStrategy, what does not work though is that the page returned by

            public Page doInitialRequest(WebClientSpec wcSpec) throws IOException
             {
             HtmlPage page = (HtmlPage)super.doInitialRequest(wcSpec);
             setValue(page, "loginForm:name", this.userName);
             setValue(page, "loginForm:password", this.password);
             return clickSubmitComponent(page);
             }
            

            is alway empty, even though the webapp does everything as expected. Am I missing something here?


            • 3. Re: multiple requests
              Stan Silvert Master

              Maybe I can help. Can you post the whole class so I can see exactly what you did?

              Stan

              • 4. Re: multiple requests
                Tilman Rossmy Newbie

                Hi Stan! Thanks! Well it's basically your FormauthenticationStrategy, only that I replaced the userName and password inputText id's with those that we are using. But it's not a JEE container-managed security system, maybe that is the problem?

                
                import com.gargoylesoftware.htmlunit.Page;
                import com.gargoylesoftware.htmlunit.html.ClickableElement;
                import com.gargoylesoftware.htmlunit.html.HtmlElement;
                import com.gargoylesoftware.htmlunit.html.HtmlInput;
                import com.gargoylesoftware.htmlunit.html.HtmlPage;
                import java.io.IOException;
                import java.util.List;
                
                import org.jboss.jsfunit.framework.SimpleInitialRequestStrategy;
                import org.jboss.jsfunit.framework.WebClientSpec;
                
                
                public class FormAuthenticationStrategy extends SimpleInitialRequestStrategy
                {
                
                 private String userName;
                 private String password;
                 private String submitComponent = "loginForm:loginSubmit";
                
                 /**
                 * Create a new FormAuthenticationStrategy.
                 *
                 * @param userName The user name.
                 * @param password The password.
                 */
                 public FormAuthenticationStrategy(String userName, String password)
                 {
                 this.userName = userName;
                 this.password = password;
                 }
                
                 /**
                 * Set the name of the submit component. This should be the value of the
                 * name attribute that will cause the username/password to be submitted. Note
                 * that this is the name attribute and not the id attribute. The default
                 * value is "Submit".
                 *
                 * @param submitComponent The name of the component that will submit the credentials.
                 */
                 public void setSubmitComponent(String submitComponent)
                 {
                 this.submitComponent = submitComponent;
                 }
                
                 /**
                 * Perform the initial request and provide FORM authentication
                 * credentials when challenged.
                 *
                 * @param wcSpec The WebClient specification.
                 *
                 * @return The requested page if authentication passed. Otherwise, return
                 * the error page specified in web.xml.
                 */
                 public Page doInitialRequest(WebClientSpec wcSpec) throws IOException
                 {
                 HtmlPage page = (HtmlPage)super.doInitialRequest(wcSpec);
                 setValue(page, "loginForm:name", this.userName);
                 setValue(page, "loginForm:password", this.password);
                 return clickSubmitComponent(page);
                 }
                
                 protected Page clickSubmitComponent(HtmlPage page) throws IOException
                 {
                 HtmlElement htmlElement = getElement(page, this.submitComponent);
                 if (!(htmlElement instanceof ClickableElement))
                 {
                 throw new IllegalStateException("Component with name=" + this.submitComponent + " is not a ClickableElement.");
                 }
                
                 ClickableElement clickable = (ClickableElement)htmlElement;
                 return clickable.click();
                 }
                
                 protected void setValue(HtmlPage page, String elementName, String value)
                 {
                 HtmlElement element = getElement(page, elementName);
                 if (!(element instanceof HtmlInput))
                 {
                 throw new IllegalStateException("Component with name=" + elementName + " is not an HtmlInput element.");
                 }
                 HtmlInput inputElement = (HtmlInput)element;
                 inputElement.setValueAttribute(value);
                 }
                
                 protected HtmlElement getElement(HtmlPage page, String elementName)
                 {
                 List<HtmlElement> elements = page.getHtmlElementsByName(elementName);
                 if (elements.size() == 0)
                 {
                 throw new IllegalStateException("Component with name=" + elementName + " was not found on the login page.");
                 }
                 if (elements.size() > 1)
                 {
                 throw new IllegalStateException("More than one component with name=" + elementName + " was found on the login page.");
                 }
                
                 return elements.get(0);
                 }
                
                }
                

                The webapp works like this: Whenever there is a request a phaselistener checks if there is a valid user object in the session, if that is not the case it redirects to the login page. After successfull login the user then is redirected to the originally requested page. In the jsfUnit test the expected viewId is correct, but all the components are null. Im using the repository snapshot 1.0GA-SNAPSHOT

                • 5. Re: multiple requests
                  Tilman Rossmy Newbie

                  forgot the test:

                   WebClientSpec wcSpec = new WebClientSpec("/myServletPath.action");
                   wcSpec.setInitialRequestStrategy(new FormAuthenticationStrategy("myUser", "123456"));
                   HtmlPage page = (HtmlPage) wcSpec.doInitialRequest();
                   FacesContext facesContext = FacesContextBridge.getCurrentInstance();
                   UIViewRoot root = facesContext.getViewRoot();
                   boolean b = root.getViewId().equals("/myServletPath.jspx");
                   assertTrue(b);
                   HtmlInput inputText = (HtmlInput) page.getElementById("myForm:myId");
                   assertNotNull(inputText);
                   // this assert fails
                  
                  
                  


                  • 6. Re: multiple requests
                    Stan Silvert Master

                    You need to pass the wcSpec to a JSFSession. You should not call wcSpec.doInitialRequest() directly.


                    JSFSession jsfSession = new JSFSession(wcSpec);


                    Stan

                    • 7. Re: multiple requests
                      Tilman Rossmy Newbie

                      ok, I found the solution, the reason the login action was not executed was that the phaselistener would always redirect a request with uiViewRoot ==null where uiViewRoot is

                      UIViewRoot uiViewRoot = facesContext.getViewRoot()
                      

                      to the login page which somehow works allright with browsers that do have a head;-) but not with the underlying htmlunit Library where the submitted requests seem to always have a blank uiViewRoot