Gradle – Extent Report Version 5 for Cucumber, Selenium, and TestNG

HOME

The previous tutorial explained the generation of Extent Reports Version 5 for Cucumber 7 and TestNG in a Maven project. In this tutorial, I will explain the steps to create an Extent Report Version 5 for Cucumber, Selenium, and TestNG in a Gradle project.

Prerequisite

  1. Java 8 or above installed
  2. Eclipse or IntelliJ IDE installed
  3. Gradle Installed
  4. Environment variables JAVA_HOME and GRADLE_HOME are correctly configured

In this tutorial, I’ll create a BDD Framework for the testing of web applications using Cucumber, and Selenium WebDriver with TestNG.

  1. Cucumber Java- 7.6.0
  2. Cucumber JUnit– 7.6.0
  3. Java 11
  4. TestNG – 7.6.0
  5. Gradle – 7.5.1
  6. Selenium – 4.3.0
  7. ExtentReport – 5.0.9
  8. GrassHopper Cucumber Adapter – 1.7.0

Implementation Steps

There is a tutorial that explains the Integration of Cucumber, Selenium, and TestNG in a Gradle project. Please refer to this tutorial – Gradle Project with Cucumber, Selenium and TestNG.

Step 1 – Add Extent Report dependency to the build.gradle

To create an Extent Report, we need to add the below-mentioned dependency in the build.gradle

implementation 'tech.grasshopper:extentreports-cucumber7-adapter:1.7.0'
implementation 'com.aventstack:extentreports:5.0.9'  

Step 2 – Add ExtentCucumberAdapter plugin to task cucumber

task cucumber() {
    dependsOn assemble, compileTestJava
    doLast {
        javaexec {         
            main = "io.cucumber.core.cli.Main"
            classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
            args = ['--plugin', 'pretty', 
            '--plugin', 'io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm',
            '--plugin', 'com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:',
            '--glue', 'com.example.definitions', 'src/test/resources']
        }
    }
}

Step 3 – Add Cucumber, Selenium, and TestNG dependencies in build.gradle

dependencies {

    testImplementation 'io.cucumber:cucumber-java:7.6.0'
    testImplementation 'io.cucumber:cucumber-junit:7.6.0'
    
     //TestNG  
     testImplementation 'org.testng:testng:7.6.0'
    
    //ExtentReport    
    implementation 'tech.grasshopper:extentreports-cucumber7-adapter:1.7.0'
    implementation 'com.aventstack:extentreports:5.0.9' 

    // This dependency is used by the application.
    implementation 'com.google.guava:guava:30.1.1-jre'
    implementation 'org.seleniumhq.selenium:selenium-java:4.4.0'
    implementation 'io.github.bonigarcia:webdrivermanager:5.3.0'
}

The complete build.gradle is shown below:

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'application'
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

java {
    sourceCompatibility = 11
    targetCompatibility = 11
}

dependencies {
   
    // Use TestNG framework, also requires calling test.useTestNG() below
    testImplementation 'io.cucumber:cucumber-java:7.6.0'
    testImplementation 'io.cucumber:cucumber-testng:7.6.0'
             
    //TestNG  
     testImplementation 'org.testng:testng:7.6.0'
      
    //ExtentReport    
     implementation 'tech.grasshopper:extentreports-cucumber7-adapter:1.7.0'
     implementation 'com.aventstack:extentreports:5.0.9'  
      
     //Others  
     implementation 'com.google.guava:guava:31.0.1-jre'
     implementation 'org.seleniumhq.selenium:selenium-java:4.4.0'
     implementation 'io.github.bonigarcia:webdrivermanager:5.3.0'

}

application {
    // Define the main class for the application.
    mainClass = 'com.example.App'
}

tasks.named('test') {
    // Use TestNG for unit tests.
    useTestNG()
}

configurations {
    cucumberRuntime {
        extendsFrom testImplementation
    }
}

task cucumber() {
    dependsOn assemble, compileTestJava
    doLast {
        javaexec {         
            main = "io.cucumber.core.cli.Main"
            classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
            args = ['--plugin', 'pretty', 
            '--plugin', 'io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm',
            '--plugin', 'com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:',
            '--glue', 'com.example.definitions', 'src/test/resources']
        }
    }
}

Step 4 – Create Locator and Action classes and Step Definition corresponding to the feature file

As mentioned above, there is another tutorial that explains the project structure as well as the feature file and corresponding Step Definitions, please refer to this tutorial – Gradle Project with Cucumber, Selenium, and TestNG.

Step 5 – Create extent.properties file in the resources folder and paste the below code

#Extent Report
extent.reporter.spark.start=true
extent.reporter.spark.out=Reports/Spark.html
 
#PDF Report
extent.reporter.pdf.start=true
extent.reporter.pdf.out=PdfReport/ExtentPdf.pdf
 
#HTML Report
extent.reporter.html.start=true
extent.reporter.html.out=HtmlReport/ExtentHtml.html
 
#FolderName
basefolder.name=ExtentReports/SparkReport_
basefolder.datetimepattern=d_MMM_YY HH_mm_ss
 
#Screenshot
screenshot.dir=/Screenshots/
screenshot.rel.path=../Screenshots/
 
#Base64
extent.reporter.spark.base64imagesrc=true
 
#System Info
systeminfo.os=windows
systeminfo.version=10

Step 6 – Execute the Tests

Go to the app project and run the tests, using the below command

gradle cucumber

The output of the above program is

Step 7 – View the ExtentReports

Refresh the project and will see a new folder – SparkReport_ which further contains 4 folders -Html Report, Pdf Report, Reports, and Screenshots.

The Extent Report will be present in the Report’s folder with the name Spark.html. PDF Report is present in the Pdf Report folder and HTML Report is present in the HTML report folder. We can see that the Screenshot’s folder is empty because we have used the base64imagesrc feature, which resulted in no physical screenshots. The screenshots are embedded in the reports.

Right-click and open the ExtentHtml.html report with the Web Browser. The report also has a summary section that displays the summary of the execution. The summary includes the overview of the pass/fail using a pictogram, start time, end time, and pass/fail details of features as shown in the image below.

ExtentHtml.html

The failed test has a screenshot embedded in it. Double-click on mase64image, and it will open the screenshot in full screen.

Screenshot of failed Test Case

PDF Report

To know more about PDF Report generation, please refer to this tutorial – PDF ExtentReport for Cucumber and TestNG.

Spark Report

Right-click and open the Spark.html report with the Web Browser.

Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!

Selenium 4 Grid – Parallel Testing

HOME

The previous tutorial explained running the tests in Selenium4 Grid using the Standalone option. One of the major advantages of Selenium Grid is the ability to run tests parallelly on multiple browsers simultaneously. Parallel testing helps to reduce execution time and efforts and results in a faster time to delivery.

In this tutorial, we will run the same set of tests on Chrome, Firefox, and Edge browsers sequentially initially to confirm that we can perform Cross Browser testing also.

It is very important to construct our tests thread-safe in order to run them in parallel without a problem

This example uses Selenium 4 with TestNG.

Implementation Steps

1. Download Selenium Grid 4

The latest version of Selenium 4 is 4.3.0 and the same can be downloaded from the official website of Selenium

2. Download various Browser driver exe

It is recommended to download the exe of various browsers in the same location where the Selenium WebDriver jar file is present. This is because Selenium 4 Alpha has the ability to automatically detect the WebDrivers present on the node machine. For this example, I have downloaded Chrome, Firefox, and edge drivers.

3. Start Selenium Server Jar

Open a command line terminal. Go to the location where these files are present

cd C:/Users/Vibha/Software/SeleniumGrid

Use the below command to run selenium-server standalone jar files.

java -jar selenium-server-4.3.0.jar standalone --port 4445

It’s optional to mention the port number at the end of the command. By default, it will use port 4444. It is good practice to mention the port at the end to avoid any conflict between the ports.

4. Open Selenium Console

