ShrinkWrap Resolver 2.0.0-alpha-4 Released

Since we wrote this post we didn't laze around. Check our latest announcement.

The Arquillian team is proud to announce the 2.0.0-alpha-4 release of the ShrinkWrap Resolver component!

What is ShrinkWrap Resolver?

The ShrinkWrap Resolvers project provides a Java API to obtain artifacts from a repository system. This is handy to include third party libraries available in any Maven repository in your test archive. ShrinkWrap Resolvers additionally allow you to reuse all the configuration you've already specified in the Maven build file, making packaging of an application archive much easier job.

Release details

Component ShrinkWrap Resolver
Version 2.0.0-alpha-4 view tag
Release date 2012-09-22
Released by Andrew Lee Rubinger
Compiled against
  • JUnit – 4.8.2

Published artifacts org.jboss.shrinkwrap.resolver

  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-bom pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-api jar javadoc pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-api-maven jar javadoc pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-api-maven-archive jar javadoc pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-depchain pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-maven-plugin-tests jar javadoc pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-impl-maven jar javadoc pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-impl-maven-archive jar javadoc pom

Release notes and resolved issues 3

Feature Request
  • SHRINKRES-67 - BOM file should contain depchain included
  • SHRINKRES-68 - Remove Runtime Dependency on Plexus and transitives
Task
  • SHRINKRES-69 - Fix RepositoryAuthTestCase, Ensure bad auth values are not cached

Thanks to the following list of contributors: Andrew Lee Rubinger, Karel Piwko

Introducing Arquillian Graphene Page Fragments

Tools like Arquillian Graphene, WebDriver, or just plain Selenium combined with concepts like Page Objects can help you automate your functional(integration, whatever…) web UI tests. We have already introduced some of the advances brought to you by Arquillian Graphene earlier. In this blog entry we will look a bit deeper into a new concept introduced in Arquillian Graphene 2.0.0.Alpha2; Page Fragments.

Consider the following example taken from the RichFaces component showcase. The page under test contain three Autocomplete widgets.

public class TestAutocompleteWidgets extends AbstractGrapheneTest {

    private JQueryLocator minCharInput = jq("input[type=text]:eq(0)");
    private JQueryLocator multipleSelectionInput = jq("input[type=text]:eq(1)");
    private JQueryLocator selectFirstFalseInput = jq("input[type=text]:eq(2)");
    private JQueryLocator selection = jq("div.rf-au-itm");

    @Test
    public void testFirstAutocomplete() {

        graphene.keyPress(minCharInput, 'a');

        assertFalse(graphene.isElementPresent(selection),
            "The suggestion list should not be visible, since there is only one char!");

        String keys = "ar";
        graphene.focus(minCharInput);
        selenium.type(minCharInput, keys);
        guardXhr(graphene).fireEvent(minCharInput, Event.KEYPRESS);

        assertTrue(graphene.isVisible(selection), 
            "The suggestion list should be visible, since there are two chars!");

        String actualArizona = graphene.getText(jq(selection.getRawLocator() + ":eq(0)"));
        assertEquals(actualArizona, "Arizona", "The provided suggestion should be Arizona!");

        String actualArkansas = graphene.getText(jq(selection.getRawLocator() + ":eq(1)"));
        assertEquals(actualArkansas, "Arkansas", "The provided suggestion should be Arkansas!");

    }

    @Test
    public void testSecondAutocomplete() {

        char key = 'a';
        selenium.focus(multipleSelectionInput);
        guardXhr(selenium).keyPress(multipleSelectionInput, key);

        assertTrue(selenium.isVisible(selection),
            "The suggestion list should be visible, since there is correct starting char!");

        selenium.keyPressNative(KeyEvent.VK_ENTER);

        key = ' ';
        selenium.keyPress(multipleSelectionInput, key);

        key = 'w';

        selenium.focus(multipleSelectionInput);
        guardXhr(selenium).keyPress(multipleSelectionInput, key);

        assertTrue(selenium.isVisible(selection),
            "The suggestion list should be visible, since there is correct starting char!");

        selenium.keyPressNative(KeyEvent.VK_ENTER);

        String actualContentOfInput = selenium.getValue(multipleSelectionInput);
        assertEquals(actualContentOfInput, "Alabama Washington", "The input should contain something else!");
    }

