Search code examples
mavenjakarta-eejboss-arquillianshrinkwraparquillian-drone

How to use a Maven ear artifact in Arquillian functional testing?


All examples I've encountered so far use Arquillian's @Deployment(testable = false) public static Archive<?> createDeployment() to build their own WebArchive or EnterpriseArchive which allows to test parts of the application in a quick and isolated way. However, in my understanding it also would make sense to test the generated EAR (in a multi-module Java EE setup) directly taken from Maven after the install phase finished, i.e. in a separate module running after the EAR assembly, e.g. with

@Deployment(testable = false)
public static Archive<?> createDeployment() {
    EnterpriseArchive retValue = Maven.configureResolver().workOffline().resolve("richtercloud:arquillian-ear-it-ear:ear:1.0-SNAPSHOT").withoutTransitivity().asSingle(EnterpriseArchive.class);
    retValue.writeTo(System.out, Formatters.VERBOSE);
    return retValue;
}

So that one can conduct test like

@Drone
private WebDriver browser;
@ArquillianResource
private URL deploymentUrl;
@FindBy(id = "mainForm:saveButton")
private WebElement saveButton;

@Test
public void testWebFrontend() throws IOException {
    browser.get(deploymentUrl+ "/index.xhtml");
    seleniumHelper.screenshot(browser);
    Assert.assertTrue(saveButton.isDisplayed());
}

This currently fails because the injected deployment URL ignores the context-path of the application which results in the request to index.xhtml failing because of The requested resource is not available and HTTP error 404.

Interestingly, the web module of the EAR is present in the local Maven cache installation, but missing in the listing. This still is the case after adding it explicitly with retValue.addAsModule(Maven.configureResolver().workOffline().resolve("richtercloud:arquillian-ear-it-web:war:1.0-SNAPSHOT").withTransitivity().asSingle(WebArchive.class)); which I then not understand at all. Maybe I'm misunderstanding what Shrinkwrap is resolving.

The versions are

<properties>
    <powermock.version>1.7.0RC4</powermock.version>
    <version.org.jboss.arquillian>1.1.5.Final</version.org.jboss.arquillian>
    <version.org.wildfly>8.1.0.Final</version.org.wildfly>
    <version.junit>4.12</version.junit>
    <browser>phantomjs</browser>
