Supported Test Runners

Standalone mode (no 3rd party test-runner)

JUnit 4

  • Import this maven dependency.
<dependency>
    <groupId>org.fluentlenium</groupId>
    <artifactId>fluentlenium-junit</artifactId>
    <version>4.3.1</version>
    <scope>test</scope>
</dependency>
  • Extends FluentTest.

Fluent Test is the entry point of FluentLenium. You only have to extend FluentTest and implement a test as usual.

public class MyTest extends FluentTest {
    @Test
    public void testGoogle() {
        goTo("http://www.google.com");
    }
}

If you need to make your tests run concurrently to speed them up, you should use dedicated libraries/extensions. You can use the Surefire maven plugin for example.

Surefire JUnit example

<profile>
    <id>junit-tests</id>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <parallel>methods</parallel>
                    <threadCount>4</threadCount>
                    <forkCount>8</forkCount>
                    <reuseForks>true</reuseForks>
                </configuration>
            </plugin>
        </plugins>
    </build>
</profile>

More configuration examples can be found in our Integration tests. Enable them by activating framework-integration-tests Maven profile.

JUnit 5 Jupiter

  • Import this maven dependency.
<dependency>
    <groupId>org.fluentlenium</groupId>
    <artifactId>fluentlenium-junit-jupiter</artifactId>
    <version>4.3.1</version>
    <scope>test</scope>
</dependency>
  • Extends FluentTest.

If you need to run your tests in parallel please take a look into our Integration tests examples. Enable them by activating framework-integration-tests Maven profile.

TestNG

  • Import this maven dependency.
<dependency>
    <groupId>org.fluentlenium</groupId>
    <artifactId>fluentlenium-testng</artifactId>
    <version>4.3.1</version>
    <scope>test</scope>
</dependency>
  • Extends FluentTestNG instead of FluentTest.

If you need to make your tests run concurrently to speed them up, you should use dedicated libraries/extensions. You can use the Surefire maven plugin for example.

Surefire TestNG example

<profile>
    <id>testng-tests</id>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <suiteXmlFiles>
                        <suiteXmlFile>test-suites/basic.xml</suiteXmlFile>
                    </suiteXmlFiles>
                    <goal>test</goal>
                </configuration>
            </plugin>
        </plugins>
    </build>
</profile>

TestNG test suite file

<suite name="Parallel tests" parallel="tests" thread-count="10">
    <test name="Home Page Tests" parallel="methods" thread-count="10">
        <parameter name="test-name" value="Home page"/>
        <classes>
            <class name="com.example.testng.OurLocationTest"/>
            <class name="com.example.testng.OurStoryTest"/>
        </classes>
    </test>
    <test name="Another Home Page Tests" parallel="classes" thread-count="2">
        <parameter name="test-name" value="another home page"/>
        <classes>
            <class name="com.example.testng.HomeTest"/>
            <class name="com.example.testng.JoinUsTest"/>
        </classes>
    </test>
</suite>

TestNG gives you more flexibility in order to the concurrency level, test suites and having better control on executed scenarios.

Both test frameworks are giving possibility to define the parallelism level of tests.

It is possible when you have multiple execution/concurrency levels set in your tests to face driver sharing issues, so please use METHOD driverLifecycle configuration property when your execution methods are mixed up.

More configuration examples can be found in our Integration tests. Enable them by activating framework-integration-tests Maven profile.

Cucumber

  • Import this maven dependency.
<dependency>
    <groupId>org.fluentlenium</groupId>
    <artifactId>fluentlenium-cucumber</artifactId>
    <version>4.3.1</version>
</dependency>
  • Create runner class annotated with Cucumber.class
@RunWith(Cucumber.class)
@CucumberOptions
public class Runner {
}
  • Extend FluentCucumberTest class in all of your steps classes:
public class ExampleSteps1 extends FluentCucumberTest {
}
public class ExampleSteps2 extends FluentCucumberTest {
}

or only in your BaseTest class:

public class BaseTest extends FluentCucumberTest {
}
public class ExampleSteps1 extends BaseTest {
}
  • Add Before and After hooks:
import cucumber.api.Scenario;
import cucumber.api.java.After;
import cucumber.api.java.Before;

public class FluentHooks extends FluentCucumberTest {
    @Before
    public void beforeScenario(Scenario scenario) {
        before(scenario);
    }

    @After
    public void afterScenario(Scenario scenario) {
        after(scenario);
    }
}

When using Cucumber with Java 8 (package cucumber-java8), hooks can be added like this:

public class FluentHooks extends FluentCucumberTest {
    
    public FluentHooks(){
        Before(this::before);
        
        After(this::after);
    }
}

Notes related to Cumber hooks:

