11 Replies Latest reply on Aug 22, 2007 12:21 PM by ssilvert

    Proposed change to ClientFacade

    ssilvert

      Hi Everyone. I'd like to get your thoughts on ClientFacade API design. Please read below.

      I've been meaning to talk about the design of ClientFacade for awhile now. Because this is an abstraction of HttpUnit, I knew it would be challenging to get this API just right. Thanks to those of you who have added suggestions and comments.

      I think that the ClientFacade is proving to be very convenient, especially because it allows you to refer to client elements by component ID, which is what JSF relies upon. It is nice to be able to just say

      client.clickLink("myCoolLink")
      instead of
      webResponse.getLinkWithID("_id03:_id06:form1:myCoolLink").click();


      The problem comes in because you sometimes need the full power that HttpUnit provides. This has already been shown in the case of secure pages and setting headers.

      The current API for ClientFacade looks like this:
      http://labs.jboss.com/file-access/default/members/jsfunit/freezone/apidocs/org/jboss/jsfunit/facade/ClientFacade.html

      To fix this once and for all, we would remove the constructor that takes a username/password in favor of one that takes a WebConversation. And, we would add a getWebConversation() method.

      WebConversation webConversation = WebConversationFactory.makeWebConversation();
      ..
      // add username/password, headers, etc.
      ..
      ClientFacade client = new ClientFacade(webConversation, initialPage);
      
      // Access to internal WebConversation if you need it. You might need
      // to do this if you used the single-arg constructor for ClientFacade.
      WebConversation webConv = client.getWebConversation();


      We would keep the single-arg constructor:
      ClientFacade client = new ClientFacade(initialPage);


      Right now, ClientFacade is not a clean facade because it allows access to some of the HttpUnit internals. If we add getWebConversation(), we will have these two methods that bleed through the facade:
      WebResponse response = client.getWebRespons();
      WebConversation webConv = client.getWebConversation();


      And to some extent, this one bleeds as well:
      WebForm form = client.getForm(componentID);


      Maybe this is OK. Or maybe we can improve things?

      Thoughts from anyone on this list? Is the ClientFacade API too polluted with HttpUnit? Is there a cleaner way to do this?

      Stan

        • 1. Re: Proposed change to ClientFacade
          mblondel

          I think it's a good idea to be able to get back the webconversation from the ClientFacade.
          But, when you create the clientFacade, like this

          ClientFacade client = new ClientFacade("/Authenticate.jsf");
          


          you can't change the page after (or may be I did'nt understand). So you can't test the next page after a click. Can't we have a sort of

          clientFacade.setWebConversation(webConversation);
          




          • 2. Re: Proposed change to ClientFacade
            ssilvert

             

            "mblondel" wrote:
            I think it's a good idea to be able to get back the webconversation from the ClientFacade.
            But, when you create the clientFacade, like this

            ClientFacade client = new ClientFacade("/Authenticate.jsf");
            


            you can't change the page after (or may be I did'nt understand). So you can't test the next page after a click. Can't we have a sort of

            clientFacade.setWebConversation(webConversation);
            




            When you do a submit(), click(), or clickCommandLink() on a ClientFacade, the page will change. It will also change if you do Ajax4jsfClient.fireAjaxEvent().

            ClientFacade is a facade for the client conversation. So you can simulate a whole user session with one ClientFacade object. I'll try to make that more explicit in the documentation.

            Thanks for the feedback. It's very helpful.

            Stan Silvert
            http://www.jsfunit.org

            • 3. Re: Proposed change to ClientFacade
              ssilvert

              I'm going to go ahead and make the changes I noted earlier. I'll post again here when I'm done.

              Stan

              • 4. Re: Proposed change to ClientFacade
                mblondel

                after my logging, I would like to access a page without using a link :

                ClientFacade client = new ClientFacade("/Authenticate.jsf");
                WebForm loginform = client.getWebResponse().getFormWithID("authenticateForm");
                loginform.setParameter("authenticateForm:login", "admin");
                loginform.setParameter("authenticateForm:password", "admin");
                loginform.getSubmitButton("authenticateForm:_idJsp15").click();
                
                WebRequest req = new GetMethodWebRequest(
                 WebConversationFactory.getWARURL() + "/wizard0.jsf");
                client.ajaxRequest(req);
                client.submit();
                
                WebResponse resp = client.getWebResponse();
                String title = resp.getTitle();
                System.out.println("title = " + title);
                
                WebForm productForm = client.getWebResponse().getFormWithID(PRODUCT_FORM_NAME);
                productForm.setParameter("product", "Activescout");
                productForm.setParameter("host", "host");
                
                WebLink link = resp.getLinkWithID("formProduct:_idJsp99");
                WebResponse resp2 = link.click();
                String title2 = resp2.getTitle();
                System.out.println("title2 = " + title2);
                


                I stay on the same page (title == title2)
                I think the clientfacade is not updated correctly.
                Am i doing something wrong ?

                Thanks

                • 5. Re: Proposed change to ClientFacade
                  ssilvert

                  That's not how it should be coded. And this is what I was worried about. Right now I'm trying to figure out if I should wrap all the HttpUnit objects that come from ClientFacade. It's really hard to make sure the API is used as intended while we still retain all the power of HttpUnit.

                  Your code should look something like this:

                  ClientFacade client = new ClientFacade("/Authenticate.jsf");
                  client.setParameter("login", "admin");
                  client.setParameter("password", "admin");
                  client.submit();
                  
                  WebResponse resp = client.getWebResponse();
                  String title = resp.getTitle();
                  System.out.println("title = " + title);
                  
                  client.setParameter("product", "Activescout");
                  client.setParameter("host", "host");
                  
                  // you need to set an id <h:outputLink id="mylink"/>
                  client.click("mylink");
                  WebResponse resp2 = client.getWebResponse();
                  String title2 = resp2.getTitle();
                  System.out.println("title2 = " + title2);


                  You should never call client.ajaxRequest(). This is only called by the Ajax4jsfClient. This is another design issue because that is not obvious to the developer.

                  Stan Silvert
                  http://www.jsfunit.org

                  • 6. Re: Proposed change to ClientFacade
                    mblondel

                    I will try this. thanks
                    but can I access directly to a page without calling client.clickLink() ?
                    I would like to set a request to the clientfacade, is it possible ?

                    thanks

                    • 7. Re: Proposed change to ClientFacade
                      ssilvert

                       

                      "mblondel" wrote:
                      I will try this. thanks
                      but can I access directly to a page without calling client.clickLink() ?
                      I would like to set a request to the clientfacade, is it possible ?

                      thanks


                      I'm sorry. I don't understand your questions. What do you mean by "access directly to a page" and "set a request to the clientfacade"?

                      Stan

                      • 8. Re: Proposed change to ClientFacade
                        mblondel


                        ClientFacade client = new ClientFacade("/Authenticate.jsf");
                        client.setParameter("login", "admin");
                        client.setParameter("password", "admin");
                        client.submit();
                        
                        WebResponse resp = client.getWebResponse();
                        String title = resp.getTitle();
                        System.out.println("title = " + title);
                        


                        This works fine. i arrive to my default page.
                        But now i would like to go to an another page (wizard.jsf).
                        I have no link on my default page to access this page
                        I would like to do something like this :

                        WebRequest req = new GetMethodWebRequest(
                         WebConversationFactory.getWARURL() + "/wizard0.jsf");
                        client.ajaxRequest(req);
                        client.submit();
                        


                        is it correct ?

                        • 9. Re: Proposed change to ClientFacade
                          ssilvert

                           

                          "mblondel" wrote:


                          This works fine. i arrive to my default page.
                          But now i would like to go to an another page (wizard.jsf).
                          I have no link on my default page to access this page
                          I would like to do something like this :

                          WebRequest req = new GetMethodWebRequest(
                           WebConversationFactory.getWARURL() + "/wizard0.jsf");
                          client.ajaxRequest(req);
                          client.submit();
                          


                          is it correct ?


                          No. You should never call client.ajaxRequest(). I'm going to fix this when I refactor ClientFacade. Right now there is no way to do what you want through the ClientFacade.

                          I'm wondering why you would test a scenario that can't be followed by the user. Your thoughts on this will help with the design.

                          Stan

                          • 10. Re: Proposed change to ClientFacade
                            mblondel

                            actually, I change my design and it works better.
                            thanks for your help

                            • 11. Re: Proposed change to ClientFacade
                              ssilvert

                               

                              "mblondel" wrote:
                              actually, I change my design and it works better.
                              thanks for your help


                              Great!! Better design is what it's all about, right?

                              You've helped me too. Thanks for the feedback.

                              Stan
                              http://www.jsfunit.org