The server is listening on http://172.30.96.1:4445/ui/index.html  which is the same as shown in the above image. This is a dynamic address, so make sure to get the address from the logs when Selenium Grid is started.

The Grid automatically identifies that the WebDrivers for Chrome and Firefox are present on the system.

5. Add dependencies to the project

In this example, we are using a Maven project, so are adding the dependencies to the POM.xml.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>Selenium4Parallel</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>

        <!-- Selenium 4 Dependency -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.1.2</version>
        </dependency>

        <!-- Selenium WebDriver Manager -->
        <dependency>
            <groupId>io.github.bonigarcia</groupId>
            <artifactId>webdrivermanager</artifactId>
            <version>5.1.0</version>
        </dependency>

        <!-- TestNG Dependency -->
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>7.4.0</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

</project>

6. Create a Test Code

Creating an instance of the Remote WebDriver and passing the selenium endpoint and chrome options defined in it.

To run a Remote WebDriver client, we first need to connect to the RemoteWebDriver. We do this by pointing the URL to the address of the server running our tests. In order to customize our configuration, we set desired capabilities.

Below is an example of instantiating a remote WebDriver object pointing to our remote web server running our tests on Chrome, Firefox, and Edge. We have used @Parameters Annotation to pass the browser names to the tests.

import org.openqa.selenium.By;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Parameters;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.Duration;

public class BaseTest {


    protected static ThreadLocal<RemoteWebDriver> driver = new ThreadLocal<RemoteWebDriver>();
    public static String remote_url = "http://localhost:4445/";
    public Capabilities capabilities;

    @Parameters({"browser"})
    @BeforeMethod
    public void setDriver(String browser) throws MalformedURLException {
    	
    	System.out.println("Test is running on "+browser);

        if(browser.equals("firefox")) {
            capabilities = new FirefoxOptions();
        } else if (browser.equals("chrome")) {
            capabilities = new ChromeOptions();
        } else if (browser.equals("edge")) {
        	capabilities = new EdgeOptions();
        }

        driver.set(new RemoteWebDriver(new URL(remote_url), capabilities));
        driver.get().get("https://opensource-demo.orangehrmlive.com/");
        driver.get().manage().window().maximize();
        driver.get().manage().timeouts().pageLoadTimeout(Duration.ofSeconds(10));
        WebDriverWait wait = new WebDriverWait(driver.get(), Duration.ofSeconds(10));
        wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[@id='divUsername']/span")));
    }

    public WebDriver getDriver() {
        return driver.get();
    }

    @AfterMethod
    public  void closeBrowser() {
        driver.get().quit();
        driver.remove();
    }
}

Selenium4ParallelDemo

This class contains the various tests that need to be executed.

  • In BaseTest class, I created ThreadLocal <>() webdriver (ThreadLocalMap) for thread-safe test execution
  • I got the TestNG parameter (browser) with @Parameter annotation.
  • BaseTest returns browser Capabilities based on browser name.
  • In BaseTest class, the getDriver() method returns the created driver.
  • Selenium4ParallelDemo class extends TestBase class and comprises their test code.

import org.openqa.selenium.By;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;

public class Selenium4ParallelDemo extends BaseTest {

    @Test
    public void validCredentials()  {

        getDriver().findElement(By.xpath("//*[@id='txtUsername']")).sendKeys("Admin");
        getDriver().findElement(By.xpath("//*[@id='txtPassword']")).sendKeys("admin123");
        getDriver().findElement(By.xpath("//*[@id='btnLogin']")).click();
        String newPageText = getDriver().findElement(By.xpath("//*[@id='content']/div/div[1]/h1")).getText();
        System.out.println("newPageText :" + newPageText);
        assertEquals(newPageText,"Dashboard");

    }

    @Test
    public void invalidCredentials() {
    	
        getDriver().findElement(By.xpath("//*[@id='txtUsername']")).sendKeys("1234");
        getDriver().findElement(By.xpath("//*[@id='txtPassword']")).sendKeys("12342");
        getDriver().findElement(By.xpath("//*[@id='btnLogin']")).click();
        String actualErrorMessage = getDriver().findElement(By.xpath("//*[@id='spanMessage']")).getText();
        System.out.println("Actual ErrorMessage :" + actualErrorMessage);
        assertEquals(actualErrorMessage,"Invalid credentials");

    }

    @Test
    public void loginPageHeading() {

        String loginText = getDriver().findElement(By.xpath("//*[@id='logInPanelHeading']")).getText();
        System.out.println("Actual loginText :" + loginText);
        assertEquals(loginText,"LOGIN Panel");

    }

    @Test
    public void forgotPasswordPageHeading()  {

        getDriver().findElement(By.xpath("//*[@id='forgotPasswordLink']/a")).click();
        String forgetPasswordTitle= getDriver().findElement(By.xpath(" //*[@id='content']/div[1]/div[2]/h1")).getText();
        System.out.println("Actual Page Title of Forgot Password Page :" + forgetPasswordTitle);
        assertEquals(forgetPasswordTitle,"Forgot Your Password?");
    }

    @Test
    public void verifyLinkedIn() {

        Boolean linkedInIcon = getDriver().findElement(By.xpath("//*[@id='social-icons']/a[1]/img")).isEnabled();
        System.out.println("Actual linkedIn Text :" + linkedInIcon);
        assertTrue(linkedInIcon);

    }
}

7. Create a testng.xml

It is very easy to create testng.xml in the case of Eclipse. Right-click on the project, and select TestNG -> Convert to TestNG. It will create a basic testng.xml structure. We need to add the parameter name and value to it.

We are planning to run the test on 3 different browsers, so we are passing the name of the browser from this testng.xml using the parameter. This testng.xml will run the test sequentially. There is a minor change needs to be done in testng.xml that will run the tests parallelly.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">

<suite name="Suite">
  <test thread-count="5" name="Chrome Test">
    <parameter name ="browser" value="chrome"/>
    <classes>
      <class name="org.example.Selenium4ParallelDemo"/>
    </classes>
  </test> <!-- Test -->
  
   <test thread-count="5" name="Firefox Test">
    <parameter name ="browser" value="firefox"/>
    <classes>
      <class name="org.example.Selenium4ParallelDemo"/>
    </classes>
  </test> <!-- Test -->
  
   <test thread-count="5" name="Edge Test">
    <parameter name ="browser" value="edge"/>
    <classes>
      <class name="org.example.Selenium4ParallelDemo"/>
    </classes>
  </test> <!-- Test -->
</suite> <!-- Suite -->

8. Run the tests from testng.xml

Right-Click on the testng.xml and select Run As ->TestNG Suite.

9. Navigate to the sessions tab on the Selenium Grid UI upon running the command

It would reflect an active session.

10. Review the test execution result

There are 2 ways to see if the tests are getting executed or not. First, we can check in the command line. We can see the logs there as shown below.

The complete test execution result can be found in the console too.

The tests are TestNG ones, so we can also check the Result of Running Suite tab also.

11. TestNG Report Generation

TestNG generates the test reports in the test-output folder.

We are interested in 2 reports – index.html and emailable-report.html.

Index.html

The below image shows that the tests are run sequentially.

Emailable-Report.html

This report is the summary report. It contains the summary of all the tests executed like, the number of tests passed, skipped, retried, and failed, and the execution time taken by each test.

Parallel Testing

Update the testng.xml for parallel testing. Add parallel=”tests” in the XML.

Updated testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">

<suite name="Suite" parallel="tests">
  <test thread-count="5" name="Chrome Test">
    <parameter name ="browser" value="chrome"/>
    <classes>
      <class name="org.example.Selenium4ParallelDemo"/>
    </classes>
  </test> <!-- Test -->
  
   <test thread-count="5" name="Firefox Test">
    <parameter name ="browser" value="firefox"/>
    <classes>
      <class name="org.example.Selenium4ParallelDemo"/>
    </classes>
  </test> <!-- Test -->
  
   <test thread-count="5" name="Edge Test">
    <parameter name ="browser" value="edge"/>
    <classes>
      <class name="org.example.Selenium4ParallelDemo"/>
    </classes>
  </test> <!-- Test -->
