Creating HTML reports for your Selenium tests using ExtentReports

In a comment on a previous post I wrote on creating custom HTML reports for Selenium tests, Anshoo Arora of Relevant Codes pointed me to ExtentReports, his own solution for generating HTML reports. This week, I have been playing around with it for a while and I must say I’m pretty impressed by its ease of use and the way the reports it generates turn out. Let’s have a look.

Note: this post is based on ExtentReports version 1.4 and therefore might not reflect any changes made in more recent versions.

Downloading and installation
Installation of ExtentReports is a breeze. Just download the latest .jar from the website, add it as a dependency to your Java project and you’re all set.

An example test and report
To illustrate the workings of ExtentReports, we’ll use two simple login tests that are executed against the ParaBank demo application on the Parasoft website. Both tests perform a login action, where the first will be successful and the second one will be unsuccessful due to invalid credentials. We’ll have ExtentReports generate a HTML report that contain the appropriate test results.

public class ExtentReportsDemo {

	static final ExtentReports extent = ExtentReports.get(ExtentReportsDemo.class);
	static WebDriver driver = new FirefoxDriver();

	static String reportLocation = "C:\\Tools\\reports\\";
	static String imageLocation = "images/";
	
	public static void main (String args[]) {

		extent.init(reportLocation + "ScreenshotReport.html", true, DisplayOrder.BY_OLDEST_TO_LATEST, GridType.STANDARD);

        extent.config().documentTitle("Sample ExtentReports report");
        
		extent.config().reportHeadline("Test report for ParaBank login tests generated using <b>ExtentReports</b>");

		extent.startTest("TC01.1","This test is a positive login test for ParaBank");
		runPositiveTest();
		extent.endTest();

		extent.startTest("TC01.2","This is a negative login test for ParaBank (contains a defect)");
		runNegativeTest();
		extent.endTest();

		driver.quit();
	}

	public static void runPositiveTest() {

		driver.get("http://parabank.parasoft.com");

		checkTitle(driver,"ParaBank | Welcome | Online Banking");

		driver.findElement(By.name("username")).sendKeys("john");
		driver.findElement(By.name("password")).sendKeys("demo");
		driver.findElement(By.xpath("//input[@value='Log In']")).click();

		checkTitle(driver,"ParaBank | Accounts Overview");

		driver.findElement(By.partialLinkText("Log Out")).click();
	}

	public static void runNegativeTest() {

		driver.get("http://parabank.parasoft.com");

		checkTitle(driver,"ParaBank | Welcome | Online Banking");

		driver.findElement(By.name("username")).sendKeys("john");
		driver.findElement(By.name("password")).sendKeys("incorrectpassword");
		driver.findElement(By.xpath("//input[@value='Log In']")).click();

		checkErrorMessage(driver,"Incorrect credentials");
	}

	public static void checkTitle(WebDriver driver, String expectedTitle) {

		if(driver.getTitle().equals(expectedTitle)) {
			extent.log(LogStatus.PASS, "Check page title", "Page title is " + expectedTitle);
		} else {
			extent.log(LogStatus.FAIL, "Check page title", "Incorrect login page title " + driver.getTitle());
		}
	}

	public static void checkErrorMessage(WebDriver driver, String expectedMessage) {

		String errorMessage = driver.findElement(By.className("error")).getText();

		if(errorMessage.equals(expectedMessage)) {
			extent.log(LogStatus.PASS, "Check error message", "Error message is " + expectedMessage);
		} else {
			extent.log(LogStatus.FAIL, "Check error message","View details below:",createScreenshot(driver));
		}
	}
}

As you can see, using ExtentReports is very straightforward. All we need to do is initialize the report by specifying:

  • The location where the report needs to be stored
  • If any existing reports with the same name should be overwritten
  • Whether the tests in the report should appear in chronological (DisplayOrder.BY_OLDEST_TO_LATEST) or antichronological order
  • Whether the grid type used for the results should be standard (GridType.STANDARD) or using the Masonry framework (GridType.MASONRY)

With .config().documentTitle(“Your report title”) you can set the HTML document title for your report.

We can also specify a custom header using .config().reportHeadline(“place header here”). This header can also contain HTML code, which gives you a wide array of options for creating a nice looking header for your report.

For every test, we start a test-specific report using .startTest(), and we end recording reporting events using .endTest(). .startTest() takes two parameters, the first is the test name or identifier, the second is a description that is added to the report as we will see. .endTest() ends the report activities for the test that has been started earlier. As of version 1.0, explicitly ending a test using .endTest() is no longer required when you want to start a new test.

Logging actual events is straightforward as well using the .log() method. Logging events can be created on six different levels (their use as presented here are suggestions only):

  • PASS for checks that are executed with a positive result
  • ERROR for logging any (non-fatal) error that occurs during test execution
  • WARNING for logging warnings
  • FAIL for checks that are executed with a negative result
  • INFO for logging additional info relevant to the test (or for debugging purposes)
  • FATAL for logging fatal errors occurring during test execution

Since we can include HTML markup everywhere in the report, we can also add screenshots wherever we want. To do this, all we need to do is to add a slightly modified version of the screenshot method I introduced here:

public static String createScreenshot(WebDriver driver) {

	UUID uuid = UUID.randomUUID();

	// generate screenshot as a file object
	File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
	try {
		// copy file object to designated location
		FileUtils.copyFile(scrFile, new File(reportLocation + imageLocation + uuid + ".png"));
	} catch (IOException e) {
		System.out.println("Error while generating screenshot:\n" + e.toString());
	}
	return imageLocation + uuid + ".png";
}

Note that I’ve predefined the report folder (an absolute path) and image subfolder (a subdirectory of the report location) somewhere else in the code. This method is called in the example above when we log an error and want to have a screenshot added to the report.

The result can be viewed here (the link to the screenshot is in the results for the second test). The same report using the Masonry framework can be viewed here. You’re free to play around with the various buttons to filter, expand and collapse test results and change the overall layout of the report a bit to have a look at the various display options.

More configuration options
Apart from the options already used in the examples above, ExtentReports offers a couple of other useful features. If you really want to give your HTML reports a customized look, you can apply your own specific CSS simply by specifying it during report initialization as follows:

extent.config().addCustomStylesheet("C:\\path\\to\\yourcustomcss.css");

Alternatively, you can use inline style definitions as follows:

String style = "p{font-size:20px;}";
extent.config().addCustomStyles(style);

You can also add your own JavaScript code to your report:

extent.config().insertJS("$('.test').click(function(){ alert('test clicked'); });");

You can also disable the footer that is displayed at the bottom of the page:

extent.config().removeExtentFooter();

You can also include a screenshot in the report without having to log a test step:

extent.attachScreenshot(createScreenshot(driver),"This is a sample screenshot without an accompanying log step");

Finally, you can exchange the standard icons for any other icon included in the FontAwesome library:

extent.config().statusIcon(LogStatus.PASS, "check-circle");

Since version 1.4, a lot of new features have been added. For the complete documentation please review the usage documentation at http://relevantcodes.com/extentreports-documentation/.

Further notes
As you have seen in this post, ExtentReports is a very useful library for quick generation of great looking HTML reports. Although ExtentReports is labeled as a solution for generating HTML reports for Selenium tests, it’s a generic solution that can be applied easily to other test frameworks, as long as they’re built in Java.

Thanks again to Anshoo Arora for pointing me to ExtentReports.

