Testing Wicket AjaxBehavior

Mischa Dasberg

Last week I ran into a problem while testing AjaxBehavior in Wicket.

Consider the following scenario: we have a FormComponent which has an AjaxBehavior added to it. We want to test that behavior. Depending on the selected value of for instance a RadioChoice, the Ajaxbehavior should show one component and hide another.

You would think that this would be out of the box behavior when using WicketTester, but unfortunately this is not the case. Triggering an Ajaxbehavior is easy using WicketTester, but setting the selected value isn't.

So we have the following code:

public class TestPage extends WebPage {
    
    private Label l1;
    private Label l2;
    private WebMarkupContainer container;

    public TestPage() {
        container = new WebMarkupContainer("container");
        container.setOutputMarkupPlaceholderTag(true);
        
        l1 = new Label("true", "I selected true");
        l1.setVisible(false);
        l1.setOutputMarkupPlaceholderTag(true);
        l2 = new Label("false", "I selected false");
        l2.setVisible(false);
        l2.setOutputMarkupPlaceholderTag(true);
        
        container.add(new SingleLineRadioChoice("choice", new Model(), 
       Arrays.asList(Boolean.TRUE, Boolean.FALSE)) {
            private static final long serialVersionUID = 1L;
            @Override
            public void onUpdateBehavior(AjaxRequestTarget target) {
                if(getModelObject()) {
                    l1.setVisible(true);
                    l2.setVisible(false);
                } else {
                    l1.setVisible(false);
                    l2.setVisible(true);
                }
                target.addComponent(container);
            }
        }, l1, l2);
        add(container);
    }
    
    public class SingleLineRadioChoice extends RadioChoice {
        private static final long serialVersionUID = -6650798211067977383L;

        public SingleLineRadioChoice(String id,  IModel model, List choices) {
            super(id, model, choices);
            setSuffix("");
            add(new AjaxFormChoiceComponentUpdatingBehavior() {
                private static final long serialVersionUID = 1L;
                @Override
                protected void onUpdate(AjaxRequestTarget target) {
                    updateModel();
                    onUpdateBehavior(target);
                }
            });
        }

        /**  @param target The {@link AjaxRequestTarget}. */
        public void onUpdateBehavior(AjaxRequestTarget target) { }

    }
}

The way you should normally expect the test to work is:

 public void testShouldShowL2() {
        tester.assertInvisible("container:false");
        tester.setParameterForNextRequest("container:choice", "true");
        tester.executeBehavior((AbstractAjaxBehavior) 
        tester.getComponentFromLastRenderedPage("container:choice").getBehaviors().get(0));
        tester.assertVisible("container:false");
    }

Unfortunately this doesn't work because the WicketTester method executeBehavior calls
tester.getServletRequest().setRequestToRedirectString(url.toString()) which sets the
selected value to null.

To be able to test this behavior I created a method om my BaseTest class which looks like this:

   /**
     * Wicket tester.executeBehavior calls 
     * tester.getServletRequest().setRequestToRedirectString(url.toString()) which sets the 
     * selected value to null. To keep the value call tester.getServletRequest()
     * .setParameter(id, value) after tester.getServletRequest().setRequestToRedirectString
     *(url.toString()) 
     * @param id The wicket:id.
     * @param value The value that should be selected The value should be the selected index
     * from the list starting with 0.
     */
    public void executeBehavior(String id, String value) {
        AbstractAjaxBehavior behavior = (AbstractAjaxBehavior) 
        tester.getComponentFromLastRenderedPage(id).getBehaviors().get(0);
        CharSequence url = behavior.getCallbackUrl(false);
        WebRequestCycle cycle = tester.setupRequestAndResponse(true);
        tester.getServletRequest().setRequestToRedirectString(url.toString());
        tester.getServletRequest().setParameter(id, value);
        tester.processRequestCycle(cycle);
    }

Now you can test the behavior like this.

  public void testShouldShowL2() {
        tester.assertInvisible("container:false");
        executeBehavior("container:choice", "1");
        tester.assertVisible("container:false");
    }

Comments (2)

  1. Paul Szulc - Reply

    August 25, 2009 at 10:00 pm

    Hi, can I possibly apply it to my enhanced wicket tester project? Maybe you would like to contribute? In future it could be base for API changes in WicketTester. Let me know what you think. You got my email.

  2. Omnaest - Reply

    August 22, 2010 at 6:36 pm

    Still nearly one year after this post, your idea helped me a lot! Thank you!!

Add a Comment