Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Java CSS
branch: master

This branch is even with arquillian:master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
build-resources
portal
shrinkwrap
warp
.gitignore
README.md
apl.txt
license.txt
pom.xml

README.md

Arquillian Portal Extension

What is this?

Arquillian Portal Extension was created to help you write tests for portlets.

Currently it supports:

  • Injection of portal specific @ArquillianResource URL with @PortalURL
  • @PortalURL supports following values:
    • null or "" - URL to page with all deployed portlets on a single page
    • "MyPortlet" - URL to page with only "MyPortlet" loaded
    • {"MyPortlet", "YourPortlet"} - URL to page with listed portlets on a single page.
  • Ability for portlet containers to add extra deployments into the runtime container prior to deployment of the test archive
  • @PortalTest marker annotation on test class to allow special processing by container specific implementations

As part of the extension we provide implementations for the following portlet containers:

Code example


@RunWith(Arquillian.class)
@PortalTest
public class PortletTest {
    @Deployment
    public static WebArchive createDeployment() {
        return ShrinkWrap
            .create(WebArchive.class)
            .addAsLibraries(
                Maven.resolver().loadPomFromFile("pom.xml")
                    .resolve("org.jboss.portletbridge:portletbridge-impl")
                    .withTransitivity
                    .asFile())
            .addAsWebInfResource("WEB-INF/web.xml", "web.xml")
            .addAsWebInfResource("WEB-INF/faces-config.xml")
            .addAsWebInfResource("WEB-INF/portlet.xml", "portlet.xml");
            .addClass(Bean.class)
            .addAsWebResource("output.xhtml", "home.xhtml")
            .addAsWebResource("resources/stylesheet.css", "resources/stylesheet.css");
    }

    protected static final By OUTPUT_FIELD = By.id("output");

    @ArquillianResource
    @PortalURL
    URL portalURL;

    @Drone
    WebDriver browser;

    @Test
    @RunAsClient
    public void renderFacesPortlet() throws Exception {
        browser.get(portalURL.toString());
        assertNotNull("Check that page contains output element", browser.findElement(OUTPUT_FIELD));
        assertTrue("Portlet should return: " + Bean.HELLO_JSF_PORTLET,
            ExpectedConditions.textToBePresentInElement(OUTPUT_FIELD, Bean.HELLO_JSF_PORTLET).apply(driver));
    }
}

Shrinkwrap PortletArchive

We can now simplify the process of creating an Archive for portlet testing with PortletArchive.

The PortletArchive allows us to create definitions for portlets that extend GenericPortlet or GenericFacesPortlet by pre-populating portlet.xml for us.

To create a PortletArchive with a portlet.xml definition of a portlet called MyPortlet we do:

ShrinkWrap.create(PortletArchive.class)
          .createSimplePortlet(MyPortlet.class);

Using PortletArchive, the above code sample for the deployment method now becomes:

@Deployment
public static PortletArchive createDeployment() {
    return ShrinkWrap
            .create(PortletArchive.class)
            .createFacesPortlet("SimpleTest", "Simple Test Portlet", "home.xhtml")
            .addAsLibraries(
                Maven.resolver().loadPomFromFile("pom.xml")
                    .resolve("org.jboss.portletbridge:portletbridge-impl")
                    .withTransitivity
                    .asFile())
            .addAsWebInfResource("WEB-INF/web.xml", "web.xml").addAsWebInfResource("WEB-INF/faces-config.xml")
            .addClass(Bean.class)
            .addAsWebResource("output.xhtml", "home.xhtml")
            .addAsWebResource("resources/stylesheet.css", "resources/stylesheet.css");
}

Warp Portlets

We can now take advantage of Warp to test the internals of our portlets!

For testing non JSF portlets, such as those extending GenericPortlet, we can use @BeforePortletPhase and @AfterPortletPhase on our Warp inspection methods. The possible values for these annotations are ACTION, EVENT, RENDER, and RESOURCE, signifying which type of portlet request we want the method to run before or after.

An example usage:

@RunWith(Arquillian.class)
@PortalTest
@WarpTest
public class PortletWarpTest {

    @Deployment
    public static PortletArchive getDeployment() {
    ...
    }

    @ArquillianResource
    @PortalURL
    URL portalURL;

    @Drone
    WebDriver browser;