</properties>
<dependencies>
    <dependency>
        <groupId>richtercloud</groupId>
        <artifactId>arquillian-ear-it-jar</artifactId>
        <version>1.0-SNAPSHOT</version>
        <scope>test</scope>
        <type>jar</type>
    </dependency>
    <dependency>
        <groupId>org.primefaces</groupId>
        <artifactId>primefaces</artifactId>
        <version>6.1</version>
    </dependency>
    <dependency>
        <groupId>net.glxn</groupId>
        <artifactId>qrgen</artifactId>
        <version>1.4</version>
    </dependency>
    <dependency>
        <groupId>richtercloud</groupId>
        <artifactId>validation-tools</artifactId>
        <version>1.0-SNAPSHOT</version>
        <type>jar</type>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.5</version>
        <type>jar</type>
    </dependency>
    <dependency>
        <groupId>xerces</groupId>
        <artifactId>xercesImpl</artifactId>
        <version>2.11.0</version>
        <scope>test</scope>
        <type>jar</type>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.2</version>
        <type>jar</type>
    </dependency>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-web-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4</artifactId>
        <version>${powermock.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-api-mockito2</artifactId>
        <version>${powermock.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>net.sf.jmimemagic</groupId>
        <artifactId>jmimemagic</artifactId>
        <version>0.1.3</version>
        <exclusions>
            <exclusion>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
            </exclusion>
            <exclusion>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
            </exclusion>
            <exclusion>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.imgscalr</groupId>
        <artifactId>imgscalr-lib</artifactId>
        <version>4.2</version>
    </dependency>
    <dependency>
        <groupId>org.ocpsoft.prettytime</groupId>
        <artifactId>prettytime</artifactId>
        <version>3.2.7.Final</version>
    </dependency>
    <dependency>
        <groupId>org.bitbucket.cowwoc</groupId>
        <artifactId>diff-match-patch</artifactId>
        <version>1.1</version>
    </dependency>
    <dependency>
        <groupId>org.rauschig</groupId>
        <artifactId>jarchivelib</artifactId>
        <version>0.7.1</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>

    <!-- Java EE integration testing -->
    <dependency>
        <groupId>org.jboss.shrinkwrap.descriptors</groupId>
        <artifactId>shrinkwrap-descriptors-api-javaee</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.jboss.arquillian.junit</groupId>
        <artifactId>arquillian-junit-container</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.jboss.shrinkwrap.resolver</groupId>
        <artifactId>shrinkwrap-resolver-depchain</artifactId>
        <type>pom</type>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.jboss.arquillian.graphene</groupId>
        <artifactId>graphene-webdriver</artifactId>
        <version>2.3.2</version>
        <type>pom</type>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>com.codeborne</groupId>
                <artifactId>phantomjsdriver</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>com.codeborne</groupId>
        <artifactId>phantomjsdriver</artifactId>
    </dependency>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>htmlunit-driver</artifactId>
    </dependency>
    <dependency>
        <groupId>net.sourceforge.htmlunit</groupId>
        <artifactId>htmlunit</artifactId>
        <version>2.26</version>
    </dependency>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-java</artifactId>
    </dependency>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-firefox-driver</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.9.2</version>
    </dependency>
    <dependency>
        <groupId>richtercloud</groupId>
        <artifactId>jsf-validation-service</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>richtercloud</groupId>
        <artifactId>selenium-tools</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.jboss.arquillian</groupId>
            <artifactId>arquillian-bom</artifactId>
            <version>1.1.14.Final</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.arquillian.selenium</groupId>
            <artifactId>selenium-bom</artifactId>
            <version>3.7.0</version>
                <!-- - 3.3.1, 3.2.0 and 3.1.0 cause   required: java.util.function.Function<? super org.openqa.selenium.WebDriver,V>
                        found: org.openqa.selenium.support.ui.ExpectedCondition<org.openqa.selenium.WebElement>
                        reason: cannot infer type-variable(s) V
                        (argument mismatch; org.openqa.selenium.support.ui.ExpectedCondition<org.openqa.selenium.WebElement> cannot be converted to java.util.function.Function<? super org.openqa.selenium.WebDriver,V>)
                - 3.0.1 causes java.lang.IllegalAccessError: tried to access class org.openqa.selenium.os.ExecutableFinder from class org.openqa.selenium.phantomjs.PhantomJSDriverService when using phantomjs driver
                - 3.6.0 causes `Unrecognized platform: linux-unknown-64bit`
                    which one is supposed to work around using 3.5.3
                    <ref>https://github.com/SeleniumHQ/selenium/issues/4781</ref>-->
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.arquillian.extension</groupId>
            <artifactId>arquillian-drone-bom</artifactId>
            <version>2.4.3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<profiles>
    <profile>
        <id>arquillian-glassfish-embedded</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <dependencies>
            <dependency>
                <groupId>org.jboss.arquillian.container</groupId>
                <artifactId>arquillian-glassfish-embedded-3.1</artifactId>
                <version>1.0.1</version>
            </dependency>
            <dependency>
                <groupId>fish.payara.extras</groupId>
                <artifactId>payara-embedded-all</artifactId>
                <version>4.1.2.174</version>
                    <!-- - 4.1.2.173 causes `java.lang.NoClassDefFoundError: fish/payara/nucleus/healthcheck/stuck/StuckThreadsStore`
                        - 4.1.2.172 causes `java.lang.ClassNotFoundException: fish.payara.notification.eventbus.EventbusMessage`
                        - 4.1.153 and 4.1.2.174 cause `java.lang.NullPointerException
                        at org.omnifaces.application.OmniApplication.createValidator(OmniApplication.java:114)` when using OmniFaces -->
                <scope>test</scope>
            </dependency>
        </dependencies>
        <build>
            <testResources>
                <testResource>
                    <directory>src/test/resources</directory>
                </testResource>
                <testResource>
                    <directory>src/test/resources-glassfish-embedded</directory>
                </testResource>
            </testResources>
        </build>
    </profile>
</profiles>

The SSCCE arquillian-ear-it illustrates the issue.


Solution

  • The above scenario can be accomplished by appending the context path to the deployment URL, e.g.

    browser.get(deploymentUrl+ "/arquillian-ear-it-web/index.xhtml");
    

    in the SSCCE. A working version is provided on the web-frontend-test branch.

    Note that the web module strangely isn't listed when printing the content with enterpriseArchive.writeTo(System.out, Formatters.VERBOSE), but it's present.