Greetings.

I've been trying to figure out how to do a WicketTester based test of an Ajax-enabled form sequence. The basic idea of the code under test is to have a bunch of panels on a single page, where navigation between panels is gated by server-side validation implemented as Ajax calls triggered from a submit button on each panel.

I'm using wicket 1.3 beta 1.

My first attempt at this was to do the obvious thing where I fill in the form using a FormTester and then call submit on the FormTester. This is almost right except that it doesn't end up calling the onSubmit or onError methods of my AjaxFormSubmitBehavior. I now realize calling submit() here does an actual form submission, which is not what I want to test.

Then I noticed that there was an executeAjaxEvent method on WicketTester. I then tried to fill in the form using a FormTester and then execute the "onclick" behavior associated with my button and this almost worked again. This time all the ajax behavior events were being called but there were no values for my form parameters in the request. This seems to be because BaseWicketTester.submitAjaxFormSubmitBehavior() pulls all the values out of the actual underlying form and sets parameters in the request based on them, in effect undoing the work I did with the FormTester (recall that FormTester sets up a request and then sets parameters on the request for each call to setValue or the like).

Similarly, I could forget using FormTester and instead call BaseWicketTester.setParameterForNextRequest() for each form value I care about, but using executeAjaxEvent again cancels this work out.

Then I tried using BaseWicketTester.executeBehavior(), but because this calls getServletRequest().setRequestToRedirectString(...) again the parameters that I've filled in with the FormTester get overwritten.

At this point, I have this almost working, but I feel like what I've done is an abomination. I've subclassed FormTester and added ajaxSubmit methods, effectively an amalgamation of the FormTester.submit and the BaseWicketTester.executeAjaxEvent methods:

public void ajaxSubmit()
{
    ajaxSubmit(findSubmitButton(), "onclick");
}

public void ajaxSubmit(Component component, String event)
{
    try
    {
MockHttpServletRequest servletRequest = ajaxWicketTester.getServletRequest(); WebRequestCycle requestCycle = ajaxWicketTester.createRequestCycle();
        servletRequest.setRequestToComponent(getForm());
        // handle hasUploadedFiles()

AjaxEventBehavior behavior = findAjaxEventBehavior (component, event);
        // handle behavior not found

        behavior.onRequest();
        requestCycle.getRequestTarget().respond(requestCycle);
    }
    catch (FileUploadException e)
    {
        throw new WicketRuntimeException(e);
    }
}

This gets me really close, except that I'm now finding behavioral differences between the site running in a container vs the unit test. For example, when under test, error messages aren't being cleared between pages: once an error is generated it never goes away. I could try to reach into RequestCycle.detach() for myself but this is going way outside the bounds of a reasonable solution to this problem.

So my questions come down to these:

- Am I crazy for wanting to write these kinds of tests? I figure a few tests like these running through critical site functionality should be integrated into our CI build with every commit. WicketTester tests are way more palatable than doing something like Selenium here. When the forms weren't Ajax enabled the FormTester approach worked really well. We don't have a whole lot of Javascript besides that which Wicket supplies so hooking up the ajax-based version of this test would seem to be just what the doctor ordered.

- Why are executeBehavior and executeAjaxEvent implemented so differently? executeBehavior uses setRequestToRedirectString then calls processRedirectCycle (which in turn calls detach and cleans up rendered error messages). executeAjaxEvent calls onRequest on the behavior directly, and then calls requestCycle.getRequestTarget ().respond(requestCycle) bypassing the detach step in the RedirectCycle, leaving error messages present forever.

- Similarly, how could I effectively use executeAjaxEvent when submitAjaxFormSubmitBehavior pulls parameters from the underlying form? Writing test code that reaches out and grabs the actual form to set fields, to have submitAjaxFormSubmitBehavior read these and set request parameters, to set my actual form fields seems really contorted.

- All the Ajax-related calls in WicketTester are calling setupRequestAndResponse, which seems to be fundamentally at adds with what the FormTester is trying to do (it calls setupRequestAndResponse for itself and then manipulates parameters on the *current* request). Would it possibly be better to have FormTester call setParameterForNextRequest?

- (more of a question for wicket-user, but I've already got your attention) given all this, am I just missing something fundamental in how would I go about writing a test that fills in a form and clicks an AjaxSubmitButton?

If this issue is bugging other people I'd be happy to start hacking on FormTester and friends myself and submit patches but I was pretty sure that I didn't have the whole picture in my head yet and wanted to see if there were any obvious ways of doing this that I'm just missing.

Many thanks in advance and best regards for a killer tool!

-Gil

Reply via email to