DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Coding
  3. Java
  4. Serenity Tricks With Java 8

Serenity Tricks With Java 8

Lambda expressions can be used to help set up and pass your testing code. This guide shows you how Java 8's functional aspects can synergize with Serenity.

John Ferguson Smart user avatar by
John Ferguson Smart
·
Jan. 10, 17 · Tutorial
Like (7)
Save
Tweet
Share
10.07K Views

Join the DZone community and get the full member experience.

Join For Free

Java 8 came out back in 2014, but I still find many teams not making as much use of its features as they could. Arguably the biggest new feature in Java 8 were Lambda expressions, which finally brought a taste of functional programming to the Java world.

In this article, I want to give a simple example of how Java 8 and Lambda expressions can make your life easier, through a concrete example. Suppose we want to write a test for one of the few remaining applications that use frames or iframes. The Java APIs are a good example. Automating pages with frames and iframes using WebDriver is tricky because, when you manipulate a web element, you first need to switch to the frame it is in, like this:

driver.switchTo().frame("MyFrame");
button.click();
driver.switchTo().defaultContent();


Let's see how we could make this nicer in Java 8. Imagine we need to write a test to check that when you select a package in the Packages list, the correct list of classes and interfaces appears in the frame to the lower left of the screen. We could write a very simple Serenity BDD test like this:

@RunWith(SerenityRunner.class)
public class WhenConsultingPackageDetails {

    @Managed WebDriver driver;

    JavaAPIDocs apiDocs;

    @Test
    public void should_be_able_to_view_the_classes_for_a_given_package() {

        // Given
        apiDocs.open();

        // When
        apiDocs.selectAPackage("java.applet");

        // Then
        assertThat(apiDocs.getClassesAndInterfaces()).contains("AppletContext",
                                                                "AppletStub",
                                                                "AudioClip",
                                                                "Applet");
    }
}


The JavaAPIDocs is a Serenity Page Object, that Serenity will initialise for us. It looks something like this.

@DefaultUrl("https://docs.oracle.com/javase/7/docs/api/")
public class JavaAPIDocs extends PageObject {

    @FindBy(tagName = "li")
    private List<WebElementFacade> packageNames;

    public JavaAPIDocs(WebDriver driver) {
        super(driver);
    }

    public void selectAPackage(final String packageName) {
        ...
    }

    public List<String> getClassesAndInterfaces() {
        ...
    }
}


Now suppose we want to implement the selectAPackage method. Using Java 7, we would need to first navigate to the frame, find the corresponding link to click on, then navigate back to the main window:

public void selectAPackage(final String packageName) {
    getDriver().switchTo().frame(("packageListFrame")
    find(By.linkText(packageName)).click();
    getDriver().switchTo().defaultContent();
}


In Java 8, on the other hand, we could create a class whose responsibility it is to switch to and from frames, and then just pass in the operation (as a Lambda expression) that we want to perform. Suppose we call this class InFrame. Our method would become something like this:

private InFrame inAFrame;

public JavaAPIDocs(WebDriver driver) {
    super(driver);
    inAFrame = new InFrame(driver);
}

public void selectAPackage(final String packageName) {
    inAFrame.called("packageListFrame").attemptTo(() -> find(By.linkText(packageName)).click());
}


Notice how much more readable the selectAPackage() method just became? The magic happens in the InFrame class, which contains a method, attemptTo, whose job is to execute a lambda expression passed to it as a parameter:

public void attemptTo(UIPerformable performable) {
    driver.switchTo().frame(iframeNameOrId);
    performable.perform();
    driver.switchTo().defaultContent();
}


The UIPerformable is a simple functional interface that we can use to pass a lambda expression to the method:

@FunctionalInterface
public interface UIPerformable {
    void perform();
}


We can now use this method to execute a block of WebDriver code, as simple or as complex as we need. We can be sure that we will switch to the right frame before the operation starts, and switch back when we are done.

The getClassesAndInterfaces() method is similar:

public List<String> getClassesAndInterfaces() {
    return inAFrame.called("packageFrame").retrieve(() ->
            packageNames.stream()
                    .map(WebElement::getText)
                    .collect(Collectors.toList())
    );
}


Here, we use the retrieve() method, which takes a Supplier, one of the standard Java 8 functional interfaces. Like in the previous example, we switch to the frame, perform the operation, then switch back. Only this time, the operation returns a value:

public <T> T retrieve(Supplier<T> performable) {
    driver.switchTo().frame(iframeNameOrId);
    T result = performable.get();
    driver.switchTo().defaultContent();
    return result;
}


We also use Java 8 streams to convert the list of web elements returned by WebDriver to a list of Strings, another nice feature of Java 8.

The full InFrame class is shown here:

public class InFrame {
    private final WebDriver driver;

    public InFrame(WebDriver driver) {
        this.driver = driver;
    }

    public InstantiatedIFrameContainer called(String iframeNameOrId) {
        return new InstantiatedIFrameContainer(driver, iframeNameOrId);
    }

    public class InstantiatedIFrameContainer {
        private final WebDriver driver;
        private final String iframeNameOrId;

        public InstantiatedIFrameContainer(WebDriver driver, String iframeNameOrId) {
            this.driver = driver;
            this.iframeNameOrId = iframeNameOrId;
        }

        public void attemptTo(UIPerformable performable) {
            driver.switchTo().frame(iframeNameOrId);
            performable.perform();
            driver.switchTo().defaultContent();
        }

        public <T> T retrieve(Supplier<T> performable) {
            driver.switchTo().frame(iframeNameOrId);
            T result = performable.get();
            driver.switchTo().defaultContent();
            return result;
        }
    }
}


This class took a little more effort to write initially, but in an application with a lot of frames, the effort would pay itself off very quickly through more readable and more concise Page Object and test code.

Java (programming language)

Published at DZone with permission of John Ferguson Smart, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How To Generate Code Coverage Report Using JaCoCo-Maven Plugin
  • Web Application Architecture: The Latest Guide
  • A Complete Guide to AngularJS Testing
  • What Should You Know About Graph Database’s Scalability?

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: