Advanced HTML Reports…

TestNG default reports are not very attractive and they are very basic. In this post we will use an advanced HTML Report called Extent Report. We will use this reporting to create our own custom report. Below is a snapshot on how our custom report will look like.

Extent Reports

To save time and effort we will be using already created Java Project ‘NewTourPageFactory‘ from our previous post Working with Page Factory…. We will add an additional class for our reporting and also update some existing classes. Below is the snapshot of the project structure of ‘NewTourPageFactory‘.

NewTourPageFactory Project Structure
  1. To start with Extent Reporting, first task is to download the Jar. Go to Google and type in “Extent Report jar download”. Click on the maven repository link to download the Jar or else you can go directly to Extent Report Jar download link to download the Jar. Here we will be using version 2.40.2.
  2. Extent reports jar has a dependency with freemarker jar. So this too need to be downloaded. Here we are using ‘freemarker-2.3.23’ version.
  3. Once both Jars are downloaded to the local folder, the next step is to add them into our Java Project. Right Click on the project name and click Properties. Click on Java Build Path -> Add External Jars. Go to the local folder where ‘extentreports-2.40.2’ and ‘freemarker-2.3.23’ are saved. Add Jars and click OK to close the window. Once complete, we will see them inside ‘Referenced Libraries‘.

    Extent Report Jars
  4. The next step is to create one Extent Report Reports class. This class will contain all the required methods for starting the test, logging the test status and ending the test. Right click on ‘com.selenium.util‘ package and click New -> Class. Name the class file as ‘Reports‘.

    Reports class
  5. Copy and paste the below code into the Reports class.
    package com.selenium.util;
    
    import com.relevantcodes.extentreports.ExtentReports;
    import com.relevantcodes.extentreports.ExtentTest;
    import com.relevantcodes.extentreports.LogStatus;
    
    public class Reports {
    
    	public static ExtentReports extent;
    	public static ExtentTest test;
    
    	// Start Test Case
    	public void startTest(String testCaseName) {
    
    		/*Create ExtentReports object passing location and report name as argument. Notice a new Result Log folder will be created inside project and the report name will be TestReport.html*/
    		extent = new ExtentReports(System.getProperty("user.dir") + "/RESULT_LOG" + "/TestReport.html");
    
    		// Add details to our report
    		extent.addSystemInfo("Selenium Version", "3.0.1").addSystemInfo("Environment", "QA");
    
    		// Create ExtentTest passing test case name and description
    		test = extent.startTest(testCaseName, "Our First Test Report");
    	}
    
    	// Log Test status, Test name and Test details
    	public void logStatus(LogStatus testStatus, String testStepName, String testDetails) {
    
    		// Log test status
    		test.log(testStatus, testStepName, testDetails);
    	}
    
    	// Capture screenshot and log into report
    	public void screenshotLog(LogStatus logStatus, String testStepName, String screenShotPath) {
    
    		// Attach screenshots
    		test.log(logStatus, testStepName + test.addScreenCapture(screenShotPath));
    	}
    
    	// End Test Case
    	public void endTest() {
    
    		// End test
    		extent.endTest(test);
    		extent.flush();
    		extent.close();
    	}
    }
    
  6. Next steps is to add the logging information into our test steps. For that we will add few steps into our page object class. Here we will be updating ‘HomePage’ class inside ‘com.selenium.pages‘ package.

    HomePage class
  7. Replace the existing code of ‘HomePage’ class with below code.
    package com.selenium.pages;
    
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.support.FindBy;
    import com.relevantcodes.extentreports.LogStatus;
    import com.selenium.util.Log;
    import com.selenium.util.Reports;
    
    public class HomePage {
    	// Declare WebDriver
    	WebDriver driver;
    	Reports reports;
    	// Element Locators for username textbox
    	@FindBy(name = "userName")
    	private WebElement userName;
    
    	// Element Locators for password textbox
    	@FindBy(name = "password")
    	private WebElement password;
    
    	// Element Locators for login button
    	@FindBy(name = "login")
    	private WebElement login;
    
    	// Constructor. Driver Initialization
    	public HomePage(WebDriver driver) {
    		this.driver = driver;
    		reports = new Reports();
    
    	}
    
    	// Login method. Notice there is no return type
    	public void loginUser(String uname, String pwd) {
    		// Enter username
    		userName.sendKeys(uname);
    		// Log4j logging
    		Log.info("HomePage.loginUser - username entered");
    
    		// Extent Reprot Logging. Enter Log status for HTML report
    		reports.logStatus(LogStatus.PASS, "Enter user name", "User name entered" + " <span class='label success'> Success</span>");
    		// Enter password
    		password.sendKeys(pwd);
    		// Log4j logging
    		Log.info("HomePage.loginUser - password entered");
    
    		// Extent Reprot Logging. Enter Log status for HTML report
    		reports.logStatus(LogStatus.PASS, "Enter password", "Password entered" + " <span class='label success'>Success</span>");
    		// Click Login button
    		login.click();
    		// Log4j logging
    		Log.info("HomePage.loginUser - login button clicked");
    
    		// Extent Reprot Logging. Enter Log status for HTML report
    		reports.logStatus(LogStatus.PASS, "Click Login","Login button clicked" + " <span class='label success'> Success</span>");
    	}
    }
    
  8. In the above code, notice that we created an object of Reports class and used its methods for logging test status. We can log different test status like LogStatus.PASS, LogStatus.FAIL, LogStatus.ERROR etc based on our test.
  9. We can take same approach for other page object classes. However in this post we will be updating only the ‘HomePage’ class.
  10. Before logging the log status in extent report, we need to start the test. This will be done in the TestNG test case.

    BookFlight class – TestNG test case
  11. We will update the ‘BookFlight’ class inside ‘com.selenium.testcase‘ package with below code.
    package com.selenium.testcase;
    
    import org.testng.annotations.Test;
    import com.selenium.pages.BookFlightPage;
    import com.selenium.pages.FlightConfirmationPage;
    import com.selenium.pages.FlightFinderPage;
    import com.selenium.pages.HomePage;
    import com.selenium.pages.SelectFlightPage;
    import com.selenium.util.Log;
    import com.selenium.util.Reports;
    import org.testng.annotations.BeforeMethod;
    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    import org.apache.log4j.xml.DOMConfigurator;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.support.PageFactory;
    import org.testng.annotations.AfterMethod;
    import org.testng.annotations.DataProvider;
    import org.testng.annotations.BeforeTest;
    
    public class BookFlight {
    
    	WebDriver driver;
    	HomePage homePage;
    	FlightFinderPage flightFinderPage;
    	SelectFlightPage selectFlightPage;
    	BookFlightPage bookFlightPage;
    	FlightConfirmationPage flightConfirmationPage;
    	Reports reports;
    
    	// Test Case
    	@Test(dataProvider = "newTourData")
    	public void bookFlight(String uname, String pwd, String departFrom, String departDate, String fname, String lname,
    			String ccNum) {
    
    		/*
    		 * Test case logic.
    		 * 
    		 */
    		Log.startTestCase("Test Case bookFlight");
    		Log.info("BookFlight.bookFlight - Home Page Opens");
    		homePage.loginUser(uname, pwd);
    		Log.info("BookFlight.bookFlight - Flight Finder Page Opens");
    		flightFinderPage.findFlights(departFrom, departDate);
    		Log.info("BookFlight.bookFlight - Select Flight Page Opens");
    		selectFlightPage.reserveFlight();
    		Log.info("BookFlight.bookFlight - Book Flight Page Opens");
    		bookFlightPage.bookFlight(fname, lname, ccNum);
    		Log.info("BookFlight.bookFlight - Flight Confirmation Page Opens");
    		flightConfirmationPage.clickLogOut();
    		Log.endTestCase("Test Case bookFlight");
    
    	}
    
    	// Driver and Page Objects Initialization
    	@BeforeMethod
    	public void beforeMethod() {
    		// Initialize driver
    		driver = new ChromeDriver();
    		Log.info("BookFlight.beforeMethod - Chrome Driver Intialized");
    		// Page Factory Initialization for all page objects
    		homePage = PageFactory.initElements(driver, HomePage.class);
    		flightFinderPage = PageFactory.initElements(driver, FlightFinderPage.class);
    		selectFlightPage = PageFactory.initElements(driver, SelectFlightPage.class);
    		bookFlightPage = PageFactory.initElements(driver, BookFlightPage.class);
    		flightConfirmationPage = PageFactory.initElements(driver, FlightConfirmationPage.class);
    		Log.info("BookFlight.beforeMethod - Page Factory intialization complete");
    
    		// Start Extent Report
    		reports.startTest("Book Flight");
    
    		// Nvaigate to URL
    		driver.get("http://newtours.demoaut.com");
    		Log.info("BookFlight.beforeMethod - open New Tour URL");
    
    		// Maximize window
    		// driver.manage().window().maximize();
    		Log.info("BookFlight.beforeMethod - Browser maximized");
    
    	}
    
    	// Driver closure
    	@AfterMethod
    	public void afterMethod() {
    
    		// End Extent Report
    		reports.endTest();
    
    		// Close and quit the driver to close the Browser
    		driver.close();
    		driver.quit();
    		Log.info("BookFlight.afterMethod - Browser closed");
    	}
    
    	// Create test data
    	@DataProvider
    	public Object[][] newTourData() {
    		return new Object[][] { { "demo", "demo", "London", "7", "john", "Doe", "56465465" } };
    	}
    
    	// Setting System property
    	@BeforeTest
    	public void beforeTest() {
    		// Set System Property for driver location
    		System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir") + "/Chrome/chromedriver");
    		SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
    		SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    		// Set System Property for log file location
    		System.setProperty("logfoldername", sdf1.format(Calendar.getInstance().getTime()));
    		System.setProperty("logfilename", sdf2.format(Calendar.getInstance().getTime()) + "-LOG");
    
    		Log.info("BookFlight.beforeTest - System property setting complete");
    		DOMConfigurator.configure("src/log4j.xml");
    		Log.info("BookFlight.beforeTest - XML config complete");
    
    		// Create Extent Report object
    		reports = new Reports();
    	}
    }
    
  12. Notice that in the above code, we are creating a Reports object inside ‘@BeforeTest‘ method, starting the test inside ‘@BeforeMethod‘ and ending the test inside ‘@AfterMethod‘.
  13. Final step is to execute our TestNG test case. Right click on ‘BookFlight’ class and click Run As -> TestNG Test.

    TestNG Test
  14. After successful execution, a new folder named ‘RESULT_LOG’ will be created inside our project and the Extent Report will be placed in this folder. This is because, inside ‘startTest‘ method of Reports class, we are creating an Extent Report object by passing the location as argument.
    /*Create ExtentReports object passing location and report name as
    argument. Notice a new Result Log folder will be created inside
    project and the report name will be TestReport.html*/
    extent = new ExtentReports(System.getProperty("user.dir") + "/RESULT_LOG" + "/TestReport.html");
    
  15. Right click on ‘TestReport.html’ to open on web browser. Below is the snapshots on how our test report will look like.
    Book Flight Extent Report Page 1

    Book Flight Extent Report Page 2
  16. Notice that all the log status that we entered in ‘HomePage’ class are displayed in the HTML report.

Entent Reports help us in creating beautiful looking test reports. They are very easy to implement and also provide valuable information about our test. Hope this post is useful in creating some good looking reports. Many more to follow. Till then, Happy Learning!

Additional Information:

While logging the Extent Report status we have used some HTML code inside ‘HomePage’ class.

// Extent Reprot Logging. Enter Log status for HTML report
reports.logStatus(LogStatus.PASS, "Enter user name",
	"User name entered" + " <span class='label success'>Success</span>");

The span class helps us in providing some meaningful logs and messages into our test report. Some more labels are also available for use.

"<span class='fail label'>Fail</span>"
"<span class='warning label'>Warning</span>"
"<span class='info label'>Info</span>"
"<span class='skip label'>Skip</span>"