    @Test
    public void testThirdAutocomplete() {
        //similar autocomplete interactions as in the previous tests
    }
}

Now, ask yourself the following questions:

  • Do you find these types of tests less robust than for example unit tests for the persistence layer?
  • Do you think these tests still pass when the underlying HTML change?
  • Do you see repeating code in the these tests?

In my opinion you should have a clean answer to all of these questions. You are probably aware that tests should be loosely coupled with the underlying HTML structure of the application under test as it makes tests more robust and changes in the HTML structure of the page will not directly affect all tests.

Let’s apply the Page Objects pattern to split the HTML structure and the test logic. The Page Object will encapsulate the HTML structure so when the HTML change, only your Page Objects has to change.

  • But what about when I’m testing another application that use the same Autocomplete widget?
  • Should I copy the part of the Page Object that interact with the Autocomplete widget and paste it around in my code?

But as you’re already thinking: this would be a major don’t-repeat-yourself violation! Is there something we could do to improve this?

Yes, there is! Arquillian Graphene Page Fragments to the rescue!

Page Fragments, what are they?

  • Page Fragments are any repeating part of a page, any widget, web component, etc.
  • They encapsulate parts of the page into reusable test components across your whole test suite.
  • You can differentiate each fragment by its root element and reference other elements as children of that root.
  • They leverage Selenium WebDriver under the hood combined with all of the killer features of Graphene.
  • And they come with a set of utilities which simplify using them within tests and Page Objects.

How to define Page Fragments

public class AutocompleteFragment<T> {

    @Root
    WebElement root;

    @FindBy(css = "input[type='text']")
    WebElement inputToWrite;

    public static final String CLASS_NAME_SUGGESTION = "rf-au-itm";

    public List<Suggestion<T>> getAllSuggestions(SuggestionParser<T> parser) {
        List<Suggestion<T>> allSugg = new ArrayList<Suggestion<T>>();

        if (areSuggestionsAvailable()) {
            WebElement rightSuggList = getRightSuggestionList();
            List<WebElement> suggestions = rightSuggList.findElements(
                        By.className(CLASS_NAME_SUGGESTION));

            for (WebElement suggestion : suggestions) {
                allSugg.add(parser.parse(suggestion));
            }
        }

        return allSugg;
    }

    public List<Suggestion<T>> type(String value, SuggestionParser<T> parser) {
        List<Suggestion<T>> suggestions = new ArrayList<Suggestion<T>>();

        inputToWrite.sendKeys(value);
        try {
            waitForSuggestions();
        } catch (TimeoutException ex) {
            // no suggestions available
            return suggestions;
        }

        suggestions = getAllSuggestions(parser);
        return suggestions;
    }

    //other handy encapsulation of Autocomplete services
}

The example is just a snippet from the full implementation of the RichFaces Autocomplete component.

Notice the @Root annotation? The value of the root field is automatically injected by Graphene. The root field contain the root element as defined by the @FindBy annotation on the injection point of the Page Fragment in the Page Object or test. All @FindBy fields in the Page Fragment will use this root as a starting point.

The fragment implementation is pretty generic and therefore reusable in all tests in all applications that use the Autocomplete widget. A full implementation would encapsulate all the services this fragment provide, but it could for example also encapsulate browser specific interactions like submit or click actions. There are no boundaries!

Using Page Fragments and Page Objects together

Let’s rewrite the previous test to use our new Page Fragment together with our Page Object.

First we define a Page Object which contain the structure of the page under test.

public class TestPage {
    
    @FindBy(css = "div.rf-au:nth-of-type(1)")
    private AutocompleteFragment<String> autocomplete1;

    @FindBy(css = "div.rf-au:nth-of-type(2)")
    private AutocompleteFragment<String> autocomplete2;

    @FindBy(css = "div.rf-au:nth-of-type(3)")
    private AutocompleteFragment<String> autocomplete3;

    @FindBy(xpath = "//*[contains(@id,'sh1')]")
    private WebElement viewSourceLink;

    //all getters for the fields

    //other handy methods which you find useful when testing those three Autocomplete widgets
}

Declaring the Page Fragment in the Page Object is the preferred option, but you can also declare the Page Fragment directly in the test if desired. The only thing you need to do is to annotate the Page Fragment object with WebDriver’s @FindBy annotation to refer to the fragment’s root DOM element. That simple!