1) Hooks should be added ONCE for your tests. Do not add these these hooks in all your steps classes.

2) Adding these hooks starts FluentLenium context during execution of scenario. It means that driver will start automatically. If you want to start WebDriver only for some scenarios, you can simply add tag:

@fluent
Scenario: Driver should start when tag is present above scenario
    Then WebDriver starts as expected

and add tags to your hooks:

@Before({"@fluent"})
public void beforeScenario(Scenario scenario) {
    before(scenario);
}

@After({"@fluent"})
public void afterScenario(Scenario scenario) {
    after(scenario);
}

3) Hooks in Cucumber cannot be extended. So do not add Before and After hooks in BaseTest (if you use such pattern) but add them in any other class:

public class FluentHooks extends BaseTest {
    
    @Before
    public void beforeScenario(Scenario scenario) {
        before(scenario);
    }
    
    @After
     public void afterScenario(Scenario scenario) {
        after(scenario);
    }
}
  • It is possible to access current FluentCucumberTest context using syntax:
FluentTestContainer.FLUENT_TEST.instance()

It can be handy if you want have to access current WebDriver instance. The purpose of FluentTestContainer is to share state between many steps classes.

  • Keep your configuration in BaseTest:
 // example configuration
 @FluentConfiguration(webDriver = "chrome")
 public class BaseTest extends FluentCucumberTest {
    
    @Override
    public Capabilities getCapabilities() {
        return new ChromeOptions();
    }
 }

or class with Cucumber hooks:

  // example configuration
  @FluentConfiguration(webDriver = "chrome")
  public class FluentHooks extends FluentCucumberTest {
     
     @Override
     public Capabilities getCapabilities() {
         return new ChromeOptions();
     }
     
     @Before
     public void beforeScenario(Scenario scenario) {
         before(scenario);
     }
     
     @After
     public void afterScenario(Scenario scenario) {
         after(scenario);
     }
  }
  • At default, new instance of WebDriver is created for each scenario. If you want to run single WebDriver for all scenarios in feature, change DriverLifecycle to JVM level:
import org.fluentlenium.adapter.cucumber.FluentCucumberTest;
import org.fluentlenium.configuration.ConfigurationProperties;
import org.fluentlenium.configuration.FluentConfiguration;

@FluentConfiguration(webDriver = "chrome", driverLifecycle = ConfigurationProperties.DriverLifecycle.JVM)
public class BaseTest extends FluentCucumberTest {
}
  • Remember, that page objects still need to inherit FluentPage to run correctly.

E2E Cucumber tests are present in Cucumber example. Enable it by activating examples Maven profile.

  • After having Cucumber-jvm upgraded to 4.5.0+ support is added for both cucumber.api and io.cucumber based classes like (@Given, @When, @CucumberOptions, etc.), however the FluentCucumberTest based tests will still use the old Cucumber ObjectFactory due to the Cucumber limitation of allowing only one instance of ObjectFactory to be used, and also to provide backward compatibility for projects where Cucumber version cannot be upgraded.

Spock

  • Import this maven dependency.
<dependency>
    <groupId>org.fluentlenium</groupId>
    <artifactId>fluentlenium-spock</artifactId>
    <version>4.3.1</version>
    <scope>test</scope>
</dependency>
  • Extends FluentSpecification instead of FluentTest.

E2E Spock test are present in Spock example. Enable it by activating examples Maven profile.

Standalone mode

If you want to use FluentLenium as a pure automation Framework, without any testing framework adapter, you can create an instance of FluentStandalone and use it directly, or extend FluentStandaloneRunnable and implement doRun() method.

FluentStandalone

Create an instance of FluentStandalone and use it directly. You have to manually invoke init() to initialize the WebDriver, and quit() to close it.

FluentStandalone standalone = new FluentStandalone()
standalone.init();

standalone.goTo(DEFAULT_URL);
standalone.await().atMost(1, SECONDS).until(test.$(".fluent", with("name").equalTo("name"))).present();
standalone.el("input").enabled();

standalone.quit();

Using a FluentStandalone instance is quite verbose because of the need to repeat the instance name before each instruction. If it’s a problem for you, you should consider extending FluentStandaloneRunnable.

FluentStandaloneRunnable

Another option is to extend FluentStandaloneRunnable, implement doRun() method and invoke run() method on an instance of this class. Fluent WebDriver is initialized before and released after run() method invocation.

public class MyStandaloneRunnable extends FluentStandaloneRunnable {
    @Override
    protected void doRun() {
        goTo(DEFAULT_URL);
        await().atMost(1, SECONDS).until(test.$(".fluent", with("name").equalTo("name"))).present();
        el("input").enabled();
    }
}
MyStandaloneRunnable runnable = new MyStandaloneRunnable();
runnable.run();