241 thoughts on “Creating HTML reports for your Selenium tests using ExtentReports

  1. Bas

    You have written such a wonderful review, you have shown each and every aspect of it so well. I like your image solution, I am sure a lot of users are going to adapt it, myself included.

    I will research showing the default link as you have shown in this article as a in-container preview. I have added the example here for ‘Test 1 – Image’ and it works for images posted using the log method: http://relevantcodes.com/ExtentReports/Extent.html

    extent.log(LogStatus.INFO, “Img”, “Image example:”, “C:\\img.png”);

    Thank you.

    • Hi Anshoo,

      you’re welcome! I think the ability to add screenshots is definitely something that your users might find useful. The sample you provided on your website looks good! I’ll keep watching your ExtentReport updates.

  2. Hi Bas,

    Sorry to ask a dumb question. I tried different ways to write a dependency in POM.xml for Extentreport.
    The dependency that i have tried is as below…

    com.relevantcodes
    extentreports-java
    1.1

    But i keep getting this error (Missing artifact com.relevantcodes:extentreports-java:jar:1.1).
    Your help is highly appreciated.

    Thanks
    Bon

  3. Hi Bon

    I believe you are getting this error because ExtentReports is currently not a maven project. and the artifact you’re listing cannot be found. I have just created the necessary info, can you please try again?

    com.relevantcodes
    extentreports
    jar

  4. Hi
    I would like to ask , how selenium compare between results from different browsers if I run my test against,
    I mean CSS automation testing , how I can by using selenium with c# or java compare between this different browsers . and get one report contains the results.
    Thanks in advance

    • Hi Anas,

      as far as I know Selenium can’t actively compare test results from different browsers. What you can do is the following:

      * Start a new report using extent.init(“/path/to/report”, true, DisplayOrder.BY_OLDEST_TO_LATEST);
      * Start a test against Firefox (or your browser of choice) and have ExtentReports gather and display the results
      * Start a second test that executes the same steps against Chrome (or your browser of choice) and have ExtentReports gather and display the results

      Test results for both tests should now end up in the same report. If both tests succeed, you’re OK. If one of the tests fails, then there might be a compatibility issue.

      Hope that helps.

  5. Hi Bas,

    Good Day !

    I recently came across your awesome selenium reporting stuff and tried to make use of your API in my selenium automation project.

    I could able to integrate your code and see the test results in nice HTML format.

    The problem that I am facing is I am running the tests in multi thread so what it happens the steps that im logging in different selenium tests are showing under the test which is last running thread. extent.log() showing under one test not in respective test cases. Please guide me how handle it.

    • Hi Ramkumar,

      first of all: I didn’t create ExtentReports, those credits go to Anshoo Aurora!

      I think I know what the problem is.. In my code sample, I declared the ExtentReports instance as static. In your case (and maybe even in general), I think it’s better to instantiate the ExtentReports class within the main method like this:

      public class SeleniumTest {

      static WebDriver driver = new FirefoxDriver();

      static String reportLocation = “C:\\Tools\\reports\\”;
      static String imageLocation = “images/”;

      public static void main (String args[]) {

      ExtentReports extent = ExtentReports.get(SeleniumTest.class);
      extent.init(reportLocation + “ScreenshotReport.html”, true, DisplayOrder.BY_OLDEST_TO_LATEST);

      The only thing you also need to change in this case is that you need to pass the extent variable to all helper methods (if you’re following the code example I gave in my post). I got this to work but I can’t test it with multithreaded tests here. Could you please let me know if that works?

      And also, don’t forget to use different file names for your report for different tests, that helps as well 🙂

      • Hi Bas,

        I am trying to implement the extent report to our framework. Thanks for the nice information.

        In my framework I have initiating 3 threads with different browsers, it works fine until it launches the browser window and get the desired address but extent reports fails to log the status of the tests though I am passing extent variable to all the helper classes. I get the following error while doing this, please help.

        Exception in thread “Thread-0” java.lang.ArrayIndexOutOfBoundsException: -1
        at com.relevantcodes.extentreports.ExtentReports.callerClass(ExtentReports.java:335)
        at com.relevantcodes.extentreports.ExtentReports.log(ExtentReports.java:136)
        at com.relevantcodes.extentreports.ExtentReports.log(ExtentReports.java:152)
        at ExtentReportsDemo.checkTitle(ExtentReportsDemo.java:90)
        at ExtentReportsDemo.runPositiveTest(ExtentReportsDemo.java:58)
        at test$1.run(test.java:41)
        at java.lang.Thread.run(Unknown Source)

        Thanks,
        Prasad

        • Hi Prasad, I’ll look into that when I return from holiday somewhere next week. Or maybe Anshoo will read this in the meantime and provide you with answer.

        • package com.tos.utilities;
          import org.apache.poi.hssf.usermodel.HSSFCellStyle;
          import org.apache.poi.hssf.usermodel.HSSFDateUtil;
          import org.apache.poi.hssf.util.HSSFColor;
          import org.apache.poi.ss.usermodel.Cell;
          import org.apache.poi.ss.usermodel.CellStyle;

          import org.apache.poi.ss.usermodel.IndexedColors;
          import org.apache.poi.xssf.usermodel.*;

          import java.io.*;
          import java.util.Calendar;

          public class ExcelUtil {

          public String path;
          public FileInputStream fis = null;
          public FileOutputStream fileOut =null;
          private XSSFWorkbook workbook = null;
          private XSSFSheet sheet = null;
          private XSSFRow row =null;
          private XSSFCell cell = null;

          public ExcelUtil(String path) {

          this.path=path;
          try {
          fis = new FileInputStream(path);
          workbook = new XSSFWorkbook(fis);
          sheet = workbook.getSheetAt(0);
          fis.close();
          } catch (Exception e) {
          System.out.println(“Xls file not found on path ” +path);
          e.printStackTrace();
          }

          }
          // returns the row count in a sheet
          public int getRowCount(String sheetName){
          int index = workbook.getSheetIndex(sheetName);
          if(index==-1)
          return 0;
          else{
          sheet = workbook.getSheetAt(index);
          int number=sheet.getLastRowNum()+1;
          return number;
          }

          }

          // returns the data from a cell
          public String getCellData(String sheetName,String colName,int rowNum){
          try{
          if(rowNum <=0)
          return "";

          int index = workbook.getSheetIndex(sheetName);
          int col_Num=-1;
          if(index==-1)
          return "";

          sheet = workbook.getSheetAt(index);
          row=sheet.getRow(0);
          for(int i=0;i<row.getLastCellNum();i++){
          //System.out.println(row.getCell(i).getStringCellValue().trim());
          if(row.getCell(i).getStringCellValue().trim().equals(colName.trim()))
          col_Num=i;
          }
          if(col_Num==-1)
          return "";

          sheet = workbook.getSheetAt(index);
          row = sheet.getRow(rowNum-1);
          if(row==null)
          return "";
          cell = row.getCell(col_Num);

          if(cell==null)
          return "";
          //System.out.println(cell.getCellType());
          if(cell.getCellType()==Cell.CELL_TYPE_STRING)
          return cell.getStringCellValue();
          else if(cell.getCellType()==Cell.CELL_TYPE_NUMERIC || cell.getCellType()==Cell.CELL_TYPE_FORMULA ){

          String cellText = String.valueOf(cell.getNumericCellValue());
          if (HSSFDateUtil.isCellDateFormatted(cell)) {
          // format in form of M/D/YY
          double d = cell.getNumericCellValue();

          Calendar cal =Calendar.getInstance();
          cal.setTime(HSSFDateUtil.getJavaDate(d));
          cellText =
          (String.valueOf(cal.get(Calendar.YEAR))).substring(2);
          cellText = cal.get(Calendar.DAY_OF_MONTH) + "/" +
          cal.get(Calendar.MONTH)+1 + "/" +
          cellText;

          //System.out.println(cellText);

          }

          return cellText;
          }else if(cell.getCellType()==Cell.CELL_TYPE_BLANK)
          return "";
          else
          return String.valueOf(cell.getBooleanCellValue());

          }
          catch(Exception e){

          e.printStackTrace();
          return "row "+rowNum+" or column "+colName +" does not exist in xls";
          }
          }

          // returns the data from a cell
          public String getCellData(String sheetName,int colNum,int rowNum){
          try{
          if(rowNum <=0)
          return "";

          int index = workbook.getSheetIndex(sheetName);

          if(index==-1)
          return "";

          sheet = workbook.getSheetAt(index);
          row = sheet.getRow(rowNum-1);
          if(row==null)
          return "";
          cell = row.getCell(colNum);
          if(cell==null)
          return "";

          if(cell.getCellType()==Cell.CELL_TYPE_STRING)
          return cell.getStringCellValue();
          else if(cell.getCellType()==Cell.CELL_TYPE_NUMERIC || cell.getCellType()==Cell.CELL_TYPE_FORMULA ){

          String cellText = String.valueOf(cell.getNumericCellValue());
          if (HSSFDateUtil.isCellDateFormatted(cell)) {
          // format in form of M/D/YY
          double d = cell.getNumericCellValue();

          Calendar cal =Calendar.getInstance();
          cal.setTime(HSSFDateUtil.getJavaDate(d));
          cellText =
          (String.valueOf(cal.get(Calendar.YEAR))).substring(2);
          cellText = cal.get(Calendar.MONTH)+1 + "/" +
          cal.get(Calendar.DAY_OF_MONTH) + "/" +
          cellText;

          // System.out.println(cellText);

          }

          return cellText;
          }else if(cell.getCellType()==Cell.CELL_TYPE_BLANK)
          return "";
          else
          return String.valueOf(cell.getBooleanCellValue());
          }
          catch(Exception e){

          e.printStackTrace();
          return "row "+rowNum+" or column "+colNum +" does not exist in xls";
          }
          }

          // returns true if data is set successfully else false
          public boolean setCellData(String sheetName,String colName,int rowNum, String data){
          try{
          fis = new FileInputStream(path);
          workbook = new XSSFWorkbook(fis);

          if(rowNum<=0)
          return false;

          int index = workbook.getSheetIndex(sheetName);
          int colNum=-1;
          if(index==-1)
          return false;

          sheet = workbook.getSheetAt(index);

          row=sheet.getRow(0);
          for(int i=0;i<row.getLastCellNum();i++){
          //System.out.println(row.getCell(i).getStringCellValue().trim());
          if(row.getCell(i).getStringCellValue().trim().equals(colName))
          colNum=i;
          }
          if(colNum==-1)
          return false;

          sheet.autoSizeColumn(colNum);
          row = sheet.getRow(rowNum-1);
          if (row == null)
          row = sheet.createRow(rowNum-1);

          cell = row.getCell(colNum);
          if (cell == null)
          cell = row.createCell(colNum);

          // cell style
          //CellStyle cs = workbook.createCellStyle();
          //cs.setWrapText(true);
          //cell.setCellStyle(cs);
          cell.setCellValue(data);

          fileOut = new FileOutputStream(path);

          workbook.write(fileOut);

          fileOut.close();

          }
          catch(Exception e){
          e.printStackTrace();
          return false;
          }
          return true;
          }

          // returns true if data is set successfully else false
          public boolean setCellData(String sheetName,String colName,int rowNum, String data,String url){
          //System.out.println("setCellData setCellData******************");
          try{
          fis = new FileInputStream(path);
          workbook = new XSSFWorkbook(fis);

          if(rowNum<=0)
          return false;

          int index = workbook.getSheetIndex(sheetName);
          int colNum=-1;
          if(index==-1)
          return false;

          sheet = workbook.getSheetAt(index);
          //System.out.println("A");
          row=sheet.getRow(0);
          for(int i=0;i<row.getLastCellNum();i++){
          //System.out.println(row.getCell(i).getStringCellValue().trim());
          if(row.getCell(i).getStringCellValue().trim().equalsIgnoreCase(colName))
          colNum=i;
          }

          if(colNum==-1)
          return false;
          sheet.autoSizeColumn(colNum); //ashish
          row = sheet.getRow(rowNum-1);
          if (row == null)
          row = sheet.createRow(rowNum-1);

          cell = row.getCell(colNum);
          if (cell == null)
          cell = row.createCell(colNum);

          cell.setCellValue(data);
          XSSFCreationHelper createHelper = workbook.getCreationHelper();

          //cell style for hyperlinks
          //by default hypelrinks are blue and underlined
          CellStyle hlink_style = workbook.createCellStyle();
          XSSFFont hlink_font = workbook.createFont();
          hlink_font.setUnderline(XSSFFont.U_SINGLE);
          hlink_font.setColor(IndexedColors.BLUE.getIndex());
          hlink_style.setFont(hlink_font);
          //hlink_style.setWrapText(true);

          XSSFHyperlink link = createHelper.createHyperlink(XSSFHyperlink.LINK_FILE);
          link.setAddress(url);
          cell.setHyperlink(link);
          cell.setCellStyle(hlink_style);

          fileOut = new FileOutputStream(path);
          workbook.write(fileOut);

          fileOut.close();

          }
          catch(Exception e){
          e.printStackTrace();
          return false;
          }
          return true;
          }

          // returns true if sheet is created successfully else false
          public boolean addSheet(String sheetname){

          FileOutputStream fileOut;
          try {
          workbook.createSheet(sheetname);
          fileOut = new FileOutputStream(path);
          workbook.write(fileOut);
          fileOut.close();
          } catch (Exception e) {
          e.printStackTrace();
          return false;
          }
          return true;
          }

          // returns true if sheet is removed successfully else false if sheet does not exist
          public boolean removeSheet(String sheetName){
          int index = workbook.getSheetIndex(sheetName);
          if(index==-1)
          return false;

          FileOutputStream fileOut;
          try {
          workbook.removeSheetAt(index);
          fileOut = new FileOutputStream(path);
          workbook.write(fileOut);
          fileOut.close();
          } catch (Exception e) {
          e.printStackTrace();
          return false;
          }
          return true;
          }
          // returns true if column is created successfully
          public boolean addColumn(String sheetName,String colName){
          //System.out.println("**************addColumn*********************");

          try{
          fis = new FileInputStream(path);
          workbook = new XSSFWorkbook(fis);
          int index = workbook.getSheetIndex(sheetName);
          if(index==-1)
          return false;

          XSSFCellStyle style = workbook.createCellStyle();
          style.setFillForegroundColor(HSSFColor.GREY_40_PERCENT.index);
          style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);

          sheet=workbook.getSheetAt(index);

          row = sheet.getRow(0);
          if (row == null)
          row = sheet.createRow(0);

          //cell = row.getCell();
          //if (cell == null)
          //System.out.println(row.getLastCellNum());
          if(row.getLastCellNum() == -1)
          cell = row.createCell(0);
          else
          cell = row.createCell(row.getLastCellNum());

          cell.setCellValue(colName);
          cell.setCellStyle(style);

          fileOut = new FileOutputStream(path);
          workbook.write(fileOut);
          fileOut.close();

          }catch(Exception e){
          e.printStackTrace();
          return false;
          }

          return true;

          }
          // removes a column and all the contents
          public boolean removeColumn(String sheetName, int colNum) {
          try{
          if(!isSheetExist(sheetName))
          return false;
          fis = new FileInputStream(path);
          workbook = new XSSFWorkbook(fis);
          sheet=workbook.getSheet(sheetName);
          XSSFCellStyle style = workbook.createCellStyle();
          style.setFillForegroundColor(HSSFColor.GREY_40_PERCENT.index);
          XSSFCreationHelper createHelper = workbook.getCreationHelper();
          style.setFillPattern(HSSFCellStyle.NO_FILL);

          for(int i =0;i<getRowCount(sheetName);i++){
          row=sheet.getRow(i);
          if(row!=null){
          cell=row.getCell(colNum);
          if(cell!=null){
          cell.setCellStyle(style);
          row.removeCell(cell);
          }
          }
          }
          fileOut = new FileOutputStream(path);
          workbook.write(fileOut);
          fileOut.close();
          }
          catch(Exception e){
          e.printStackTrace();
          return false;
          }
          return true;

          }
          // find whether sheets exists
          public boolean isSheetExist(String sheetName){
          int index = workbook.getSheetIndex(sheetName);
          if(index==-1){
          index=workbook.getSheetIndex(sheetName.toUpperCase());
          if(index==-1)
          return false;
          else
          return true;
          }
          else
          return true;
          }

          // returns number of columns in a sheet
          public int getColumnCount(String sheetName){
          // check if sheet exists
          if(!isSheetExist(sheetName))
          return -1;

          sheet = workbook.getSheet(sheetName);
          row = sheet.getRow(0);

          if(row==null)
          return -1;

          return row.getLastCellNum();

          }
          //String sheetName, String testCaseName,String keyword ,String URL,String message
          public boolean addHyperLink(String sheetName,String screenShotColName,String testCaseName,int index,String url,String message){
          //System.out.println("ADDING addHyperLink******************");

          url=url.replace('\\', '/');
          if(!isSheetExist(sheetName))
          return false;

          sheet = workbook.getSheet(sheetName);

          for(int i=2;i<=getRowCount(sheetName);i++){
          if(getCellData(sheetName, 0, i).equalsIgnoreCase(testCaseName)){
          //System.out.println("**caught "+(i+index));
          setCellData(sheetName, screenShotColName, i+index, message,url);
          break;
          }
          }

          return true;
          }
          public int getCellRowNum(String sheetName,String colName,String cellValue){

          for(int i=2;i<=getRowCount(sheetName);i++){
          if(getCellData(sheetName,colName , i).equalsIgnoreCase(cellValue)){
          return i;
          }
          }
          return -1;

          }

          // to run this on stand alone
          public static void main(String arg[]) throws IOException{

          //System.out.println(filename);
          ExcelUtil datatable = null;

          datatable = new ExcelUtil("H:\\Student_Selenium_Workspaces\\Framework_Weekend\\src\\Framework_XL_Files\\Controller.xlsx");
          for(int col=0 ;col< datatable.getColumnCount("TC5"); col++){
          System.out.println(datatable.getCellData("TC5", col, 1));
          }
          }

          }

  6. 1. How to change the title ‘extent-report’ on the report landing page.
    2. The dashboard charts require internet connection. They are not visible when we are offline. How can we handle this issue.
    Please help.

  7. Hi Rohit

    1. See Bas’ response above
    2. This is not possible as the visualization library must be downloaded dynamically for charts to become available so you cannot view them offline

    Cheers

    Anshoo

    • Hi Anshoo,

      Thanks for the immediate reply. For the mentioned issues-

      Issue 1. Can you put the id attribute for the title div or add a function to change/modify the title.

      Issue 2: Can’t we create the reports which won’t require to download the library.
      Cant we put the code of the visualization library in the extent-report code statically, so no need to download them.
      Can’t we use the java API of the charts.?

  8. Pingback: ExtentReports for Selenium WebDriver Reporting

  9. Hi Bas/Anshoo,

    Need some help on taking screenshots.
    Can you help or Can I get your source code of taking active sceen’s screenshot.
    Waiting for your help.

    Thanks,
    Rohit

    • Hi Rohit,

      the code I used is included in this post, please take a look at the code sample for the createScreenshot method. It takes a screenshot, saves it as .png and returns the file location where it’s stored.

      Does that help?

      • Thanks Bas….If you can provide testng.xml support I believe lot of people can use your reports.. As most of the people use testng.xml for their automation.

  10. If i run same test multiple times…5-6 times I am not getting Pass or Fail Status in reports..
    Is there a way to attach the screen shots for you.?

    • public class Testing {
      public static final ExtentReports extent = ExtentReports.get(Testing.class);
      // static WebDriver driver = new FirefoxDriver();
      static String reportLocation = “C:\\Tools\\reports1\\”;
      @BeforeSuite
      public static void beforeTestSuite(){

      extent.init(reportLocation + “CD_Testing_Report.html”, false, DisplayOrder.BY_LATEST_TO_OLDEST, GridType.MASONRY);
      extent.config().displayTestHeaders(true);

      extent.config().documentTitle(“Sample ExtentReports report”);

      extent.config().reportHeadline(“CD Automation Report“);

      extent.startTest(“CD::S2C”,”CD S2C Submission Automation Report “);
      }

      @BeforeMethod
      public void beforeMethod() throws Exception {

      }

      @Test
      public void CDDashBoardclicks() throws Exception {

      extent.log(LogStatus.FAIL, “S2C”, “S2C Request was not submitted Successfully”);

      }

      @Test
      public void validatePatchfileisempty() throws Exception {
      extent.log(LogStatus.PASS, “S2C”, “S2C Request Paramters was validated Successfully”);
      }

      @AfterMethod
      public void afterMethod() throws Exception {

      }

      }

  11. Hi Bas,
    I am from south india and i am learning Test Automation using selenium webdriver from internet.I have two things to say:
    1)extent.config().displayTestHeaders(true);
    This is showing as deprecated in my Eclipse.
    2)I believe there is an error in your code.
    In the return statement inside createScreenshot Method
    It should be return reportLocation + imageLocation + uuid + “.png”;
    instead of imageLocation + uuid + “.png”; right?

    • Hi Sherin,

      1) You’re right, that one is deprecated. I try to keep this post in sync with the latest version of ExtentReports, but sometimes errors like these slip through. Thanks for mentioning this, I have removed this line from the sample code in my post.
      2) I did this on purpose to get relative links in the report rather than absolute links. This makes it easier to distribute reports and underlying image folders. Feel free to adapt it to your needs though.

      • Hi Bas,
        I really loved this program.I believe programming is something which should come naturally right?
        Anyway i have a few queries if you don’t mind.
        1)Why did you declared the variables extent,driver,reportLocation,imageLocation all as static ‘whereas’ extent as ‘static final’?-something to did with the functions you wrote below?
        2)i believe you mentioned the text ‘check error message’ in the generated extent report that must be-‘The email and password could not be verified’ displayed in the screenshot right?
        But if i have to display the same error
        message in my extent report what should i use driver.get Error() or something like that?

        • Hi Sherin,

          1) No reason, really. You could declare the extent variable as static just as well. Please do keep in mind that I’m not a programmer myself so it’s very possible that I make mistakes or don’t do things the proper way. What I can guarantee though is that my examples work or at least work on my machine.

          2) That error message is the text in a text field on the page you see in the screenshot. It is retrieved using

          String errorMessage = driver.findElement(By.className(“error”)).getText();

          I used this because that text field is the only element on the page that is in the “error” class.

          • ok,but why did you gave both LogStatus.PASS and LogStatus.FAIL inside the function checkErrorMessage()?
            I mean any way the login details are incorrect.so there will be an error,oh you expected the error message to be ‘Incorrect Credentials’ and it turned out to be ‘The username and password could not be verified’ displayed in the screenshot right?so even while running a negative test we have to give both pass and fail status may be that is the standard way to do it right?

          • You’re right. The test (which again is just an example) checks whether the displayed error message equals an expected message. If it does, the test passes, even though it’s a negative test (i.e., not a happy flow scenario).

  12. i just know python programming language. is this tool have a python alternative? (python library) or something like this?

    • Hi Amir,

      No, at the moment there’s only the Java version. A .NET version might be coming sooner or later but I don’t know whether a Python version is planned.

      The source code is on GitHub so you could try and convert it yourself though.

  13. Is there a way to capture multiple screen shot for a single test? Could you please provide me a sample code snippet if there is any way to achieve this?

    Thanks in advance.

  14. Hi Bas/Anshoo,

    I was trying my hands with Extent Reports. With version 1.41 only, I was successfully able to use it. However, I could not write this statement “ExtentReports extent = ExtentReports.get(SeleniumTest.class);” using the maven version of Extent reports.
    Also I want to configure it with Jenkins, do we have support for jenkins??

  15. Hi Bas,

    Great writeup. Led me to using Extent Reports and I’m very happy with the outcome. I’m using it with TestNG and find it much more appealing than the standard reporting output.

    Do you know if there is any built-in way to customize the report’s ‘Quick Test Summary’ (or create a new summary table) to show summary stats for each Category or test class (rather than each individual test)?

    Also, is there a way to get the filters in the Detail section to work in tandem (e.g. filter by Result AND Category)? Currently the tests can only be filtered by the latest filter selection. It would be useful for me to only see tests that meet both criteria (i.e. ‘Errors’ in the ‘Internet Exploder’ category).

    Again, great post (and excellent work, Anshoo)

    Thanks

  16. Hi Bas,
    Why did you use this code and what it does?
    -static final ExtentReports extent = ExtentReports.get(ExtentReportsDemo.class);

    • That line initializes the report for the current class (in my case it’s called ExtentReportsDemo. It’s only required in version 1.xx of ExtentReports though, if you’re using version 2.xx you can initialize a report using

      extent = new ExtentReports(“file-path”, true);

      • Bas,
        I have a doubt.Testng is a framework right?i believe so is selenium webdriver.But ExtentReport is a Report Generating tool right?So a framework plus a report generating tool is the best option to automate a full website by writing script right?if that is the case we have to surely inculde Testng while using ExtentReports right?

        • I wouldn’t get too hung up about the details. Just choose what works best in your case.

          If you want to automate tests for a website, choose Selenium. If you use Selenium, you want some kind of reporting. You could use TestNG for that, or ExtentReports.

  17. Bas,
    thanks for such a good example, my question is about if the extenreports is emailable. i want to be able to email the results to members on my team.

    • Hi Hanifa, that’s not included in the ExtentReports library itself, but you could pretty easily add an ’email report’ step with a little bit of extra code. There’s lots of examples on the net on how to email a file.

  18. Pingback: Selenium HTML result reporting using ExtentReports 2.X – Software QA and Validation

  19. Can i keep image as a title of the report .
    eg, I want to include company name and logo in title field .

    If yes can you please give command or example how to do it .

  20. Hi,

    I am not able to create Extended Masonry Selenium Report with above Code.Can you please provide me correct code through which I can design Masonry Selenium Reports.

    Thanks
    Gaurav

  21. Q> Search does not seem to work . I tried searching exact test case name , with ” * * ” , any word from test case name .

  22. Hi

    My test steps are getting appended automatically with text “[RemoteTestNG.initAndRun]”
    So my test step looks like this
    “[RemoteTestNG.initAndRun] Any StepName”

    Please help me overcome this issue

  23. Pingback: Another Testers blog – ExtentReports review

  24. Hi bas, I am using extent reports for my java selenium project. I am using 2.10 extent reporting jars. I do not get start time, end time, report name, report title and footer in my reports. Please send us the sample script or suggest me where to make the changes to look my reports better.

  25. How to save screenshots so they will be reflected in any form of report itself? When I look at the report itself from my machine, where I run tests, I can clearly see screenshots, but when I attached html report to a Jira, my manager doesn’t see screenshots, only test steps.

    • Hi Aznariy,

      the screenshots are separate .png (or .jpg) files and should therefore also be uploaded to Jira. The reports only contain links to those image files (as is usual in HTML).

  26. Hi Bas, I did it first, downloaded pictures together with the report to Jira, but report didn’t reflect them when I tried to open it from my co-worker machine. I guess the problem is report provide absolute paths links of screenshots on my machine, therefore nobody except me can see them. My question is, am I able to change the paths in report html itself? Or links will always create an absolute paths to the folder on my machine? Thanks for the response.

    • As far as I know (and supported by this page) you are in full control of the paths to the images yourself, so you can easily include relative paths to the images.

  27. Hi Bas,

    Kindly share workspace with code for downloading.So that we can generate the reports(Which you did for HTML report generation in the previous post).Kindly do it fast.

    -TR.

    • Depending on where you want it exactly, and given your ExtentReports instance is called ‘extent’, you can use

      extent.config().reportHeadline("INSERT LINK TO IMAGE HERE");

      or

      extent.config().reportName("INSERT LINK TO IMAGE HERE");

      Use standard HTML ‘img src=’ and a link to your logo to insert it in your report. Easy as pie.

  28. html
    body

    a href=”default”
    img src=”TR02.png” alt=”HTML tutorial” style=”width:42px;height:42px;border:0″
    /a

    /body
    /html

    Saved as cmg1.html in d:/Ereports
    image is also on same page.

    extent.config.reportName(d:/Ereports/HTML tutorial)

    but extent.reportName is accepting only string.

    extent.config.reportName(“Selenium”);
    kindly guide me.

  29. If TR02.png is the image you want to use, just do

    extent.config().reportName(“< i m g s r c = '/path/to/TR02.png / >‘ “) (without the spaces)

  30. Hi Bas, Extent Report is great..
    My issue is, I am adding an extension to the browser, I have to click on the “add extension ” button in the pop up. but switchTo.alert() is not at all detecting the pop up. driver.getTitle() suppose to throw exception when there is an alert but in this case I am getting the title name and no alert exception 🙁 🙁 .. although all other places it worked. what could be the reason. Please help!!

    • It seems like this specific popup is not a JavaScript popup like the other ones but a different HTML element altogether. Can you inspect its properties using for example FireBug or the Chrome developer tools? Maybe that gives you a clue as to how to handle this popup.

  31. Can we get a sample code, showing how the different parameters can be populated in the report. I am not getting enough code in C#. Most of them are in Java. Please help

    • Hi Aman, I’d be happy to give you some sample code but what do you mean by ‘how the different parameters can be populated’? Which parameters are you talking about?

      • Hi Bas, Thanks for your quick response.

        It will be very helpful, if I can get some code demonstrating:

        1. How to populate all possible information in the report. For example: I am able to populate the description and Author name . Is there any other information that we can populate ?

        2. Best way to code in C#, for multiple test cases

        3. How to get the best view of the Extent report with Graphs? Or any other view.

        4. How to report skipped test cases.

        I am after pretty much everything else we can use, from reporting point of view.

        Thanks in advance.

        Aman

  32. Hi Bas
    Read your interesting articles which was very useful thanks for that but facing one problem, which might be resolved by you.
    Using selenium i want to create HTML report where i can store screenshots.
    I am able to get screenshots and saved into the directory folder but instead of that i want them to paste it into my HTML reports Using java in eclipse.

    That will be very thankful if you will be able to help me out with this problem.

    • Hi Ankit, I think there’s an example of how to do that in one of my posts. The ExtentReports docs also show you how to do just that.. Let me know if you found the reference

      • Yes, Thanks Bas for your information. I found the relevant solution to that. Now, Started using ExtentReports which is very helpful for generating html reports in a formatted way.

  33. Code you have used bas is using ExtentReports Jar version 1.41 Which is not supported in version 2.40.
    Same code is not working with ExtentReports 2.40 Jar file.

    • True. I wrote this blog post when 1.41 was the latest version. I’m afraid I am not going to update the post and the code included anymore, but there are a lot of other good references on ExtentReports out there.

  34. Hi, I want to append the browser details (name, version) to the extent report for each test in the extent report table. Is this possible ? When I am execute the scripts on different browsers, it is hard to find what test is executed on which browser.

    • Hi, assuming you already know what browser you’re using at any given moment, you can add info to the report using ExtentReports.addSystemInfo(key,value);

      This is described in the online manual, by the way.

  35. Hi,
    I am trying to add screenshot in my report using relative path. I need to run my script using jenkins nd thats why i am using relative path for report and screenshots. Here is my code –

    logger.log(LogStatus.PASS, methodname + ” Add Attempt Success”);
    String image = this.captureScreenshot(driver, methodname + “Success”);
    String image1 = logger.addScreenCapture(image);
    logger.log(LogStatus.INFO, methodname + ” Screenshot: “, image1);
    logger.log(LogStatus.PASS, image1 , methodname + ” Screenshot: “);
    report.flush();

    public static String captureScreenshot(WebDriver driver, String screenshotName)
    {
    try {
    TakesScreenshot ts = (TakesScreenshot)driver;
    File source = ts.getScreenshotAs(OutputType.FILE);
    //
    String destold = “./target/runreport/”;
    String dest = destold + screenshotName + “.png”;
    File destination = new File(dest);
    FileUtils.copyFile(source,destination);
    System.out.println(“screenshot taken”);
    return dest;
    }
    catch (Exception e)
    {
    System.out.println(“Exception while taking a screensht” +e.getMessage());
    return e.getMessage();
    }
    }

    Above code worked fine with absolute path but its not working with relative path. Not sure what i am missing here.

    Any help would be appreciated. Thanks!

    • Is ./target/runreport/ the subfolder for your Jenkins workspace where the screenshots have to end up? I’ll have to take a look at my current project’s code later today, I use relative paths there as well and it works a charm.

      • I am using Intellij and ./target/runreport folder is maven target folder and currently points to my intellij project folder. Once i test it on my machine i will move everything to jenkins.

        do you mind checking your code and sharing the usage of relative path. Thanks!

        • Hmm.. seems I was wrong, I’m using absolute paths. You can try to convert the relative path to an absolute path using Path.getAbsolutePath(). You will have to convert the string containing the path to a Path object first though.

          By the way, this is how I’m doing it in my code (C#):

          string uuid = Guid.NewGuid().ToString();
          string fileName = uuid + “.png”;

          Screenshot screen = ((ITakesScreenshot)driver).GetScreenshot();
          screen.SaveAsFile(Constants.ReportDirectory + fileName, ImageFormat.Png);

          return fileName;

  36. Pingback: Selenium HTML result reporting using ExtentReports 2.X – QAValidation

  37. Hi,
    Is there anyway you can edit the HTML of the extent report to add in your own features? Such as I want to add in a legacy feature where from a click of a button you can open up a previous extent report html file from a previous test?
    Thanks.

    • Hi John, to be honest I’m not sure you can. Your best bet would probably be to contact Anshoo, he’s the creator of ExtentReports..

      • Hi Bas,

        Thanks for the reply. Would you have a contact for him? Is there anyway I could do it by adding the feature to my java class for reporting?

        Thanks.

        • Hi John,

          You can try relevantcodes.com/contact/

          As for your other question: I really haven’t got a clue, sorry!

          • No problem, Bas much appreciated. Its kind of a specific question so I understand.

            Thanks anyways, and great work on the article its very good and informative.

            Thanks,
            John.

  38. Hi , Using extent report i have generated the html report . Now i want to share my html report results with wider audience . is there a way to email the report or share the link ?

    • Not from within ExtentReports. But you can simply either email the HTML file and any associated screenshots by hand, have Jenkins or any other CI system you’re using take care of it or build a custom method or task that does so.

    • Hi Deepa,

      to be honest I have no idea, as I don’t have any hands-on experience with Groovy. However, I think I’ve read that Groovy supports importing of third-party Java libs without problems so I think it just might work.

  39. Hi,

    I am trying to run multiple test scripts using Extent Reports and generate a single report. Every time I am initialising the report class as “report=new ExtentReports(”
    C:/path/AutomationReport.html”);”. What happens is after all the script run only last script wiwill be updated in the report and only One test case PASS or FAIL result will be there. Please let me know how to append the same report for multiple test case runs ??

    Also Please provide me with the Documentation to convert the Extent Reports generated into a dashboard.

    Thanks in advance…

    • Hi Manju, sounds like you’re reinitializing the report for every test. To get all test results in a single report you only need to initialize it once before you start executing your tests (for example using @BeforeSuite in TestNG) and flush it once all tests are finished.

      • Thanks Bas ,

        Can you Please tell me How to do in Java . I am new to Java and learning this coding ..

        Also Can You please share any Document if u have for my refernece..

        Thanks in advance..

        • Hi Manju,

          Just do a search for TestNG examples and the use of @BeforeSuite and other annotations. Sure I can write you an example but you’ll learn a lot more from searching and experimenting yourself.

          I’ve used TestNG a lot in previous posts so the code projects that are included there might also give you some pointers.

  40. Hi Bas,

    Very useful post on ExtentReports but unfortunately i’m not able to execute the sample program shared here. I’m gettting error in the below statement.

    static final ExtentReports extent = ExtentReports.get(ExtentReportsDemo.class);

    I’m not getting the method ‘get’ listed in the suggestion drop down. Could you help me to solve this issue.

    Currently i’m using extentreports-java-v2.41.0

    Thanks in advance.

  41. Hi Bas,

    Please share if you have ExtentX documentation if you have any ? I am trying to convert my Extent Reports which is genarated to a Dashboard so wnated your help in configy=uring the same ..

    Thanks

  42. No Bas,

    I have not worked with Node js and MongoDB . Also I am not sure of the system requirements for setting this up.. So Looking out for guidance in this regard.

    Thanks

    • I haven’t either (at least not with MongoDB) but the instructions are fairly clear, aren’t they? Node is really lightweight and MongoDB too as far as I know so this should run on any fairly modern desktop or laptop..

  43. Pingback: Selenium HTML result reporting using ExtentReports 2.X – qavalidation

  44. Hi,

    While testing reporting of Extent Report version 2.41.0 and loading configuration information using load-extent.xml file I am getting following error.

    [javac] D:\Demos\VHospital\src\ExtentReport\ExtentManager.java:43: error: cannot find symbol
    [javac] Patient_extent.loadConfig(new File(“D:/Demos/VHospital/extent-config.xml”));
    [javac] ^
    [javac] symbol: method loadConfig(File)
    [javac] location: variable Patient_extent of type ExtentReports
    [javac] 1 error

  45. Hi Bas,
    I have started using extent report. It works fine only issue I am facing is that for each test case I have to start with Login method and I am using StartTest in login page. Issue here is that test case name is mention as Login Page and it will display each test case name as Login Page. Can you please let me know how can I overcome this that it should display different test case name?

    Thanks,
    Sachin

    • Hi Sachin,

      Is there any way you can do the StartTest() in a separate method, for example annotated with @BeforeTest or something like that? Do you use TestNG or JUnit or something similar?

      • Thanks Bas for quick reply. Yes I am using NUnit and I can use BeforeTest(). Still I am not sure how can I use StartTest with each test case name.
        e.g. Test case 1 –
        1) I am on login page
        2) I login using xyz
        3) I should see

        here test case name like Verify that displayed on home page

        Test case 2 –
        1) I am on login page
        2) I login using xyz
        3) I should have option of Inbox

        here test case name like Verify that Inbox is available to user.

        In both test case step 1 and 2 is common however mostly test case name changes based on verification step.
        This may be basic question but somehow I am unable to resolve it.

        Thanks,
        Sachin

        • Ah I see now. Just don’t do the StartTest() in the login. That’s bad design by the way, a login method should log you in, nothing else. So instead of

          TestMethod (
          1. Goto login (which also starts the test)
          2. Login
          3. Do check
          )

          do:

          TestMethod (
          1. Method for starting test
          2. Goto login
          3. Login
          4. Do check
          )

          I hope that horrible piece of pseudocode makes sense..

          • Thanks Bas. I understand your pseudocode and possibly tough to implement it with existing framework as it will need an update to all existing features file. Let me ask other question then if it make sense. We are already generating html report (might be NUnit default report). Is it possible to convert this (NUnit) HTML report into Extent Report. Might be something like creating object of NUnit HTML and passing it to Extent. This will save lot of time and effort.

  46. ExtentReports html report not showing skipped tests. Only showing Pass and Failed test cases in the report. How to include skips tests in ExtentReports ?

    Following is my after method which is executing after every test run

    @AfterMethod
    public void afterMethod(ITestResult result)
    {
    if (result.getStatus()==ITestResult.FAILURE){

    logger.log(LogStatus.FAIL,result.getThrowable());
    } else if (result.getStatus() == ITestResult.SKIP) {
    logger.log(LogStatus.SKIP,result.getThrowable());
    }else {
    logger.log(LogStatus.PASS, “Test passed”);
    }
    report.endTest(logger);
    report.flush();

    }

  47. Dear Anshoo/Bas,

    I need your help. I am trying to generate an HTML report using ExtentReports. Selenium Webdriver + Visual Studio.

    Right now I am able to generate a report, but whenever I am running the new test, it overwrites the old report with new one. I want to keep the records of all the old reports as well and want to generate new report after each execution in the same folder. Can you please help me?

    • Hi Pravek, you could do this by generating a unique name for every report (for instance using a Guid or a timestamp) and assigning it to you report on initialization.

  48. Thanks Bas for your reply, somehow I was able to generate unique reports using timestamp, but i ran into another problem here – I am trying to execute 2 test cases from visual studio and its generating 2 different reports for them. If possible could you please take a look at my code? basically, I want to generate a single report for both the test cases.

    TestCase#1 –

    using System;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using OpenQA.Selenium;
    using OpenQA.Selenium.Chrome;
    using OpenQA.Selenium.Support.UI;
    using log4net;
    using System.Configuration;
    using OpenQA.Selenium.Firefox;
    using OpenQA.Selenium.IE;
    using RelevantCodes.ExtentReports;

    namespace C_Online_2016
    {
    [TestClass]
    public class TestCase_17265
    {
    ExtentReports Reports;
    ExtentTest logger;
    public IWebDriver driver;
    String URL = ConfigurationManager.AppSettings[“URL”];
    String ExpctdPageTitle = “Welcome to Test Online”;
    String reportLocation = ConfigurationManager.AppSettings[“ReportLocation”];
    String reportName = ConfigurationManager.AppSettings[“ReportName”];

    [TestInitialize]
    public void Test_Setup()
    {
    String Browser = ConfigurationManager.AppSettings[“browser”];
    switch (Browser.ToLower())
    {
    case “chrome”:
    this.driver = new ChromeDriver();
    break;
    case “ie”:
    this.driver = new InternetExplorerDriver();
    break;
    case “firefox”:
    this.driver = new FirefoxDriver();
    break;
    }
    }

    [TestMethod]
    public void TestMethod17265()
    {
    C_Online_Consts constants = new C_Online_Consts(this.driver);

    String timeStamp = constants.GetTimestamp(DateTime.Now);

    Reports = new ExtentReports(reportLocation + reportName + timeStamp + “.html”, false);
    logger = Reports.StartTest(“TestMethod17265”);

    logger.Log(LogStatus.Info, “Browser started”);

    constants.NavigateToURL(URL);

    constants.Maximize();

    logger.Log(LogStatus.Info, “Checking the Title”);
    String Actual_PageTitle = constants.GetWelcomePageTitle();
    Assert.AreEqual(ExpctdPageTitle, Actual_PageTitle);
    }

    [TestCleanup]
    public void MyCleanUp()
    {
    driver.Close();
    Reports.EndTest(logger);
    logger.Log(LogStatus.Info, “************* End of TestCase_17265 execution **************”);
    Reports.Flush();
    }
    }
    }

    TestCase#2 –

    using System;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using OpenQA.Selenium;
    using OpenQA.Selenium.Chrome;
    using log4net;
    using System.Configuration;
    using OpenQA.Selenium.Firefox;
    using OpenQA.Selenium.IE;
    using RelevantCodes.ExtentReports;

    namespace C_Online_2016
    {
    [TestClass]
    public class TestCase_17289
    {
    ExtentReports Reports;
    ExtentTest logger;
    public IWebDriver driver;
    String URL = ConfigurationManager.AppSettings[“URL”];
    String ExpctdPageTitle = “Welcome to CRA Online”;
    String reportLocation = ConfigurationManager.AppSettings[“ReportLocation”];
    String reportName = ConfigurationManager.AppSettings[“ReportName”];

    [TestInitialize]
    public void Test_Setup()
    {
    String Browser = ConfigurationManager.AppSettings[“browser”];
    switch (Browser.ToLower())
    {
    case “chrome”:
    this.driver = new ChromeDriver();
    break;
    case “ie”:
    this.driver = new InternetExplorerDriver();
    break;
    case “firefox”:
    this.driver = new FirefoxDriver();
    break;
    }
    }
    [TestMethod]
    public void TestMethod17289()
    {
    C_Online_Consts constants = new C_Online_Consts(this.driver);

    String timeStamp = constants.GetTimestamp(DateTime.Now);
    Reports = new ExtentReports(reportLocation + reportName + timeStamp + “.html”, false);

    logger = Reports.StartTest(“TestCase_17289”);

    // Navigate to website
    constants.NavigateToURL(URL);
    logger.Log(LogStatus.Info, “Browser started”);

    // Maximize the driver window
    constants.Maximize();

    // Check for the application Title
    logger.Log(LogStatus.Info, “Checking the CRA Online welcome page title”);
    // Do something here

    // Click the Toggle fullscreen mode button
    logger.Log(LogStatus.Info, “Clicking Toggle fullscreen icon”);
    constants.ClickToggleFullScreen();
    logger.Log(LogStatus.Info, “Successfully clicked Toggle fullscreen icon”);
    }

    [TestCleanup]
    public void MyCleanUp()
    {
    driver.Close();
    Reports.EndTest(logger);
    logger.Log(LogStatus.Info, “************* End of TestCase_17289 execution **************”);
    Reports.Flush();

    }
    }
    }

    • Hi Pravek,

      you should move the creation of the Reports object to a ClassInitialize method. Now you’re running two tests, each creating their own report. That’s why you see two. See also here.

  49. Hi Bas, I am little confused here. In first test case I should add ClassInitialize method and create object of Reports? then in second test case also I need to add ClassInitialize method and create Report object?

    • No, you need to create a separate method that handles the report creation and annotate it with ClassInitialize to ensure it runs exactly once for the class containing your test methods. There should be plenty of examples online.

  50. Hi,

    I want to use extent Reports in my selenium C# automation .I need to convert the following code in java to c# . How to do it?
    does Extent Report will support c#

    static final ExtentReports logger = ExtentReports.get(classname.class);
    logger.init(“reports\\ExecutionReport.html”, true);
    logger.config().documentTitle(“ExecutionReport”);
    logger.config().useExtentFooter(false);
    logger.config().reportHeadline(” Execution Report Summary.”);
    logger.config().displayCallerClass(false);
    logger.config().reportTitle(” Execution”);

    • The full API for C# can be found on the ExtentReports web site. The commands are pretty much the same as for Java.

      Sure I could translate them for you but you won’t learn anything from that 😉

  51. Automation HTML test template for sample format:

    Automation Execution Report

    google.load(“visualization”, “1”, {packages:[“corechart”]});
    google.setOnLoadCallback(drawChart);

    function drawChart() {
    var pass = readTable(‘PASS’);
    var fail = readTable(‘FAIL’);
    var skip = readTable(‘SKIP’);

    var data = google.visualization.arrayToDataTable([
    [‘Total Testcases’, ’50’],
    [‘Pass’, pass],
    [‘Fail’, fail],
    [‘Skip’, skip]
    ]);

    var options = {
    title: ‘Graphical Test Report’,
    colors: [‘#339933’, ‘#FF0000’, ‘#FF9900’ ]
    };

    var chart = new google.visualization.PieChart(document.getElementById(‘piechart’));
    chart.draw(data, options);

    }

    function readTable(val) {

    var passTC =0, failTC =0, skipTC =0;
    //gets table
    var oTable = document.getElementById(‘myTable’);

    //gets rows of table
    var rowLength = oTable.rows.length;

    //loops through rows
    for (i = 0; i < rowLength; i++){

    //gets cells of current row
    var oCells = oTable.rows.item(i).cells;

    //gets amount of cells of current row
    var cellLength = oCells.length;

    //loops through each cell in current row
    for(var j = 0; j < cellLength; j++){

    // get your cell info here

    var cellVal = (oCells.item(j).innerHTML).trim();

    if(String(cellVal) == val)
    { passTC = passTC +1 ;

    }

    }

    }
    return passTC;
    }

    Test Summary

    Application Type :

    Time :

    S No
    Test Case ID
    Area
    Seals
    Diameter
    Status
    ScreenShot
    Comments

    ________________________________
    img {
    display: block;
    height: 100px;
    width: 300px;
    margin: auto;
    }

    p {
    text-align: center;
    font-family: Verdana, sans-serif;
    font-size: 18px;
    }

    #header {

    margin-right: 500px;
    border-radius: 5px;
    border: 1px solid #6495ED;
    background-color: #6495ED;
    padding: 5px 5px 5px 5px;
    height: 50px;
    width: 300px;
    text-align: center;
    font-size: 18px;
    font-family: Verdana, sans-serif;
    }

    #myTable{

    border: 1px solid Black;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    }

    th{
    text-align: center;
    font-family: Garamond, serif;
    font-size: 18px;
    background-color: #A7DBD8;
    text-align: center;
    }

    a {
    text-decoration: none;
    color: #3D59AB;
    font-family: Verdana, sans-serif;
    background-color: #FFFFFF;

    }

    span {
    font-weight: bold;
    font-size: 18px;
    font-family: Verdana, sans-serif;
    }

    #fail {

    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FF0040;
    }

    #pass {
    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FFFFFF;
    }

    #skip {
    background-color: #ff9900;

    }
    #sno{
    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FFFFFF;
    }

    #productType{
    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FFFFFF;
    }

    #appBG
    {
    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FFFFFF;
    }

    #area{
    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FFFFFF;

    }

    #tcid{
    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FFFFFF;
    }

    #seal{
    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FFFFFF;
    }

    #executionTime{

    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FFFFFF;
    }

    #status{
    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FFFFFF;
    }

    #dataCheck{
    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FFFFFF;
    }

    #dataMismatchYes{
    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FF0040;
    }
    #dataMismatchNo{
    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FFFFFF;
    }

    #details{

    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FFFFFF;
    }

    #screenshot{

    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FFFFFF;
    }
    #comments{

    border: 1px solid #6495ED;
    margin: auto;
    text-align: center;
    font-size: 14px;
    font-family: Verdana, sans-serif;
    background-color: #FFFFFF;
    }

  52. I have implemented .net plugin for extent report and it is working fine but it’s not generating the .html result file in the respective folder. Please respond.
    Thanks in advance

  53. Hi Bas,
    It wouldbe silly question but would be great help it you can help me out.
    I tried implementing extent report for multple test cases, but report are not getting generated .

    Code:
    public class SampleTc1
    {
    static WebDriver driver;
    static ExtentReports report;
    static ExtentTest logger;

    static void testcase1()
    {
    System.setProperty(“webdriver.chrome.driver”,”chromedriver.exe”);
    driver = new ChromeDriver();
    driver.get(“https://www.google.co.in”);
    logger.log(LogStatus.PASS, “This step is passed”);
    driver.close();
    }
    }

    public class SampleTc2
    {
    static WebDriver driver;
    static ExtentReports report;
    static ExtentTest logger;

    static void testcase2()
    {
    System.setProperty(“webdriver.chrome.driver”,”chromedriver.exe”);
    driver = new ChromeDriver();
    driver.get(“https://www.google.co.in”);
    logger.log(LogStatus.PASS, “This step is passed”);
    driver.close();
    }
    }

    Main Class:
    public class Maindriver {
    static WebDriver driver;
    static ExtentReports report;
    static ExtentTest logger;
    public static void main(String[] args) throws Exception {
    // TODO Auto-generated method stub
    report=new ExtentReports(“./Report/ExtentReport/ExecutionResult.html”, true);

    logger=report.startTest(“TC1”, “Testc Case1”);
    SampleTc1.testcase1();
    report.endTest(logger);

    logger=report.startTest(“TC2”, “Testc Case2”);
    SampleTc2.testcase2();
    report.endTest(logger);

    report.flush();
    }

    }

    After running no reports are getting generated and it is showing null ponter exception:
    Exception in thread “main” java.lang.NullPointerException
    at SmokeTest.SampleTc1.testcase1(SampleTc1.java:24)
    at SmokeTest.Maindriver.main(Maindriver.java:22)

  54. Hi Bas,

    When i am trying to use screenshot function in extend report. Screenshot of particular page is been taken… but when i see the html report by using extend report…..
    In that am seeing the path of the snapshot…whereas i should see the snapshot in html report as well..

    PFB code

    package Screenshot;

    import java.io.File;
    import java.io.IOException;

    import org.apache.commons.io.FileUtils;
    import org.openqa.selenium.OutputType;
    import org.openqa.selenium.TakesScreenshot;
    import org.openqa.selenium.WebDriver;

    public class Utility {

    public static String CaptureScreenshot(WebDriver driver, String ScreenshotName){

    File src = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
    String destination = “C:\\Users\\Abhishesh\\Abhishesh\\ScreenShot\\”+ScreenshotName+”.jpg”;
    try {
    FileUtils.copyFile(src, new File(destination));
    } catch (IOException e) {
    System.out.println(“Exception is :- ” + e.getMessage());
    }
    return destination;
    }

    }

    package abc;

    import java.io.File;
    import java.io.IOException;

    import org.apache.commons.io.FileUtils;
    import org.openqa.selenium.OutputType;
    import org.openqa.selenium.TakesScreenshot;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.firefox.FirefoxDriver;

    import com.relevantcodes.extentreports.ExtentReports;
    import com.relevantcodes.extentreports.ExtentTest;
    import com.relevantcodes.extentreports.LogStatus;

    import Screenshot.Utility;

    public class Facebook {
    static WebDriver driver;
    static ExtentReports report;
    static ExtentTest logger;

    public static void main(String[] args) {
    report = new ExtentReports(“C:\\Users\\Abhishesh\\TestAutomation\\Report\\google.html”);
    logger = report.startTest(“Google”);

    System.setProperty(“webdriver.chrome.driver”, “Y:\\Automation\\browser Driver\\chromedriver.exe”);
    driver = new ChromeDriver();
    driver.get(“https://www.google.com”);
    logger.log(LogStatus.INFO, Utility.CaptureScreenshot(driver, “google”));
    System.out.println(“google loaded”);
    //Utility.CaptureScreenshot(driver, “google”);
    System.out.println(“screenshot taken”);
    driver.quit();
    report.endTest(logger);
    report.flush();
    }

    }

    please suggest where am doing something wrong.

  55. Hello Anshoo/ Bas,

    I worked on your extent Report code and its awesome. Loved it.

    Now I need one more thing to add screenshot of report summary in the email. is there a way i can add that HTML of pie chart in my email directly. Please help.

    • Hey Naina,

      I don’t think so, unfortunately. Those pie charts are created using an imported library as far as I can remember.. But maybe you could contact Anshoo directly?

  56. Hi Bas,

    I have used extent report in one of my test automation framework based on TestNG. I create a extent test object in @beforeMethod and endTest in @afterMethod. I’ve also implemented a retry mechanism, in which a test is retried if it fails for a number of times given in testNG.xml.
    Because of retry, multiple runs of a test in included in the extent report but I only want the last one. For this, I need to delete duplicate results for a test method from extent report. I can derive some login to know which tests to delete but I can’t find a way on how can I delete reported results from an extent report.
    Is there a way, I can achieve this?

  57. Hi Bas,
    I have used extent report in one of my test automation framework based on TestNG.

    POM dependencies are:

    com.relevantcodes
    extentreports
    2.41.2

    Code lines:

    protected ExtentReports extent = ExtentReports.get(TestBaseSetup.class);
    public String reportLocation = System.getProperty(“user.dir”);
    private static String dirName;

    But “.get” is showing error : The method get(Class) is undefined for the type ExtentReports

    Code: .init is showing error

    extent.init(dirName+”\\TestReport_”+testName+”_”+Thread.currentThread().getId()+”.html”, true, DisplayOrder.OLDEST_FIRST);

    error: The method init(String, boolean, DisplayOrder) is undefined for the type ExtentReports

    • That’s right, because those methods are not defined for the ExtentReports class in version 2.41.2. See the JavaDoc here. I think you might have accidentally copied a code snippet from an earlier version.

  58. Anshu/Bas,

    I need to know how to show the data in the report in below format.

    Let us consider i have a test case which would run three times with different parameter (In Nunit we could achieve this by using “Sequential attribute”, Which would run the same scripts three times with different parameter) and on top of this attribute we can define to which category it belongs to (Let’s say it belongs to “Category 1”).

    In this case when i run Category 1 it runs the test case three times and gives me the output. But the issue here is. If you see in the report it shows as three different test case, which is expected. What i need to have the category at the top and child to be the three test case like below

    Category 1
    Test Case
    Test Case
    Test Case

    Could you please help me in achieving this.

    • Hey Joe, I have two options for you:

      1. I have a full blown solution I built for a client that I can share. Includes Selenium, SpecFlow, ExtentReports on top of NUnit. I’d be happy to share that with you. It uses a somewhat older version of ExtentReports but I’d do it the same way if asked today.

      2. I’m planning on writing a single post to end all ‘what would your solution look like’ questions I get. No more custom HTML reporting, no more messing about with Excel, only well known and useful open source libraries (sorry, packages ;). That’s going to be done in C# too (if only to encourage readers to do some work themselves as they’re 99% Java users). But that might take another month..

      Let me know!

      • I’d like the solution as ‘m trying to see how its works – need to see the solution before making changes etc. I’m no theorist.
        I’d like to get point 1 and be able to get the output for point 2

        Am I being greeedy? I’ll need REALLY specific install instructions. I’m a UFT vbs guy and a sometime visual basic studiio guy so I’ll need a .soln and then see it running and then break it down – possible?

        Joe

        • That’s not greedy, that’s knowing what you want. I sent you my VS solution via email.

          The blog post is in the planning, but preparing it will take me some time, and that’s a bit of a sparse commodity at the moment!

  59. Could you please tell how to add custom user log messages in cucumber extent report?

    currently i have timestamp, step name and details. But i want to add comments to put user log messages

    • I haven’t used the BDD style reporting myself so far, but from what I see in the documentation I don’t think you can do that. You might want to send an email to Anshoo (the creator of ExtentReports) to make sure.

  60. Hi i need to add a new field in Extent report dash board view alone . Stating in which URL my test has run .. Is it possible to add a new field ..??

Leave a Reply

Your email address will not be published. Required fields are marked *