Graphene differentiates between Page Fragments and plain WebElements in the same Page Object so they can be declared side by side. All of the initialization is done automatically, so there is no need to initialize the Page Fragments or Page Objects in the @Before method of your test case.

In this last example we see how the autocomplete widgets’s Page Fragment is used in the test case.

public class TestWhichUsesPageFragments extend AbstractTest {

    @Page
    private TestPage testPage;

    @Test
    public void testFirstAutocomplete {
        AutocompleteFragment<String> autocomplete = testPage.getAutocomplete1();
        
        autocomplete.type("a");

        assertFalse(autocomplete.areSuggestionsAvailable(), 
            "The suggestion list should not be visible, since there is only one char!");

        String keys = "ar";
        autocomplete.type(keys);

        assertTrue(autocomplete.areSuggestionsAvailable(), 
            "The suggestion list should be visible, since there are two chars!");

        List<Suggestion<String>> expectedSuggestions = new ArrayList<Suggestion<String>>();
        expectedSuggestions.add(new Suggestion<String>("Arizona"));
        expectedSuggestions.add(new Suggestion<String>("Arkansas"));

        assertEquals(autocomplete.getAllSuggestions(new StringSuggestionParser()), expectedSuggestions, 
            "Suggestions are wrong!");
    }

    @Test
    public void testSecondAutocomplete() {
        AutocompleteFragment<String> autocomplete = testPage.getAutocomplete2();

        String key = "a";
        autocomplete.type(key);
        
        String errorMsg = "The suggestion list should be visible, since there was typed correct char ";
        assertTrue(autocomplete.areSuggestionsAvailable(), errorMsg + key);

        autocomplete.autocomplete(autocomplete.getFirstSuggestion());

        autocomplete.type(" ");

        key = "w"
        autocomplete.type(key);

        assertTrue(autocomplete.areSuggestionsAvailable(), errorMsg + key);

        autocomplete.autocomplete(autocomplete.getFirstSuggestion());        

        String actualContentOfInput = autocomplete.getInputValue();
        assertEquals(actualContentOfInput, "Alabama Washington", "The input should contain something else!");
    }

    @Test
    public void testThirdAutocomplete() {
        //similar autocomplete interactions as in the previous tests
    }
}

As your application grow, the only thing that needs to change is the root references of your Page Fragments. Last but not least you will be able to make your Page Fragment availabe to be used by other tests in other applications.

To try Page Fragments check out the Graphene 2.0.0.Alpha2 release. Getting start information can be found in the Reference Documentation.

ShrinkWrap Resolver 2.0.0-alpha-3 Released

Since we wrote this post we didn't laze around. Check our latest announcement.

The Arquillian team is proud to announce the 2.0.0-alpha-3 release of the ShrinkWrap Resolver component!

What is ShrinkWrap Resolver?

The ShrinkWrap Resolvers project provides a Java API to obtain artifacts from a repository system. This is handy to include third party libraries available in any Maven repository in your test archive. ShrinkWrap Resolvers additionally allow you to reuse all the configuration you've already specified in the Maven build file, making packaging of an application archive much easier job.

Release details

Component ShrinkWrap Resolver
Version 2.0.0-alpha-3 view tag
Release date 2012-09-18
Released by Andrew Lee Rubinger
Compiled against
  • JUnit – 4.8.2

Published artifacts org.jboss.shrinkwrap.resolver

  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-bom pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-api jar javadoc pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-api-maven jar javadoc pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-api-maven-archive jar javadoc pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-depchain pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-maven-plugin-tests jar javadoc pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-impl-maven jar javadoc pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-impl-maven-archive jar javadoc pom

Release notes and resolved issues 4

Task

Thanks to the following list of contributors: Andrew Lee Rubinger

Graphene 2.0.0.Alpha2 Released

Since we wrote this post we didn't laze around. Check our latest announcement.

The Arquillian team is proud to announce the 2.0.0.Alpha2 release of the Graphene component!

Graphene 2 is building on top of the Selenium WebDriver API and provide extensions for writing reusable, robust and AJAX-enabled tests with improved readability.

Graphene 2 uses the ideas from Graphene 1 (based on Selenium 1 API) and applies it to the world of Selenium WebDriver.

You can read more about the difference between Graphene 1 and Graphene 2 in the Reference Documentation

Features

Page Abstractions