</suite> <!-- Suite -->

The below image shows that the tests were running on multiple browsers at the same time.

The console also shows that tests were started on all three browsers at the same time.

Index.html shows that methods run in chronological order. It can be seen that the setDriver() method for all 3 browsers was the first one to be executed.

Best Practices:

  1. It is advisable to use nodes other than 4444 to run the tests. By using the different port numbers, we prevent the risk that the port is already in use on your system.
  2. It is suggested to use RemoteWebDriver objects, as it is used to set which node (or machine) our test will run against.

Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!

Run Selenium Tests in GitLab CI/CD

Last Updated on

HOME

This tutorial explains the process to run the Selenium Tests in the GitLab pipeline. This is a very important step towards achieving CI/CD. Ideally, the tests need to run after any change (minor/major) before merging the latest change to the master branch. Suppose there are 100 changes merged to the master branch in a day. It is expected to run the tests every time before deployment. In this case, any QA won’t want to start the tests manually 100 times in a day. Now, what should be done to overcome this problem. Now, adding tests to the GitLab pipeline comes into the picture. We can add a test stage to the pipeline and the tests will run automatically when the pipeline run.

Table of Contents

  1. Prerequisite
  2. What is GitLab CI/CD Workflow?
  3. What is a headless browser?
  4. Implementation Steps
    1. Create a new Maven Project
    2. Add the dependencies to the POM.xml
    3. Create the Test Code
    4. Create testng.xml to run the tests
    5. Run the tests through command line
  5. GitLab Section
    1. Create a blank project in GitLab
    2. Push the project from local repository to Gitlab Repository
    3. Create a .gitlab-ci.yml file in the project in GitLab
    4. Run the tests in the GitLab pipeline
    5. Check the status of the pipeline
    6. Download the report

Prerequisite

  1. Selenium
  2. TestNG/JUnit (for Assertions)
  3. Java 11
  4. Maven/ Gradle
  5. GitLab Account

What is GitLab CI/CD Workflow?

Build the proposed changes. Then, push the commits to a feature branch. This branch should be in a remote repository that’s hosted in GitLab. The push triggers the CI/CD pipeline for your project. Then, GitLab CI/CD runs automated scripts (sequentially or in parallel) to build as well as to test the application. After a successful run of the test scripts, GitLab CI/CD deploys your changes automatically to any environment (DEV/QA/UAT/PROD). But if the test stage is failed in the pipeline, then the deployment is stopped.

After the implementation works as expected:

  • Get the code reviewed and approved.
  • Merge the feature branch into the default branch.
    • GitLab CI/CD deploys your changes automatically to a production environment.

To use GitLab CI/CD, we need to keep 2 things in mind:

a) Make sure a runner is available in GitLab to run the jobs. If there is no runner, install GitLab Runner and register a runner for your instance, project, or group.

b) Create a .gitlab-ci.yml file at the root of the repository. This file is where CI/CD jobs are defined.

The Selenium tests run on a headless browser in the pipeline.

What is a headless browser?

A headless browser is like any other browser, but without a Head/GUI (Graphical User Interface).  A headless browser is used to automate the browser without launching the browser. While the tests are running, we cannot see the browser. However, we can see the test results coming on the console.

To explain, I have created 2 Selenium tests and used TestNG for asserting the tests. The tests will run on a headless Chrome browser. One more thing to keep in mind is that when tests run on a headless Chrome browser, the window screen won’t be full screen. So, the screen needs to be maximized explicitly otherwise some of the tests would fail.

Implementation Steps

Step 1 – Create a new Maven Project

Step 2- Add the dependencies to the POM.xml

Add the below-mentioned dependencies that need to add to the project to the pom.xml in Maven Project.

 <dependencies>

        <dependency>
            <groupId>io.github.bonigarcia</groupId>
            <artifactId>webdrivermanager</artifactId>
            <version>5.1.0</version>
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.141.59</version>
        </dependency>

        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>7.5</version>
            <scope>test</scope>
        </dependency>
                   
    </dependencies>
    <build>
     <plugins>
     
     <!--  Compiler Plugin -->
    
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
           <source>11</source>
           <target>11</target>
        </configuration>
    </plugin>
     
      <!--  Plugin used to execute tests -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>3.0.0-M5</version>
        <configuration>
          <suiteXmlFiles>
            <suiteXmlFile>testng.xml</suiteXmlFile>
          </suiteXmlFiles>
        </configuration>
      </plugin>
     </plugins>
  </build>
</project>

As explained in one of the previous tutorial, it is needed to add the maven-surefire-plugin to run the TestNG tests through the command line.

Step 3 – Create the Test Code

This is the BaseTest Class. The WebDriver is initialized here. It operates in headless mode and full screen. At the end, the WebDriver is closed.

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;

import io.github.bonigarcia.wdm.WebDriverManager;

public class BaseTest {
	
	WebDriver driver;
	
	@BeforeMethod
	public void beforeTests() {
        WebDriverManager.chromedriver().setup();
        ChromeOptions options=new ChromeOptions();
        options.setHeadless(true);
        options.addArguments("window-size=1920,1200");
        driver=new ChromeDriver(options);
        driver.get("https://opensource-demo.orangehrmlive.com/");
    }

	@AfterMethod
    public void afterTests() {
        driver.quit();
    }

}

There are 2 different pages that need to be tested – LoginPage and ForgetPasswordPage

LoginPage contains the tests to log in to the application. After successful login, the application moves to the next webpage – HomePage. You can see that BaseTest class is extended in both the Test classes.

import org.openqa.selenium.By;
import org.testng.Assert;
import org.testng.annotations.Test;

@Test
public class LoginPage extends BaseTest{
	
	@Test
	public void validCredentials() throws InterruptedException {

	        driver.findElement(By.name("txtUsername")).sendKeys("Admin");	        
	        driver.findElement(By.name("txtPassword")).sendKeys("admin123");
	        driver.findElement(By.id("btnLogin")).click();
	         String newPageText = driver.findElement(By.xpath("//*[@id='content']/div/div[1]/h1")).getText();
	        System.out.println("newPageText :" + newPageText);
	        Assert.assertEquals(newPageText,"Dashboard");

	}

}

ForgetPasswordPage

import org.openqa.selenium.By;
import org.testng.Assert;
import org.testng.annotations.Test;

@Test
public class ForgetPasswordPage extends BaseTest{
	
	@Test
	public void getHeading() {
		
		Thread.sleep(1000);
		driver.findElement(By.xpath("//*[@id='forgotPasswordLink']/a")).click();
		String heading = driver.findElement(By.xpath("//*[@id='content']/div[1]/div[2]/h1")).getText();
		System.out.println("Title : "+ heading );
		Assert.assertEquals(heading, "Forgot Your Password?");
	}
	
}

Step 4 – Create testng.xml to run the tests

Now, let’s create a testng.xml to run the TestNG tests. If JUnit is used instead of TestNG, then this step is not needed.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite">
  <test name="Test">
    <classes>
      <class name="org.example.DockerDemo.LoginPage"/>
      <class name="org.example.DockerDemo.ForgetPasswordPage"/>
    </classes>
  </test> <!-- Test -->
</suite> <!-- Suite -->

Step 5 – Run the tests through command line

Now, let us execute the tests through the command line. Go to the place where the pom.xml of the project is placed and use the below command to run the tests. This step makes sure that all the tests are running as expected.

mvn compile test

GitLab Section

Step 6 – Create a blank project in GitLab

To know, how to create a blank new project in GitLab, please refer to this tutorial.

Step 7 – Push the project from local repository to Gitlab Repository

To know, how to push the changes in GitLab, please refer to this tutorial.

Step 8 – Create a .gitlab-ci.yml file in the project in GitLab

There are many ways to create a new file in GitLab. One of the ways is to create a file as shown in the below image.

