When an issue is discovered in an real application, it needs to be reproduced by the dev team in a sandbox environment.

It really helps to have this reproducer in the form of an automated test that should work on a given sample code, but that is failing due to the underlying issue.

Such a test can be used for debugging the issue, leading into its assessment and resolution, and finally (once resolved) guarding against a regression.

This is exactly the use case for employing the Arquillian framework.

Sample Framework Test

Let’s look at the following integration test for FocusManager taken from the RichFace’s source.

This test verifies that after a request the FocusManager will enforce the focus of a particular input.

@Test
public void when_there_is_form_based_focus_but_focus_was_enforced_using_FocusManager_then_it_is_not_aplied() {

    contextPath = URLUtils.buildUrl(contextPath, "form.jsf");

    Warp.initiate(openPage).inspect(new VerifyFocusEnforcingOverridesFocusSettings("form:input2"));
    assertEquals(input2, getFocusedElement());

    Warp.initiate(submit).inspect(new VerifyFocusEnforcingOverridesFocusSettings("form:input2"));
    assertEquals(input2, getFocusedElement());

    Warp.initiate(ajax).inspect(new VerifyFocusEnforcingOverridesFocusSettings("form:input2"));
    assertEquals(input2, getFocusedElement());
}

In the external file, you can find a definition of Warp’s inspection which is suppose to verify which component is going to be focused after the request:

public class VerifyFocusEnforcingOverridesFocusSettings extends VerifyFocusEnforcing {

    private static final long serialVersionUID = 1L;

    /**
     * @param enforceFocusId clientId of input component to be enforced to gain focus
     */
    public VerifyFocusEnforcingOverridesFocusSettings(String enforceFocusId) {
        super(enforceFocusId);
    }

    @AfterPhase(Phase.RENDER_RESPONSE)
    public void verify_focus_is_applied(@ArquillianResource FacesContext context) {
        AbstractFocus component = bean.getComponent();
        FocusRendererBase renderer = bean.getRenderer();
        assertFalse(renderer.shouldApply(context, component));
    }
}

Note that there is no mocking involved. We are using a real implementation in a real JSF context driven by a real browser.

The only missing piece here is the XHTML file we test - we define it right in the source, so the test and its sources are all in one place:

private static void addFormFocusIndexPage(FrameworkDeployment deployment) {
    FaceletAsset p = new FaceletAsset();

    p.body("<h:form id='form'>");
    p.body("    <r:focus id='focus' binding='#{componentBean.component}' />");

    p.body("    <h:inputText id='input1' />");
    p.body("    <h:inputText id='input2' />");

    p.body("    <h:commandButton id='submit' value='Submit' />");

    p.body("    <r:commandButton id='ajax' render='@form' value='Ajax' />");

    p.body("</h:form>");

    deployment.archive().addAsWebResource(p, "form.xhtml");
}

That is everything you need to reproduce the issue in automated way.

Authoring New Tests

When you write a test for reproduction you don’t even need to start on a green field, since a lot of components already have some tests and creating a specific reproducer is usually matter of copying & pasting with appropriate modifications to fit your new scenario.

The tests themselves can be written really easily since they reflect how we interact with a page in a browser (WebDriver API) and what the request causes on the server (Warp inspections).

Issue Assessment

RichFaces Framework tests even offers great tools for issue assessment so you can really quickly decide whether

  • is the issue a regression?

    • you can switch the test to use older RichFaces version

  • is the issue present in only a specific environment?

    • specific browser

    • Mojarra / MyFaces

By switching various maven profiles in the framework build and test execution, you can easily execute a test in different environments and effectively identify the root cause.

Conclusion

When you write a framework test you not only reproduce the issue, but you also help with issue assessment and investigation and finally provide code to verify that the component works as expected with any future changes.


blog comments powered by Disqus