1

I'm learning Arquillian right now I wonder how to create page that has a placeholder inside the path. For example:

@Location("/posts/{id}")
public class BlogPostPage {
     public String getContent() {
          // ...
     }
}

or

@Location("/posts/{name}")
@Location("/specific-page?requiredParam={value}")

I have looking for an answer on graphine and arquillian reference guides without success. I used library from other language that have support for page-objects, but it has build-in support for placeholders.

Yavin
  • 445
  • 3
  • 15

2 Answers2

0

AFAIK there is nothing like this implemented in Graphene. To be honest, I'm not sure how this should behave - how would you pass the values...?

Apart from that, I think that it could be also limited by Java annotation abilities https://stackoverflow.com/a/10636320/6835063

Community
  • 1
  • 1
  • something like `pageInstance.open(parametersMap)` and the map is eg `id => 7`. I'm looking at source of graphene, maybe i'll find something helpful. Thanks for the help! – Yavin Sep 21 '16 at 19:26
0

This is not possible currently in Graphene. I've created ARQGRA-500.

It's possible to extend Graphene to add dynamic parameters now. Here's how. (Arquillian 1.1.10.Final, Graphene 2.1.0.Final.)

Create an interface.

import java.util.Map;

public interface LocationParameterProvider {

    Map<String, String> provideLocationParameters();

}

Create a custom LocationDecider to replace the corresponding Graphene's one. I replace the HTTP one. This Decider will add location parameters to the URI, if it sees that the test object implements our interface.

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
import java.util.Map.Entry;

import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.graphene.location.decider.HTTPLocationDecider;
import org.jboss.arquillian.graphene.spi.location.Scheme;
import org.jboss.arquillian.test.spi.context.TestContext;

public class HTTPParameterizedLocationDecider extends HTTPLocationDecider {

    @Inject
    private Instance<TestContext> testContext;

    @Override
    public Scheme canDecide() {
        return new Scheme.HTTP();
    }

    @Override
    public String decide(String location) {
        String uri = super.decide(location);

        // not sure, how reliable this method of getting the current test object is
        // if it breaks, there is always a possibility of observing
        // org.jboss.arquillian.test.spi.event.suite.TestLifecycleEvent's (or rather its
        // descendants) and storing the test object in a ThreadLocal
        Object testObject = testContext.get().getActiveId();
        if (testObject instanceof LocationParameterProvider) {
            Map<String, String> locationParameters = 
                    ((LocationParameterProvider) testObject).provideLocationParameters();

            StringBuilder uriParams = new StringBuilder(64);
            boolean first = true;
            for (Entry<String, String> param : locationParameters.entrySet()) {
                uriParams.append(first ? '?' : '&');
                first = false;
                try {
                    uriParams.append(URLEncoder.encode(param.getKey(), "UTF-8"));
                    uriParams.append('=');
                    uriParams.append(URLEncoder.encode(param.getValue(), "UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    throw new RuntimeException(e);
                }
            }
            uri += uriParams.toString();
        }

        return uri;
    }

}

Our LocationDecider must be registered to override the Graphene's one.

import org.jboss.arquillian.core.spi.LoadableExtension;
import org.jboss.arquillian.graphene.location.decider.HTTPLocationDecider;
import org.jboss.arquillian.graphene.spi.location.LocationDecider;

public class MyArquillianExtension implements LoadableExtension {

    @Override
    public void register(ExtensionBuilder builder) {
        builder.override(LocationDecider.class, HTTPLocationDecider.class,
            HTTPParameterizedLocationDecider.class);
    }

}

MyArquillianExtension should be registered via SPI, so create a necessary file in your test resources, e.g. for me the file path is src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension. The file must contain a fully qualified class name of MyArquillianExtension.

And that's it. Now you can provide location parameters in a test.

import java.util.HashMap;
import java.util.Map;

import org.jboss.arquillian.graphene.page.InitialPage;
import org.jboss.arquillian.graphene.page.Location;
import org.junit.Test;

public class TestyTest implements LocationParameterProvider {

    @Override
    public Map<String, String> provideLocationParameters() {
        Map<String, String> params = new HashMap<>();
        params.put("mykey", "myvalue");
        return params;
    }

    @Test
    public void test(@InitialPage TestPage page) {
    }

    @Location("MyTestView.xhtml")
    public static class TestPage {

    }

}

I've focused on parameters specifically, but hopefully this paves the way for other dynamic path manipulations.

Of course this doesn't fix the Graphene.goTo API. This means before using goTo you have to provide parameters via this roundabout provideLocationParameters way. It's weird. You can make your own alternative API, goTo that accepts parameters, and modify your LocationDecider to support other ParameterProviders.

Vsevolod Golovanov
  • 4,068
  • 3
  • 31
  • 65