It is a YAML file where you configure specific instructions for GitLab CI/CD. In the .gitlab-ci.yml, we can define:

  • The scripts you want to run.
  • Other configuration files and templates you want to include.
  • Dependencies and caches.
  • The commands you want to run in sequence and those you want to run in parallel.
  • The location to deploy your application to.
  • Whether you want to run the scripts automatically or trigger any of them manually.
image: markhobson/maven-chrome

stages:
  - test

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"

test:
  stage: test
  allow_failure: true

# Run the tests  
  script:
    - mvn $MAVEN_OPTS clean package
    - mvn compile test

# Store artifacts
  artifacts:
    when: always
    name: "report"
    paths:
    - target/surefire-reports/*
    expire_in: 1 h

Image – markhobson/maven-chrome is used in this test. It is a docker image for Java automated UI tests.

This gitlab-ci.yml has only 1 stage. It is a test stage that contains the command to run the tests. It also creates an artifact that contains all the surefire reports. These reports can be saved as Test Evidence.

Step 9 – Run the tests in the GitLab pipeline

Now, when a new change is committed, a pipeline kicks off and it runs all the tests.

Step 10 – Check the status of the pipeline

Once the Status of the pipeline changes to either failed or passed.. that means the tests are already executed.

As you can see the Status is failed here which means that the execution is completed. Let us see the logs of the execution it shows that out of 2 tests, 1 test passed and 1 test failed. This shows that tests are running successfully in the GitLab pipeline.

As I have added an artifact also in the gitalb-ci.yml, which is highlighted in the image. This artifact creates a folder with the name “report” and the reports in this folder come from the path /target/surefire-reports. This artifact gives us the option to download the reports or browse the report. This report will be available for 1 hour only as mentioned in the gitlab-ci.yml.

Step 11 – Download the report

Once, will click on the download button, it will download “report.zip”. Unzip the folder and it looks like something as shown below:

Example of Emailable-Report.html

Example of Index.html

Congratulations. This tutorial has explained the steps to run Selenium tests in GitLab CI/CD. Happy Learning!!

How to disable infobar warning for Chrome tests in Selenium

Last Updated On

HOME

This tutorial explains the steps to disable infobar warning generated by Selenium for running tests in Chrome. Selenium tests run on Chrome shows a warning message – Chrome is being controlled by automated test software as shown in the below image.

We want to run the Selenium tests on Chrome, but without the above-shown warning message. This can be achieved by using excludeSwitches.

chromeOptions.setExperimentalOption("excludeSwitches", Arrays.asList("enable-automation"));

The complete program is shown below:

import java.util.Arrays;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import io.github.bonigarcia.wdm.WebDriverManager;

public class ChromeDisableInfobars {

	public static void main(String[] args) {

		WebDriverManager.chromedriver().setup();

		// Create an object of Chrome Options class
		ChromeOptions chromeOptions = new ChromeOptions();

		// prevents Chrome from displaying the notification 'Chrome is being controlled
		// by automated software'
        options.addArguments("--disable-infobars");
		chromeOptions.setExperimentalOption("excludeSwitches", Arrays.asList("enable-automation"));

		// Create an object of WebDriver class and pass the Chrome Options object as an
		// argument
		WebDriver driver = new ChromeDriver(chromeOptions);

		driver.get("https://duckduckgo.com/");

		System.out.println("Title of Page :" + driver.getTitle());

		// close the browser
		driver.quit();

	}
}

The output of the above program is

We are done. Congratulations!! Happy Learning.

Parallel testing of DataProviders in TestNG

HOME

The previous tutorial has explained the DataProviders in TestNG. The DataProvider in TestNG is a way to pass the parameters in the test functions. Using DataProvider in TestNG, we can easily inject multiple values into the same test case. It comes inbuilt into TestNG and is popularly used in data-driven frameworks.

 It is an option for the parallel execution of tests in TestNG. 

It is advisable to create 2 classes – one class contains the Test cases and another class defines TestNG parameters – DataProviders.

Let us create a class for the DataProvider method with all the Test Data as shown below:

import org.testng.annotations.DataProvider;

public class DataProviderDemo {	
	
	 @DataProvider(name = "testData", parallel=true)
	 public Object[][] dataProvFunc() {
	       return new Object[][] {           
	    	   {"","","Username cannot be empty"},    	  
	    	   {"","Test","Username cannot be empty"},
	    	   {"$%1234","2345%$","Invalid credentials"}          
	    	 };
	    }
	}

An extra parameter “parallel” is required to initiate parallel execution in TestNG using the data provider.

Below is the test which uses the parameter from the data provider and runs the tests parallelly.

A new ThreadLocal is instantiated for each test class, since it’s in the BeforeClass annotation.

private static final ThreadLocal<WebDriver> WEB_DRIVER_THREAD_LOCAL = new ThreadLocal<WebDriver>();

Below is the complete test code:

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class DataProviderParallelTests {
	
	public WebDriver driver;
	private static final ThreadLocal<WebDriver> WEBDRIVER_THREADLOCAL = new ThreadLocal<WebDriver>();
	
	 @BeforeMethod
    public void setUp(){

        System.setProperty("webdriver.chrome.driver",
                "C:\\Users\\Vibha\\Software\\chromedriver\\chromedriver.exe");
        driver = new ChromeDriver();
        WEBDRIVER_THREADLOCAL.set(driver);
        System.out.println("Before method Thread Id:" + Thread.currentThread().getId());
        
    }
	
	@Test(dataProvider = "testData", dataProviderClass = DataProviderDemo.class)
    public void invalidLoginTest(String username, String password, String errorMessage) throws InterruptedException {
		     
	    driver = WEBDRIVER_THREADLOCAL.get();
	    driver.manage().window().maximize();
        driver.get("https://opensource-demo.orangehrmlive.com/");
     
        Thread.sleep(2000);
        driver.findElement(By.name("txtUsername")).sendKeys(username);
        System.out.println("Username :" + username);
        
        Thread.sleep(2000);
        driver.findElement(By.name("txtPassword")).sendKeys(password);
        System.out.println("password :" + password);
        
        Thread.sleep(2000);
        String expectedError = driver.findElement(By.id("spanMessage")).getText();
        System.out.println("Error Message :" + expectedError);
        Assert.assertTrue(expectedError.contains(errorMessage));

    }
		 
	@AfterMethod
	public void tear_down() {
		 
		 WebDriver driver = WEBDRIVER_THREADLOCAL.get();
		 System.out.println("After method Thread Id:" + Thread.currentThread().getId());
	        if (driver != null) {
	            driver.quit();
	     }
    }	
}

testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite" thread-count="2" data-provider-thread-count="2">
  <test name="Test">
    <classes>
      <class name="DataProvider.DataProviderParallelTests"/>
    </classes>
  </test> <!-- Test -->
</suite> <!-- Suite -->

In this file, the data-provider-thread-count is set to 2, then two browsers will be opened, and the first two tests will run from the list. 

Run the test script from testng.xml, Right-Click on the XML, and select Run As ->TestNG Suite.

The execution status shown below shows that 2 threads are active at a time, which execute 2 sets of data provider parameters – Thread 14 and Thread 15. Once the tests are finished for Thread 14 and Thread 15, they are closed and a new Thread 15 is again initiated to start the test execution of the 3rd parameter.

TestNG generates multiple test reports under the folder test-output. We are mainly concerned about 2 reports – emailable-report.html and index.html.

Emailable-report.html

Emailable reports are a type of summary report that one can transfer to other people in the team through any medium. 

Index.html

Index report contains the index-like structure of different parts of the report, such as failed tests, test files, passed tests, etc. We can divide this report into two parts. The left part contains the index, and this is the reason it is called an index report, while the right part contains the explored content of that index.

We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!

How to run Selenium Tests on Internet Explorer

HOME

Internet Explorer is going away in near future. But still it is a browser which holds around 1% of browser market share. When anyone refers to automated browser testing, it somehow means that the testing will be performed on the latest browsers like Chrome, Firefox, etc. But along with these browsers, it is also expected to work on Internet Explorer (IE).

The Internet Explorer driver that is used by Selenium Tests can be downloaded from here.

In order to run the Selenium Tests on IE, it is needed to set the %PATH%.

How to add %PATH%

Go To -> View Advanced System Settings -> Environment Variables ->Clicks on the Path and add the path where IE binary is located on the machine.

How to run tests using Selenium IE driver in Selenium Java?

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;

public class IEDemo {

	public WebDriver driver;

	@Before
	public void setUp() {

		System.setProperty("webdriver.ie.driver",
				"C:\\Users\\Vibha\\Software\\IEDriverServer_x64_2.39.0\\IEDriverServer.exe");

		driver = new InternetExplorerDriver();
	}

	@Test
	public void verifyPageTitle() {

		System.out.println("Opening Internet Explorer Web Browser");
		driver.get("https://www.bing.com/");
		System.out.println("Title of Page : " + driver.getTitle());
		Assert.assertEquals(driver.getTitle(), "Bing");
	}

	@Test
	public void verifyPageUrl() {

		System.out.println("Opening Internet Explorer Web Browser");
		driver.get("https://www.bing.com/");
		System.out.println("URL of Page : " + driver.getCurrentUrl());
		Assert.assertEquals(driver.getCurrentUrl(), "https://www.bing.com/");
	}

	@After
	public void tearDown() {

		// Close the driver
		driver.close();

	}
}

Execution

The string webdriver.ie.driver is set to the location which contains the Selenium IE driver. The InternetExplorerDriver method is used for instantiating the IE driver class.

The test method is implemented under the @Test annotation.

 In the tearDown method, the resources held by IE driver are freed using the close() method in Selenium.

Congratulations!! We are able to open an Internet Explorer browser and perform tests. Happy Learning!!

Serenity BDD with Gradle and Cucumber for Web Application

HOME

In the previous tutorial, I have explained about Integration Testing of SpringBoot Application with Serenity BDD and Cucumber in Maven project. This tutorial describes the creation of the Gradle Java Project to test a web application using Cucumber6 and JUnit4.

In this tutorial, I will explain creating a framework for the testing of Web Applications in Cucumber BDD.

Pre-Requisite

  1. Java 11 installed
  2. Gradle installed
  3. Eclipse or IntelliJ installed

This framework consists of:

  1. Serenity – 2.6.0
  2. Serenity Cucumber – 2.6.0
  3. Java 11
  4. JUnit – 4.13.2
  5. Gradle – 7.2

Steps to setup Gradle Java Project for Web Application using Serenity, Cucumber6 and JUnit4

  1. Download and Install Java on the system
  2. Download and setup Eclipse IDE on the system
  3. Setup Gradle on System and create a new Gradle Project
  4. Update repositories, plugins, and dependencies to the Gradle project
  5. Create a feature file under src/test/resources
  6. Create the Step Definition class or Glue Code for the Test Scenario
  7. Create a Serenity Cucumber Runner class
  8. Create serenity.conf file under src/test/resources
  9. Create serenity.properties file at the root of the project
  10. Run the tests through commandline which generates Serenity Report

Step 1- Download and Install Java

Cucumber and Rest-Assured need Java to be installed on the system to run the tests. Click here to know How to install Java.

Step 2 – Download and setup Eclipse IDE on system

The Eclipse IDE (integrated development environment) provides strong support for Java developers. Click here to know How to install Eclipse.

Step 3 – Setup Gradle

To build a test framework, we need to add several dependencies to the project. This can be achieved by any build Tool. I have used Gradle Build Tool. Click here to know How to install Gradle. Click here to know How to create a Gradle Java project. Below is the structure of the Gradle project.

Step 4 – Update repositories, plugin, and dependencies to the Gradle project

defaultTasks 'clean', 'test', 'aggregate'

repositories {
    mavenLocal()
    jcenter()
}

buildscript {
    repositories {
        mavenLocal()
        jcenter()
    }
    dependencies {
        classpath("net.serenity-bdd:serenity-gradle-plugin:2.4.24")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'net.serenity-bdd.aggregator'

sourceCompatibility = 11
targetCompatibility = 11

dependencies {
   
    testImplementation 'net.serenity-bdd:serenity-core:2.6.0'
    testImplementation 'net.serenity-bdd:serenity-cucumber6:2.6.0'
    testImplementation 'net.serenity-bdd:serenity-screenplay:2.6.0'
    testImplementation 'net.serenity-bdd:serenity-screenplay-webdriver:2.6.0'
    testImplementation 'junit:junit:4.13.1'
}

test {
    testLogging.showStandardStreams = true
    systemProperties System.getProperties()
}

gradle.startParameter.continueOnFailure = true

test.finalizedBy(aggregate)

Step 5 – Create a feature file under src/test/resources

A Feature File is an entry point to the Cucumber tests. This is a file where you will describe your tests in Descriptive language (Like English). A feature file can contain a scenario or can contain many scenarios in a single feature file. Below is an example of Feature file.

Feature: Login to HRM  

   @ValidCredentials
   Scenario: Login with valid credentials
   
    Given User is on Home page
    When User enters username as "Admin"
    And User enters password as "admin123"
    Then User should be able to login successfully

Step 6 – Create the Step Definition class or Glue Code for the Test Scenario

The steps definition file stores the mapping between each step of the test scenario defined in the feature file with a code of the function to be executed. So, now when Cucumber executes a step of the scenario mentioned in the feature file, it scans the step definition file and figures out which function is to be called.

Create a StepDefinition class for LoginPage.feature

public class LoginPageDefinitions {
 
    @Steps
    StepLoginPage loginPage;
 
    @Steps
    StepDashboardPage dashPage;
 
    @Steps
    StepForgetPasswordPage forgetpasswordPage;
 
    @Given("User is on Home page")
    public void openApplication() {
        loginPage.open();
        System.out.println("Page is opened");
    }
 
    @When("User enters username as {string}")
    public void enterUsername(String userName) {
        System.out.println("Enter Username");
        loginPage.inputUserName(userName);
    }
 
    @When("User enters password as {string}")
    public void enterPassword(String passWord) {
        loginPage.inputPassword(passWord);
 
        loginPage.clickLogin();
    }
 
    @Then("User should be able to login successfully")
    public void clickOnLoginButton() {
        dashPage.loginVerify();
    }
   
}

Serenity Step Libraries integrate smoothly into Cucumber Step Definition files; all you need to do is to annotate a step library variable with the @Steps annotation.  Methods that represent a business task or action (inputUserName()), and that will appear in the reports as a separate step, are annotated with the @Step annotation. Here, I have created two StepClasses – StepLoginPage and StepDashboardPage

public class StepLoginPage extends PageObject {
 
    @Step("Enter Username")
    public void inputUserName(String userName) {
        $(By.name("txtUsername")).sendKeys((userName));
    }
 
    @Step("Enter Password")
    public void inputPassword(String passWord) {
        $(By.name("txtPassword")).sendKeys((passWord));
    }
 
    @Step("Click Submit Button")
    public void clickLogin() {
        $(By.name("Submit")).click();
    } 
 
}

StepDashboardPage

public class StepDashboardPage extends PageObject {
 
    @Step("Successful login")
    public void loginVerify() {
        String dashboardTitle = $(By.id("welcome")).getText();
        assertThat(dashboardTitle, containsString("Welcome"));
    }
}

Step 7 – Create a Serenity Cucumber Runner class

import org.junit.runner.RunWith;

import io.cucumber.junit.CucumberOptions;
import net.serenitybdd.cucumber.CucumberWithSerenity;

@RunWith(CucumberWithSerenity.class)
@CucumberOptions(plugin = {}, features = "lib/src/test/resources/features", glue = "serenitygradleautomation.definitions")

public class CucumberTestSuite {

}

Step 8 – Create serenity.conf file under src/test/resources

Serenity.conf file is used to specify various features like the type of webdriver used, various test environments, run tests in headless mode, and many more options.

webdriver {
    driver = firefox
}
 
 
environments {
  default {
    webdriver.base.url = "https://opensource-demo.orangehrmlive.com/"
  }
  dev {
    webdriver.base.url = "https://opensource-demo.orangehrmlive.com/dev"
  }
  staging {
    webdriver.base.url = "https://opensource-demo.orangehrmlive.com/staging"
  }
  prod {
    webdriver.base.url = "https://opensource-demo.orangehrmlive.com/prod"
  }
}

Step 9 – Create serenity.properties file at the root of the project

serenity.project.name = Serenity and Cucumber Gradle Demo

Step 10 – Run the tests through commandline which generates Serenity Report

Open the command line and go to the location where gradle.build of the project is present and type the below command.

gradle test

The Serenity report is generated under /lib/target/site/serenity.

Serenity Report

Below is the image of Overall Test Result with steps and screenshots.

That’s it! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!

Integration of Allure Report with Selenium and TestNG

HOME

In this tutorial, I will explain how to integrate Allure Report (one of the very famous Reports) with Selenium and TestNG.

What is Allure Framework?

Allure is an open-source framework designed to create interactive and comprehensive test reports by Yandex QA Team.

The below example covers the implementation of Allure Reports in Selenium using TestNG, Java, and Maven.

Prerequisite:

  1. Java 11 installed
  2. Maven installed
  3. Eclipse or IntelliJ installed
  4. Environment variables JAVA_HOME, MAVEN_HOME and ALLURE_HOME are correctly configured

Dependency List

  1. Selenium – 3.141.59
  2. Java 11
  3. TestNG – 7.4.0
  4. Maven – 3.8.1
  5. Allure Report – 2.14.0
  6. Allure TestNG – 2.14.0

Implementation Steps

  1. Update the Properties section in Maven pom.xml
  2. Add Selenium, TestNG, and Allure TestNG dependencies in POM.xml
  3. Update Build Section of pom.xml in Allure Report Project.
  4. Create Pages and Test Code for the pages
  5. Create testng.xml for the project
  6. Run the Test and Generate Allure Report

Step 1 – Update the Properties section

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <selenium.version>3.141.59</selenium.version>
    <testng.version>7.4.0</testng.version>
    <allure.testng.version>2.14.0</allure.testng.version>
    <maven.compiler.plugin.version>3.5.1</maven.compiler.plugin.version>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <aspectj.version>1.9.6</aspectj.version>
    <maven.surefire.plugin.version>3.0.0-M5</maven.surefire.plugin.version>
  </properties>

Step 2 – Add Selenium, TestNG, and Allure TestNG dependencies in POM.xml

<dependencies>
    
     <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>${selenium.version}</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.testng/testng -->
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>${testng.version}</version>
      <scope>test</scope>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/io.qameta.allure/allure-testng -->
    <dependency>
        <groupId>io.qameta.allure</groupId>
        <artifactId>allure-testng</artifactId>
        <version>${allure.testng.version}</version>
        <scope>test</scope>
    </dependency>
  </dependencies>

Step 3 – Update the Build Section of pom.xml in the Allure Report Project

<build>
       
       <plugins>
   <!-- Compiler plug-in -->
  
           <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.compiler.plugin.version}</version>
                <configuration>
                    <source>${maven.compiler.source}</source> <!--For JAVA 8 use 1.8-->
                    <target>${maven.compiler.target}</target> <!--For JAVA 8 use 1.8-->
                </configuration>
            </plugin>
            
     <!-- Added Surefire Plugin configuration to execute tests -->       
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-surefire-plugin</artifactId>
              <version>${maven.surefire.plugin.version}</version>
              <configuration>
                    <suiteXmlFiles>
                        <suiteXmlFile>TestNG.xml</suiteXmlFile>
                    </suiteXmlFiles>
                 <argLine>
                    -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                 </argLine>
             </configuration>          
             <dependencies>
            
            <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjweaver</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
            </dependencies>
        </plugin>
      </plugins>
  </build>

Step 4 – Create Pages and Test Code for the pages

Below is the sample project which uses Selenium and TestNG which is used to generate an Allure Report.

We have 2 pages. Below is the code for Login Page which contains all the web elements and methods related to that web elements.

LoginPage.java

public class LoginPage {

	WebDriver driver;

	By userName = By.name("txtUsername");

	By password = By.name("txtPassword");

	By titleText = By.id("logInPanelHeading");

	By login = By.id("btnLogin");

	By errorMessage = By.id("spanMessage");

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

	// Set user name in textbox
	public void setUserName(String strUserName) {
		driver.findElement(userName).sendKeys(strUserName);
	}

	// Set password in password textbox
	public void setPassword(String strPassword) {
		driver.findElement(password).sendKeys(strPassword);
	}

	// Click on login button
	public void clickLogin() {
		driver.findElement(login).click();
	}

	@Step("Verify title of Login Page")
	public void verifyPageTitle() {
		String loginPageTitle = driver.findElement(titleText).getText();
		Assert.assertTrue(loginPageTitle.contains("LOGIN Panel"));
	}

    /* Failed Test */
	@Step("Verify error message when invalid credentail is provided")
	public void verifyErrorMessage() {
		String invalidCredentialErrorMessage = driver.findElement(errorMessage).getText();
		Assert.assertTrue(invalidCredentialErrorMessage.contains("Incorrect Credentials"));
	}

	@Step("Enter username and password")
	public void login(String strUserName, String strPasword) {

		// Fill user name
		this.setUserName(strUserName);

		// Fill password
		this.setPassword(strPasword);

		// Click Login button
		this.clickLogin();

	}
}