Page abstractions allow you to abstract page functionality using the well-known Selenium design pattern Page Objects. In Graphene you can inject page objects directly into the test case using the @Page annotation.

But we take the Page Objects pattern one step further with the concept of Page Fragments . Page Fragments are reusable parts within a page encapsulated into an object similar to Page Objects. A good example of Page Fragments are JavaScript widgets or forms.

The concept of Page Fragments comes from an idea that those components share a same underlying DOM structure, the only difference between all occurences of a component is a location in a DOM tree where a component is rendered – this is denoted by the @Root annotation. You can define this root location for each concrete occurence using a @FindBy(locator) annotation.

Fluent-API for Waiting Conditions

Graphene provides a set of widely used conditions to avoid writing them repeatedly.

Request Guards

Request guards block the Selenium test execution until a network communication caused by a given action ends. Guards support blocking on HTTP and XHR (AJAX) but can also be used to verify that no such requests were done.

Under the Hood

There are some low level features exposed as API that are used by Graphene internally. While not used regularly within a normal test, can be handy to write more robust tests:

JavaScript Interface

This allows you to write a Java interface which automatically translates Java API invocations to JavaScript calls:

@JavaScript
public interface Document {
    String getTitle();
}
Page Extensions

Page Extensions allow you to inject arbitrary JavaScript code in the page under the test. The javascript code might help you to test complex situations as well as bring completely new features for improving testing. Graphene internally uses Page Extensions for Request Guards.

Graphene Context

Graphene allows you to obtain current thread-local context of a browser session and inject it exactly where you need. No more need for driver reference propagation.

Documentation

Last but definitely not the least addition is the great documentation for all of the features above including answers for general questions like how Selenium 1, Graphene 1, Selenium WebDriver and Graphene 2 relates to each other, what’s the relation between Graphene’s, Drone and Arquillian.

Getting Started

It’s the same as with any other Arquillian extension: open the IDE, setup the Maven dependency and you are ready to start testing!

What’s next?

In the upcoming releases, we would like to focus on more new features as well as migrate some features from Graphene 1 to Graphene 2:

  • Forge plugin for quick start
  • command interceptors
  • parallel browser session control
  • jQuery/Sizzle locators
  • AJAX/HTTP Communication Halter
  • page abstraction improvements
  • closer integration with the Arquillian event system
  • helpers for writing browser specific code

Call to Action

Let us know what you think and help us shape Graphene to be what you want it to be.

What is Arquillian?

Arquillian is open source software that empowers you to test JVM-based applications more effectively. Created to defend the software galaxy from bugs, Arquillian brings your test to the runtime so you can focus on testing your application's behavior rather than managing the runtime. Using Arquillian, you can develop a comprehensive suite of tests from the convenience of your IDE and run them in any IDE, build tool or continuous integration environment.

Release details

Component Graphene
Version 2.0.0.Alpha2 view tag
Release date 2012-09-12
Released by Lukas Fryc
Compiled against

Published artifacts org.jboss.arquillian.graphene

  • org.jboss.arquillian.graphene » graphene-parent pom
  • org.jboss.arquillian.graphene » graphene-selenium-parent pom
  • org.jboss.arquillian.graphene » graphene-selenium-api jar javadoc pom
  • org.jboss.arquillian.graphene » graphene-selenium-impl jar javadoc pom
  • org.jboss.arquillian.graphene » graphene-selenium-drone jar javadoc pom
  • org.jboss.arquillian.graphene » graphene-selenium pom
  • org.jboss.arquillian.graphene » graphene-webdriver-parent pom
  • org.jboss.arquillian.graphene » graphene-webdriver-impl jar javadoc pom
  • org.jboss.arquillian.graphene » graphene-webdriver-drone jar javadoc pom
  • org.jboss.arquillian.graphene » graphene-webdriver pom
  • org.jboss.arquillian.graphene » graphene-webdriver-spi jar javadoc pom
  • org.jboss.arquillian.graphene » arquillian-graphene pom
  • org.jboss.arquillian.graphene » graphene-component-api jar javadoc pom

Release notes and resolved issues 30

Adopting critical functionality from Graphene 1; Page Fragments

Component Upgrade
  • ARQGRA-150 - Upgrade to Arquillian Core 1.0.2.Final