    @Test
    @RunAsClient
    public void portletAction() throws Exception {

        browser.navigate().to(portalURL);

        Warp
            .initiate(new Activity() {
                public void perform() {
                    submitButton.click();
                }
            })
            .group()
                .observe(request().index(1))
                .inspect(new Inspection() {
                    private static final long serialVersionUID = 1L;

                    @ArquillianResource
                    ActionResponse actionResponse;

                    @BeforePortletPhase(Phase.ACTION)
                    public void beforeActionRequest() {
                        String[] values = actionResponse.getRenderParameterMap().get("data");
                        assertNull("Render parameter for data should not be set.", values);
                    }

                    @AfterPortletPhase(Phase.ACTION)
                    public void afterActionRequest() {
                        String[] values = actionResponse.getRenderParameterMap().get("data");
                        assertTrue("Render parameter for data should be set.", values.length == 1);
                        assertEquals("Render parameter set to incorrect value.", BasicPortlet.ACTION, values[0]);
                    }
                })
            .group()
                .observe(request().index(2))
                .inspect(new Inspection() {
                    private static final long serialVersionUID = 1L;

                    @ArquillianResource
                    RenderRequest renderRequest;

                    @BeforePortletPhase(Phase.RENDER)
                    public void beforeRenderRequest() {
                        String value = renderRequest.getParameter("data");
                        assertEquals("Render parameter set to incorrect value.", BasicPortlet.ACTION, value);
                    }
                })
            .execute();
    }
}

The above example also shows how we can inject the request and response objects into the Inspection to perform our assertions. All portlet lifecycle specific request and response objects, such as ActionRequest, are available for injection, in addition to the generic PortletRequest and PortletResponse objects.

An important point about the above example is the use of Warp groups and differentiating them by the first and second request. Most portlet containers implement the pattern of performing a redirect between an ActionRequest or EventRequest and the subsequent RenderRequest, so we need to bear this in mind when writing our Warp inspections. We can easily distinguish between which request we want to act on by using observe(), such as the following for an ActionRequest:

.group()
    .observe(request().index(1))
    .inspect(new Inspection() {...})

This will inform Warp that we want the inspection to run against the first request that it monitors.

We're also able to test our JSF portlets by enhancing the Warp JSF extension to handle portlets. JSF portlets can still use @BeforePortletPhase and @AfterPortletPhase on inspection methods, but it's important to realize that these annotations won't provide access to JSF internals as they are acting purely in the context of a portlet request. To fully interact with the JSF lifecycle we need to use the Warp JSF annotations along with @PortletPhase to signify in which portlet lifecycle phase we want to interact with JSF.

An example of inspecting a JSF portlet:

@RunWith(Arquillian.class)
@PortalTest
@WarpTest
public class JSFPortletWarpTest {

    @Deployment
    public static PortletArchive getDeployment() {
    ...
    }

    @ArquillianResource
    @PortalURL
    URL portalURL;

    @Drone
    WebDriver browser;

    @Test
    @RunAsClient
    public void portletAction() throws Exception {

        browser.navigate().to(portalURL);

        Warp
            .initiate(new Activity() {
                public void perform() {
                    inputField.clear();
                    inputField.sendKeys("newValue");
                    submitButton.click();
                }
            })
            .group()
                .observe(request().index(1))
                .inspect(new Inspection() {
                    private static final long serialVersionUID = 1L;


                    @ManagedProperty("#{bean}")
                    Bean bean;

                    @PortletPhase(ACTION) @BeforePhase(Phase.UPDATE_MODEL_VALUES)
                    public void testBeanValueBeforeUpdate() {
                        assertEquals("Bean value should not be updated yet.", "originalValue", bean.getText());
                    }

                    @PortletPhase(ACTION) @AfterPhase(Phase.UPDATE_MODEL_VALUES)
                    public void testBeanValueAfterUpdate() {
                        assertEquals("Bean value should now be updated.", "newValue", bean.getText());
                    }
                })
            .group()
                .observe(request().index(2))
                .inspect(new Inspection() {
                    private static final long serialVersionUID = 1L;

                    @ManagedProperty("#{bean}")
                    Bean bean;

                    @PortletPhase(RENDER) @BeforePhase(Phase.RENDER_RESPONSE)
                    public void testBeanValueBeforeRenderResponse() {
                        assertEquals("Bean value should still contain new value.", "newValue", bean.getText());
                    }
                })
            .execute();
    }
}

The above example will execute two inspection methods, before and after, around the UPDATE_MODEL_VALUES JSF lifecycle phase when part of an ActionRequest during the first group, and a separate group that will execute an inspection method before the JSF RENDER_RESPONSE lifecycle phase as part of a RenderRequest.

Notice that we can also use the same @ManagedProperty from Warp JSF to inject our JSF beans into the Inspection.

Something went wrong with that request. Please try again.