Dashboard.java

public class DashboardPage {

	WebDriver driver;

	By dashboardPageTitle = By.id("welcome");

	By options = By.cssSelector(
			"#dashboard-quick-launch-panel-menu_holder > table > tbody > tr > td:nth-child(1) > div > a > span");

	public DashboardPage(WebDriver driver) {
		this.driver = driver;

	}

	@Step("Verify title of Dashboard page")
	public void verifyDashboardPageTitle() {
		String DashboardPageTitle = driver.findElement(dashboardPageTitle).getText();
		Assert.assertTrue(DashboardPageTitle.contains("Welcome"));
	}

	@Step("Verify Quick Launch Options on Dashboard page")
	public void verifyQuickLaunchOptions() {
		String QuickLaunchOptions = driver.findElement(options).getText();
		Assert.assertTrue(QuickLaunchOptions.contains("Assign Leave"));
	}

}

Below are the Test classes for Login Page and Dashboard Page. Here, we have BaseTest Class also which contains the common methods needed by other test pages.

BaseTest.java

public class BaseTest {

	public static WebDriver driver;
	LoginPage objLogin;
	DashboardPage objDashboardPage;

	@Step("Start the application")
	@BeforeMethod
	public void setup() {
		System.setProperty("webdriver.gecko.driver",
				"C:\\Users\\Vibha\\Software\\geckodriver-v0.26.0-win64\\geckodriver.exe");
		driver = new FirefoxDriver();
		driver.manage().window().maximize();
		driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
		driver.get("https://opensource-demo.orangehrmlive.com/");
	}