Feature Request
  • ARQGRA-40 - Support for Component Objects pattern for Selenium 2
  • ARQGRA-41 - Support for Java-to-JavaScript calling interfaces
  • ARQGRA-62 - Umbrella: Adopt Graphene for usage of WebDriver/Selenium 2 API
  • ARQGRA-67 - Migrate request guards to Selenium 2
  • ARQGRA-71 - Adopt JavaScript injection (Page Extensions) for Selenium 2
  • ARQGRA-74 - Support Graphene utility in original scope with Selenium 2
  • ARQGRA-156 - Introduce Opera and RemoteWebDriver factory wrappers
  • ARQGRA-157 - Support XHR interception
  • ARQGRA-160 - Create a configurator for Graphene 2 using arquillian.xml
  • ARQGRA-161 - Introduce profile to enable execution from several browsers
  • ARQGRA-179 - Document difference between Graphene 1 and Graphene 2 (Selenium 1 and WebDriver)
  • ARQGRA-180 - Document Graphene - Getting Started
  • ARQGRA-181 - Document Using WebDriver
  • ARQGRA-182 - Document Using Drone
  • ARQGRA-183 - Document Testing AJAX
Bug
  • ARQGRA-6 - Using of JQuery 1.5 causes that JQuery selectors are not escaped properly
  • ARQGRA-151 - Graphene.getProxyForInterfaces returns wrong proxy
  • ARQGRA-159 - Use Drone depchain in Graphene depchain
Task
  • ARQGRA-132 - Add BOM usage into documentation
  • ARQGRA-158 - Check and complete all documentation for all features in Alpha2
  • ARQGRA-163 - Refactor Graphene Webdriver SPI module
  • ARQGRA-171 - Refactor Component Objects - mainly make Component Obejcts as POJO
  • ARQGRA-172 - Documentation for Page Extensions
  • ARQGRA-173 - Documentation for Page Fragments
  • ARQGRA-175 - Documentation for JavaScript interfaces
  • ARQGRA-176 - Documentation for GrapheneContext and proxies
  • ARQGRA-177 - Documentation for Request Guards
  • ARQGRA-178 - Documentation for Graphene utility class
  • ARQGRA-186 - Rename Component Objects dependencies to Page Fragments

Thanks to the following list of contributors: Jan Papoušek, Lukas Fryc, Juraj Huska, Brian Leathem

ShrinkWrap Resolver 2.0.0-alpha-2 Released

Since we wrote this post we didn't laze around. Check our latest announcement.

The Arquillian team is proud to announce the 2.0.0-alpha-2 release of the ShrinkWrap Resolver component!

What is ShrinkWrap Resolver?

The ShrinkWrap Resolvers project provides a Java API to obtain artifacts from a repository system. This is handy to include third party libraries available in any Maven repository in your test archive. ShrinkWrap Resolvers additionally allow you to reuse all the configuration you've already specified in the Maven build file, making packaging of an application archive much easier job.

Release details

Component ShrinkWrap Resolver
Version 2.0.0-alpha-2 view tag
Release date 2012-09-13
Released by Andrew Lee Rubinger
Compiled against
  • JUnit – 4.8.2

Published artifacts org.jboss.shrinkwrap.resolver

  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-bom pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-api jar javadoc pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-api-maven jar javadoc pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-api-maven-archive jar javadoc pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-depchain pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-maven-plugin-tests jar javadoc pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-impl-maven jar javadoc pom
  • org.jboss.shrinkwrap.resolver » shrinkwrap-resolver-impl-maven-archive jar javadoc pom

Release notes and resolved issues 18

Premiere of new API

Component Upgrade
Feature Request
  • SHRINKRES-9 - MavenDependencyResolver configureFrom should allow specifying properties for profile activation
  • SHRINKRES-32 - Enable dependency resolver to be cached for time-sensitive environments
  • SHRINKRES-45 - Allow for "offline" settings in new API
  • SHRINKRES-46 - Cache configurations for N resolution calls
  • SHRINKRES-60 - Modify API such that configuration of settings must happen before config from POM
Bug
  • SHRINKRES-34 - Scoped artifacts in ShrinkWrap Resolver BOM
Task

Thanks to the following list of contributors: Andrew Lee Rubinger, Karel Piwko, Carlo De Wolf, Samuel Santos, Tair Sabirgaliev, Sachin Patil, Aslak Knutsen