	@Step("Stop the application")
	@AfterMethod
	public void close() {
		driver.close();
	}
}

LoginTests.java

@Epic("Web Application Regression Testing")
@Feature("Login Page Tests")
@Listeners(TestExecutionListener.class)
public class LoginTests extends BaseTest {

	LoginPage objLogin;
	DashboardPage objDashboardPage;

	@Severity(SeverityLevel.NORMAL)
	@Test(priority = 0, description = "Verify Login Page")
	@Description("Test Description : Verify the title of Login Page")
	@Story("Title of Login Page")
	public void verifyLoginPage() {

		// Create Login Page object
		objLogin = new LoginPage(driver);

		// Verify login page text
		objLogin.verifyPageTitle();
	}

   /* Failed Test */
	@Severity(SeverityLevel.BLOCKER)
	@Test(priority = 1, description = "Login with invalid username and password")
	@Description("Test Description : Login Test with invalid credentials")
	@Story("Unsuccessful Login to Application")
	public void invalidCredentialTest() {

		// Create Login Page object
		objLogin = new LoginPage(driver);
		objLogin.login("test", "test123");

		// Verify login page text
		objLogin.verifyErrorMessage();

	}

}

We can order tests by severity by using @Severity annotation. Click here to know more about other Allure annotations.

DashboardTests.java

@Epic("Web Application Regression Testing")
@Feature("Dashboard Page Tests")
@Listeners(TestExecutionListener.class)
public class DashboardTests extends BaseTest {

	LoginPage objLogin;
	DashboardPage objDashboardPage;

	@Severity(SeverityLevel.BLOCKER)
	@Test(priority = 0, description = "Verify Dashboard Page")
	@Description("Test Description : After successful login to application opens Dashboard page")
	@Story("Successful login of application opens Dashboard Page")

	public void DasboardTest() {

		objLogin = new LoginPage(driver);

		// login to application
		objLogin.login("Admin", "admin123");

		// go the dashboard page
		objDashboardPage = new DashboardPage(driver);

		// Verify dashboard page
		objDashboardPage.verifyQuickLaunchOptions();

	}

}

We can group tests with @Epic@Feature, and @Stories annotations. Click here to know more about other Allure annotations.

TestExecutionListener.class

We can add attachments to our reports by using @Attachment annotation. It can return String, byte [], etc.  I need to add @Listeners({ TestExecutionListener.class }) declaration at the top of the test classes. Click here to know more about other Allure annotations.

public class TestExecutionListener implements ITestListener {

	@Attachment(value = "Screenshot of {0}", type = "image/png")
	public byte[] saveScreenshot(String name, WebDriver driver) {
		return (byte[]) ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
	}

	@Override
	public void onTestFailure(ITestResult result) {
		saveScreenshot(result.getName(), BaseTest.driver);
	}

}

Step 5 – Create testng.xml for the project

TestNG.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name = "Allure Reports">
  <test name = "Login Page Tests">
    <classes>
          <class name = "com.example.TestNGAllureReportDemo.tests.LoginTests"/>
         
          </classes>
          </test> 
    <test name =" Dashboard Tests">   
    <classes> 
          <class name = "com.example.TestNGAllureReportDemo.tests.DashboardTests"/>
          </classes>
    </test>

</suite>

Step 6 – Run the Test and Generate Allure Report

To run the tests, use the below command

mvn clean test

In the below image, we can see that one test failed and two passed out of three tests.

To create an Allure Report, use the below command

allure serve

This will generate the beautiful Allure Test Report as shown below.

Allure Report Dashboard

The overview page hosts several default widgets representing the basic characteristics of your project and test environment.

  1. Statistics – overall report statistics.
  2. Launches – if this report represents several test launches, statistics per launch will be shown here.
  3. Behaviors – information on results aggregated according to stories and features.
  4. Executors – information on test executors that were used to run the tests.
  5. History Trend – if tests accumulated some historical data, it’s a trend that will be calculated and shown on the graph.
  6. Environment – information on the test environment.

Categories in Allure Report

The categories tab gives you a way to create custom defects classifications to apply for test results. There are two categories of defects – Product Defects (failed tests) and Test Defects (broken tests).

Suites in Allure Report

On the Suites tab a standard structural representation of executed tests, grouped by suites and classes can be found.

Graphs in Allure Report

Graphs allow you to see different statistics collected from the test data: status breakdown or severity and duration diagrams.

Timeline in Allure Report

The timeline tab visualizes retrospective of tests execution, allure adaptors collect precise timings of tests, and here on this tab, they are arranged accordingly to their sequential or parallel timing structure.

Behaviors of Allure Report

This tab groups test results according to Epic, Feature, and Story tags.

Packages in Allure Report

The packages tab represents a tree-like layout of test results, grouped by different packages.

If you click on the (highlighted tab), it will show the test execution report in the below format.

Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!

Additional tutorials on Allure Reports:

Page Object Model without Page Factory in Selenium Webdriver

HOME

What is Page Object Model?

Page Object Model(POM) is an object design pattern in Selenium webdriver which tells how to organize the object repository. In this case, we refer to web elements as Objects. Page Object Model(POM) is not a Test Framework.

In the Page Object Model (POM), each web page is represented as a separate class. For example, consider HRM website. It has many web pages like Login , Dashboard , Assign Leave, Leave List, Timesheets, etc. Under this model, for each web page in the application, there should be a corresponding Page Class. This Page class will identify the WebElements of that web page and also contains Page methods that perform operations on those WebElements.

If a new web element is added or an existing web element is updated, then you can add or update that web element in object repository by navigating to class which has same name as webpage.

The object repository is independent of test cases, so we can use the same object repository for a different purpose with different tools. For example, we can integrate Page Object Model in Selenium with TestNG/JUnit for functional Testing and at the same time with JBehave/Cucumber for acceptance testing.

POM enhances test maintenance, readability and reducing code duplication.

In this tutorial, I’m creating a project using Page Object Model as Design Pattern and TestNG as the Test Automation Framework.

Steps to create a Page Object Model Project

  1. Download and Install Java on system
  2. Download and setup Eclipse IDE on system
  3. Setup Maven
  4. Create a new Maven Project
  5. Add dependencies to pom.xml
  6. Create Page Class for each page – LoginPage.Java and DashboardPage.java
  7. Create tests for each Page – BaseTests, LoginTests and DashboardTests
  8. Create a TestNG.XML
  9. Run the tests from TestNG.xml
  10. TestNG Report Generation

Step 1- Download and Install Java

Click here to know How to install Java. To check if Java is already installed on your machine, use the below command in the command line. This command will show the version of Java installed on your machine.

java -version

Step 2 – Download and setup Eclipse IDE on system

The Eclipse IDE (integrated development environment) provides strong support for Java developer. The Eclipse IDE for Java Developers distribution is designed to support standard Java development. It includes support for the Maven and Gradle build system and support for the Git version control system. Click here to know How to install Eclipse.

Step 3 – Setup Maven

To build a test framework, we need to add a number of dependencies to the project. It is very tedious and cumbersome process to add each dependency manually. So, to overcome this problem, we use a build management tool. Maven is a build management tool which is used to define project structure, dependencies, build, and test management. Click here to know How to install Maven.

To know if Maven is already installed or not on your machine, type this command in the command line. This command will show the version of Maven installed on your machine.

mvn -version

Step 4 – Create a new Maven Project

Click here to know How to create a Maven project

Below is the Maven project structure. Here,

Group Id – com.example
Artifact Id – pageobjectmodel_demo
Version – 0.0.1-SNAPSHOT
Package – com. example.pageobjectmodel_demo

Step 5 – Add dependencies to the pom.xml

I have added Selenium and TestNG dependencies.

<dependencies>
  
   <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>3.141.59</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.testng/testng -->
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>7.4.0</version>
      <scope>test</scope>
    </dependency>   
    
</dependencies>

Step 6 – Create Page Class for each page – LoginPage.Java and DashboardPage.java

I want to test 2 pages – Login and Dashboard. So, I’m creating 2 seperate class. Each class will contain its web elements and methods of that page.

LoginPage.Java

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

public class LoginPage {

	WebDriver driver;

	By userName = By.name("txtUsername");

	By password = By.name("txtPassword");

	By titleText = By.id("logInPanelHeading");

	By login = By.id("btnLogin");

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

	// Set user name in textbox
	public void setUserName(String strUserName) {
		driver.findElement(userName).sendKeys(strUserName);
	}

	// Set password in password textbox
	public void setPassword(String strPassword) {
		driver.findElement(password).sendKeys(strPassword);
	}

	// Click on login button
	public void clickLogin() {
		driver.findElement(login).click();
	}

	// Get the title of Login Page
	public String getLoginTitle() {
		return driver.findElement(titleText).getText();
	}

	public void login(String strUserName, String strPasword) {

		// Fill user name
		this.setUserName(strUserName);

		// Fill password
		this.setPassword(strPasword);

		// Click Login button
		this.clickLogin();
	}
}

DashboardPage.java

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

public class DashboardPage {

	WebDriver driver;

	By homePageUserName = By.id("welcome");

	public DashboardPage(WebDriver driver) {
		this.driver = driver;

	}

	// Get the User name from Home Page
	public String getHomePageText() {
		return driver.findElement(homePageUserName).getText();
	}

}

Step 7 – Create tests for each Page – BaseTests, LoginTests and DashboardTests

Here, I have created 3 classes. BaseTest class to contain startUp and tearDown methods. These methods will run once before the after of every class. LoginTests and DashboardTests classes contain the tests related to LoginPage and DashboardPage respectively.

BaseTest

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;

import com.example.pageobjectmodel_demo.pages.DashboardPage;
import com.example.pageobjectmodel_demo.pages.LoginPage;

public class BaseTest {

	public static WebDriver driver;
	LoginPage objLogin;
	DashboardPage objDashboardPage;

	@BeforeClass
	public void setup() {
		System.setProperty("webdriver.gecko.driver",
				"C:\\Users\\Vibha\\Software\\geckodriver-v0.26.0-win64\\geckodriver.exe");
		driver = new FirefoxDriver();
		driver.manage().window().maximize();
		driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
		driver.get("https://opensource-demo.orangehrmlive.com/");
	}

	@AfterClass
	public void close() {
		driver.close();
	}
}

LoginTests

import org.testng.Assert;
import org.testng.annotations.Test;

import com.example.pageobjectmodel_demo.pages.DashboardPage;
import com.example.pageobjectmodel_demo.pages.LoginPage;

public class LoginTests extends BaseTest {

	LoginPage objLogin;
	DashboardPage objDashboardPage;

	@Test(priority = 0)
	public void loginTest() {

		// Create Login Page object
		objLogin = new LoginPage(driver);

		// Verify login page text
		String loginPageTitle = objLogin.getLoginTitle();
		Assert.assertTrue(loginPageTitle.contains("LOGIN Panel"));
	}

}

DashboardTests

import org.testng.Assert;
import org.testng.annotations.Test;

import com.example.pageobjectmodel_demo.pages.DashboardPage;
import com.example.pageobjectmodel_demo.pages.LoginPage;

public class DashboardTests extends BaseTest {

	LoginPage objLogin;
	DashboardPage objDashboardPage;

	@Test(priority = 0)
	public void DasboardTest() {

		objLogin = new LoginPage(driver);

		// login to application
		objLogin.login("Admin", "admin123");

		// go the dashboard page
		objDashboardPage = new DashboardPage(driver);

		// Verify dashboard page
		Assert.assertTrue(objDashboardPage.getHomePageText().contains("Welcome"));
	}

}

Step 8 – Create a TestNG.XML

Here, I have mentioned 2 test classes. So, when I will run the tests from TestNG.xml, it will run the tests of both the classes. If will mention any one class, then the test of that particular class will be executed.

<?xml version = "1.0"encoding = "UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name = "PageObjectModel">
  <test name = "PageObjectModel Tests">
    <classes>
          <class name = "com.example.pageobjectmodel_demo.tests.LoginTests"/>
          <class name = "com.example.pageobjectmodel_demo.tests.DashboardTests"/>
     </classes>  
   </test>
</suite>

Step 9 – Run the tests from TestNG.xml

Right click on TestNG.xml and select Run As TestNG Suite.

The execution status looks like as shown below.

Step 10 – TestNG Report Generation

Once the execution is finished, refresh the project. It will create a test-output folder containing various reports generated by TestNG. Below is the screenshot of the report folder.

Image of Index.html report

Image of emailable-report.html

Cheers! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!

How to set style in Excel in Java using Apache POI

HOME

In the previous tutorial, I have explained about How to add Formulas in Excel in Java. In this tutorial, I will explain How to customize the style of cells in Excel in Java using Apache POI.

I’m using Apache POI to write data to the excel file. To download and install Apache POI, refer here.

If you are using maven, then you need to add below dependency in pom.xml.

<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.0.0</version>
</dependency>
   
   
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.0.0</version>
</dependency>

To know more about various interfaces and classes for managing Excel, please refer to this tutorial.

In the below example, I have an existing excel with the name of “EmployeeDetails.xlsx”.

Steps to Customize the style in Excel

Step 1 – Create a blank work and then a sheet with name Write_TestData.

XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("Write_TestData");

Step 2- XSSFWorkbook and XSSFSheet are imported from the below consecutive packages.

import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;

Step 3 – Write data to the sheet. To know more about this part, refer this link.

Step 4 – Set the auto Size for column 0.

sheet.autoSizeColumn(0);

Step 5 – To create a cell style, we only need a reference to the excel workbook:

	CellStyle style = workbook.createCellStyle();

Step 6 – CellStyle is imported from package mentioned below.

import org.apache.poi.ss.usermodel.CellStyle;

Step 7 – To create font style and add attributes to this font

XSSFFont font = workbook.createFont();

Step 8 – XSSFFont is imported from below package

import org.apache.poi.xssf.usermodel.XSSFFont;

Step 9 – To set the Background Colour of the cell.

style.setFillForegroundColor(IndexedColors.BLUE_GREY.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);

Step 10 – BackgroundColor and FillPattern are imported from the below consecutive packages.

import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.FillPatternType;

Step 11 – Write data to an OutputStream. Use the below code to write output stream.

FileOutputStream out = new FileOutputStream(new File("Styled_EmployeeDetails.xlsx"));
workbook.write(out);

Below is the complete program to show various cell setyles for Row 0 (Header Row).

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;

import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ExcelStyleExample {

	public static void main(String[] args) {

		try {
			// create blank workbook
			XSSFWorkbook workbook = new XSSFWorkbook();

			// Create a blank sheet
			XSSFSheet sheet = workbook.createSheet("Write_TestData");

			ArrayList<Object[]> data = new ArrayList<Object[]>();
			data.add(new String[] { "Name", "Id", "Salary" });
			data.add(new Object[] { "Jim Lawrence", "001A", 10000 });
			data.add(new Object[] { "Jack", "1001B", 40000 });
			data.add(new Object[] { "Tim", "2001C", 20000 });
			data.add(new Object[] { "Gina", "1004S", 30000 });

			// Iterate over data and write to sheet
			int rownum = 0;
			for (Object[] employeeDetails : data) {

				// Create Row
				XSSFRow row = sheet.createRow(rownum++);

				int cellnum = 0;
				for (Object obj : employeeDetails) {

					// Create cell
					XSSFCell cell = row.createCell(cellnum++);

					// Set value to cell
					if (obj instanceof String)
						cell.setCellValue((String) obj);
					else if (obj instanceof Double)
						cell.setCellValue((Double) obj);
					else if (obj instanceof Integer)
						cell.setCellValue((Integer) obj);

					// Set Column width to the maximum for Column 0
					sheet.autoSizeColumn(0);

					if (rownum == 1) {

						CellStyle style = null;

						// Creating a font
						XSSFFont font = workbook.createFont();

						font.setFontHeightInPoints((short) 10);
						font.setFontName("Verdana");
						font.setColor(IndexedColors.BLACK.getIndex());
						font.setBold(true);
						font.setItalic(false);

						// Creating cell Style
						style = workbook.createCellStyle();

						// Setting Foreground Colour
						style.setFillForegroundColor(IndexedColors.BLUE_GREY.getIndex());
						style.setFillPattern(FillPatternType.SOLID_FOREGROUND);

						// Setting Alignment of font
						style.setAlignment(HorizontalAlignment.CENTER);

						// Setting font to style
						style.setFont(font);

						// Setting cell style
						cell.setCellStyle(style);

					}
				}
			}

			// Write the workbook in file system
			FileOutputStream out = new FileOutputStream(new File("Styled_EmployeeDetails.xlsx"));
			workbook.write(out);

			System.out.println("Style of Excel is updated successfully");

			out.close();

			// Close workbook
			workbook.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}