Extent Reports in Selenium with TestNG

In this article, I will describe How to Generate the Extent Reports in Selenium with TestNG Listeners. I described how to use TestNG Listeners in this article and Canberk Akduygu, and I also described how to rerun failed tests with IRetryAnalyzer in this article. Here, I will use the TestNG listeners and the IRetryAnalyzer interface and add Extent Reports 5 classes to generate wonderful reports after each test run. At the end of this article, I will also share this project’s GitHub link. 

If you do not know Page Object Model, before starting this article, I suggest you check my POM with JAVA article. In our Page Object Model example, we create two login tests for the n11.com website. Now, I will add extentreports and listener packages under the test package, as shown below.

Extent Reports Project Structure

The project structure is shown below screenshot. We have two Extent Reports custom classes that are ExtentManager and ExtentTestManager. 

Also, we should put extent.properties file under the resources folder. This is the high-level structure of the project and in the next sections, I will explain all details.

extent report properties

Let’s start to create the test automation reporting project step by step! :)

Page Classes

BasePage Class:

public class BasePage {
    public WebDriver     driver;
    public WebDriverWait wait;

    //Constructor
    public BasePage(WebDriver driver) {
        this.driver = driver;
        wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }

    //Click Method
    public void click(By by) {
        waitVisibility(by).click();
    }

    //Write Text
    public void writeText(By by, String text) {
        waitVisibility(by).sendKeys(text);
    }

    //Read Text
    public String readText(By by) {
        return waitVisibility(by).getText();
    }

    //Wait
    public WebElement waitVisibility(By by) {
        return wait.until(ExpectedConditions.visibilityOfElementLocated(by));
    }
}

HomePage Class:

public class HomePage extends BasePage {
    /**
     * Constructor
     */
    public HomePage(WebDriver driver) {
        super(driver);
    }

    /**
     * Variables
     */
    String baseURL = "http://www.n11.com/";

    /**
     * Web Elements
     */
    By signInButtonClass = By.className("btnSignIn");

    /**
     * Page Methods
     */
    //Go to Homepage
    public HomePage goToN11() {
        Log.info("Opening N11 Website.");
        driver.get(baseURL);
        return this;
    }

    //Go to LoginPage
    public LoginPage goToLoginPage() {
        Log.info("Going to Login Page..");
        click(signInButtonClass);
        return new LoginPage(driver);
    }
}

LoginPage Class:

public class LoginPage extends BasePage {
    /**
     * Constructor
     */
    public LoginPage(WebDriver driver) {
        super(driver);
    }

    /**
     * Web Elements
     */
    By userNameId = By.id("email");
    By passwordId = By.id("password");
    By loginButtonId = By.id("loginButton");
    By errorMessageUsernameXpath = By.xpath("//*[@id=\"loginForm\"]/div[1]/div/div");
    By errorMessagePasswordXpath = By.xpath("//*[@id=\"loginForm\"]/div[2]/div/div");

    /**
     * Page Methods
     */
    public LoginPage loginToN11(String username, String password) {
        Log.info("Trying to login the N11.");
        writeText(userNameId, username);
        writeText(passwordId, password);
        click(loginButtonId);
        return this;
    }

    //Verify Username Condition
    public LoginPage verifyLoginUserName(String expectedText) {
        Log.info("Verifying login username.");
        waitVisibility(errorMessageUsernameXpath);
        assertEquals(readText(errorMessageUsernameXpath), expectedText);
        return this;
    }

    //Verify Password Condition
    public LoginPage verifyLoginPassword(String expectedText) {
        Log.info("Verifying login password.");
        waitVisibility(errorMessagePasswordXpath);
        assertEquals(readText(errorMessagePasswordXpath), expectedText);
        return this;
    }

    //Verify Password Condition
    public LoginPage verifyLogError() {
        Log.info("Verifying javascript login errors.");
        assertTrue(JSErrorLogs.isLoginErrorLog(driver));
        return this;
    }
}

Step-1: Add Extent Reports Maven Dependency

You should add Extent Reports dependency to your pom.xml. (I used the latest version when I was writing this article! You can see the latest version here: https://mvnrepository.com/artifact/com.aventstack/extentreports

Important Note: If you face with some errors, please use the latest versions of the dependencies. The version 5.0.9 of extent reports did not work as expected that’s why I downgraded that version to 5.0.8.

<?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>extent-reports-example</groupId>
    <artifactId>extent-reports-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <selenium-version>4.8.0</selenium-version>
        <testng-version>7.7.1</testng-version>
        <log4j-version>2.19.0</log4j-version>
        <extentreports-version>5.0.8</extentreports-version>
        <maven-surefire-plugin-version>3.0.0-M8</maven-surefire-plugin-version>
        <lombok-version>1.18.26</lombok-version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>${selenium-version}</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok-version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>${testng-version}</version>
        </dependency>

        <dependency>
            <groupId>com.aventstack</groupId>
            <artifactId>extentreports</artifactId>
            <version>${extentreports-version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j-version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j-version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>17</source> <!--For JAVA 8 use 1.8-->
                    <target>17</target> <!--For JAVA 8 use 1.8-->
                </configuration>
            </plugin>
            <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>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Step-2: Add Extent Reports Classes 

I created the ExtentReports package under the utils package and added below two classes to that package.

extentreports classes

ExtentManager Class:

In this class, we created an ExtentReports object, and it can be reachable via createExtentReports() method. Also, you need to set your ExtentReports report HTML file location.

public class ExtentManager {
    public static final ExtentReports extentReports = new ExtentReports();

    public synchronized static ExtentReports createExtentReports() {
        ExtentSparkReporter reporter = new ExtentSparkReporter("./extent-reports/extent-report.html");
        reporter.config().setReportName("Sample Extent Report");
        extentReports.attachReporter(reporter);
        extentReports.setSystemInfo("Blog Name", "SW Test Academy");
        extentReports.setSystemInfo("Author", "Onur Baskirt");
        return extentReports;
    }
}

ExtentTestManager Class:

  • An extentTestMap map is created. It holds the information of thread ids and ExtentTest instances.
  • ExtentReports instance is created by calling getExtentReports() method from ExtentManager.
  • At startTest() method, an instance of ExtentTest created and put into extentTestMap with current thread id.
  • At getTest() method, return ExtentTest instance in extentTestMap by using current thread id.
/**
 * extentTestMap holds the information of thread ids and ExtentTest instances.
 * ExtentReports instance created by calling createExtentReports() method from ExtentManager.
 * At startTest() method, an instance of ExtentTest created and put into extentTestMap with current thread id.
 * At getTest() method, return ExtentTest instance in extentTestMap by using current thread id.
 */
public class ExtentTestManager {
    static Map<Integer, ExtentTest> extentTestMap = new HashMap<>();
    static ExtentReports            extent        = ExtentManager.createExtentReports();

    public static synchronized ExtentTest getTest() {
        return extentTestMap.get((int) Thread.currentThread().getId());
    }

    public static synchronized ExtentTest startTest(String testName, String desc) {
        ExtentTest test = extent.createTest(testName, desc);
        extentTestMap.put((int) Thread.currentThread().getId(), test);
        return test;
    }
}

Step-3: Add Listener Classes

For retrying failed tests, we should add AnnotationTransformerRetry classes In order to listen to test events such as passed, failed, skipped, etc., we should add TestListener class in our project.

extent reports listeners

TestListener Class:

I added Extent Reports codes in each method and added some informative comments.

public class TestListener extends BaseTest implements ITestListener {
    private static String getTestMethodName(ITestResult iTestResult) {
        return iTestResult.getMethod().getConstructorOrMethod().getName();
    }

    @Override
    public void onStart(ITestContext iTestContext) {
        Log.info("I am in onStart method " + iTestContext.getName());
        iTestContext.setAttribute("WebDriver", this.driver);
    }

    @Override
    public void onFinish(ITestContext iTestContext) {
        Log.info("I am in onFinish method " + iTestContext.getName());
        //Do tier down operations for ExtentReports reporting!
        ExtentManager.extentReports.flush();
    }

    @Override
    public void onTestStart(ITestResult iTestResult) {
        Log.info(getTestMethodName(iTestResult) + " test is starting.");
    }

    @Override
    public void onTestSuccess(ITestResult iTestResult) {
        Log.info(getTestMethodName(iTestResult) + " test is succeed.");
        //ExtentReports log operation for passed tests.
        getTest().log(Status.PASS, "Test passed");
    }

    @Override
    public void onTestFailure(ITestResult iTestResult) {
        Log.info(getTestMethodName(iTestResult) + " test is failed.");

        //Get driver from BaseTest and assign to local webdriver variable.
        Object testClass = iTestResult.getInstance();
        WebDriver driver = ((BaseTest) testClass).getDriver();

        //Take base64Screenshot screenshot for extent reports
        String base64Screenshot =
            "data:image/png;base64," + ((TakesScreenshot) Objects.requireNonNull(driver)).getScreenshotAs(OutputType.BASE64);

        //ExtentReports log and screenshot operations for failed tests.
        getTest().log(Status.FAIL, "Test Failed",
            getTest().addScreenCaptureFromBase64String(base64Screenshot).getModel().getMedia().get(0));
    }

    @Override
    public void onTestSkipped(ITestResult iTestResult) {
        Log.info(getTestMethodName(iTestResult) + " test is skipped.");
        //ExtentReports log operation for skipped tests.
        getTest().log(Status.SKIP, "Test Skipped");
    }

    @Override
    public void onTestFailedButWithinSuccessPercentage(ITestResult iTestResult) {
        Log.info("Test failed but it is in defined success ratio " + getTestMethodName(iTestResult));
    }
}

AnnotationTransformer Class:

public class AnnotationTransformer implements IAnnotationTransformer {
    @Override
    public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
        annotation.setRetryAnalyzer(Retry.class);
    }
}

Retry Class:

public class Retry implements IRetryAnalyzer {
    private        int count  = 0;
    private static int maxTry = 1; //Run the failed test 2 times

    @Override
    public boolean retry(ITestResult iTestResult) {
        if (!iTestResult.isSuccess()) {                     //Check if test not succeed
            if (count < maxTry) {                           //Check if maxTry count is reached
                count++;                                    //Increase the maxTry count by 1
                iTestResult.setStatus(ITestResult.FAILURE); //Mark test as failed and take base64Screenshot
                extendReportsFailOperations(iTestResult);   //ExtentReports fail operations
                return true;                                //Tells TestNG to re-run the test
            }
        } else {
            iTestResult.setStatus(ITestResult.SUCCESS);     //If test passes, TestNG marks it as passed
        }
        return false;
    }

    public void extendReportsFailOperations(ITestResult iTestResult) {
        Object testClass = iTestResult.getInstance();
        WebDriver webDriver = ((BaseTest) testClass).getDriver();
        String base64Screenshot = "data:image/png;base64," + ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.BASE64);
        getTest().log(Status.FAIL, "Test Failed",
            getTest().addScreenCaptureFromBase64String(base64Screenshot).getModel().getMedia().get(0));
    }
}

Log Class: 

This class is designed for log4j 2 library.

public class Log {
    //Initialize Log4j instance
    private static final Logger Log =  LogManager.getLogger(Log.class);

    //Info Level Logs
    public static void info (String message) {
        Log.info(message);
    }

    //Warn Level Logs
    public static void warn (String message) {
        Log.warn(message);
    
    //Error Level Logs
    public static void error (String message) {
        Log.error(message);
    }

    //Fatal Level Logs
    public static void fatal (String message) {
        Log.fatal(message);
    }

    //Debug Level Logs
    public static void debug (String message) {
        Log.debug(message);
    }
}

JSErrorLogs Class:

public class JSErrorLogs {
    public static LogEntries getLogs(WebDriver driver) {
        return driver.manage().logs().get(LogType.BROWSER);
    }

    public static Boolean isLoginErrorLog(WebDriver driver) {
        LogEntries logEntries = driver.manage().logs().get(LogType.BROWSER);
        return logEntries.getAll().stream()
            .anyMatch(logEntry -> logEntry.getMessage().contains("An invalid email address was specified"));
    }
}

Step-4: Add Description For Tests 

You can add test descriptions in your tests and you will see them in the report as shown below.

extent reports description

extent reports dashboard

Step-5: Add Listeners to TestNG.xml

We should add listeners in TestNG.xml, as shown below.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="N11 Test Suite" >
    <listeners>
        <listener class-name="utils.listeners.TestListener"/>
        <listener class-name="utils.listeners.AnnotationTransformer"/>
    </listeners>
    <test name="LoginTest">
        <classes>
            <class name="tests.LoginTests"/>
        </classes>
    </test>
</suite>

Step-6: BaseTest Class

public class BaseTest {
    public WebDriver driver;
    public HomePage  homePage;
    public WebDriver getDriver() {
        return driver;
    }

    @BeforeClass
    public void classLevelSetup() {
        Log.info("Tests is starting!");
        driver = new ChromeDriver();
    }

    @BeforeMethod
    public void methodLevelSetup() {
        homePage = new HomePage(driver);
    }

    @AfterClass
    public void teardown() {
        Log.info("Tests are ending!");
        driver.quit();
    }
}

Step-7: Test Class

public class LoginTests extends BaseTest {
    @Test(priority = 0, description = "Invalid Login Scenario with wrong username and password.")
    public void invalidLoginTest_InvalidUserNameInvalidPassword(Method method) {
        //ExtentReports Description
        startTest(method.getName(), "Invalid Login Scenario with invalid username and password.");

        homePage
                .goToN11()
                .goToLoginPage()
                .loginToN11("[email protected]", "11122233444")
                .verifyLoginPassword("E-posta adresiniz veya şifreniz hatalı");
    }

    @Test(priority = 1, description = "Invalid Login Scenario with empty username and password.")
    public void invalidLoginTest_EmptyUserEmptyPassword(Method method) {
        //ExtentReports Description
        startTest(method.getName(), "Invalid Login Scenario with empty username and password.");

        homePage
                .goToN11()
                .goToLoginPage()
                .loginToN11("", "")
                .verifyLoginUserName("Lütfen e-posta adresinizi girin.")
                .verifyLoginPassword("WRONG MESSAGE FOR FAILURE!");
    }
}

Step-8: Add Properties Files

extent report properties

extent.properties

extent.reporter.spark.start=true
extent.reporter.spark.out=Reports/Spark.html

log4j2.properties

#Declare loggers
status = error
name= Log4j2PropertiesConfig
appenders=a_console, a_rolling
rootLogger.level=info
rootLogger.appenderRefs = ar_console,ar_rolling
rootLogger.appenderRef.ar_console.ref = StdoutAppender
rootLogger.appenderRef.ar_rolling.ref= RollingAppender

#Console Logger
appender.a_console.type = Console
appender.a_console.name = StdoutAppender
appender.a_console.layout.type = PatternLayout
appender.a_console.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n

#Rolling Logger
appender.a_rolling.type = RollingFile
appender.a_rolling.name = RollingAppender
appender.a_rolling.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n
appender.a_rolling.fileName=log4j2/log4j2-test-automation.log
appender.a_rolling.filePattern=log4j2-sample-%d{yyyy-MM-dd}.log
appender.a_rolling.layout.type = PatternLayout
appender.a_rolling.policies.type = Policies
appender.a_rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.a_rolling.policies.time.interval = 1

# To change log file every day
appender.a_rolling.policies.time.modulate = true
# To change log file after 10MB size
appender.a_rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.a_rolling.policies.size.size=10MB
appender.a_rolling.strategy.type = DefaultRolloverStrategy
appender.a_rolling.strategy.max = 20

And run the test!

Right-click to TestNG.xml file and run the tests here by clicking the green Run text.

After the test is finished, you will see extent-report.html file under the ExtentReports folder, as shown below.

extent html report

When you open the report, you will see the test results below.

Extent Reports Detailed Test Results:

extentreports dashboard

extent reports screenshot

Extent Reports General Test Results:

GitHub Project

https://github.com/swtestacademy/ExtentReportsExample

Other Related Articles

Also, you can check How to do Test Reporting with Allure and TestNG.

Also, you can check How to do Test Reporting with Extent Reports Version 3.

Also, you can check How to do Historical Test Reporting with Klov  – ExtentReports.

See you in the following article!
Onur Baskirt

206 thoughts on “Extent Reports in Selenium with TestNG”

  1. This is really a good article. I follow all your selenium and automation testing articles and of course helped me in creating a framework at work.

    Could you please create a similar article using Allure reporting. It really helps me.

    Thanks in advance.

    Reply
  2. hi,
    First, i’m sorry for my english.
    Second, i tell you that it is the best report for testng that i know, and i congratulate you for it. congratulations.
    but, i have a problem. i can´t watch the feature name and the step name. how can i watch it?
    Thank you

    Reply
  3. How to invoke ExtentTestManager.getTest() method in test classes and page classes?

    I am getting “Null Pointer Exception” while calling getTest() method. Can you please help me out with this?

    Thanks In Advance!

    Reply
    • ExtentTestManager class has public synchronized static methods. Thus, when you import “import utils.ExtentReports.ExtentTestManager;” line, then you can reach ExtentTestManager.endTest(); or ExtentTestManager.getTest();
      Please, check TestListener class. I called those methods several times. If you get null pointer, first you should start test with ExtentTestManager.startTest(String testName, String desc), then you can get that test by ExtentTestManager.getTest()

      Reply
  4. I Lost it at

    extent.endTest((ExtentTest)extentTestMap.get((int) (long) (Thread.currentThread().getId())));
    extent.startTest(testName, desc);

    it throws an unknown error

    Reply
  5. Hi Onur,

    Its a great article
    I need a little help
    I want to add my class name as a heading in the report.
    Like if Class A has five Test Cases and Class B has 4 test cases then Class name i-e ” Class A ” should appear as a heading on the left side of the report and then the test cases.

    For example
    like this

    Class A
    Test Case 1
    Test Case 2

    ….

    any solution plz
    Thanks in advance

    Reply
  6. Hello!
    Do you have any idea how to generate one report for multiple test suites run.
    For example we run 2 suite files with maven surefire plugin. So is there any way to create extent report that would include all suites in one report?
    I mean report should look like suite1 name->all tests in suite, suite2 name-> all tests in suite.

    Thank you.

    Reply
  7. The best article for extent reports. I will definitely save this page for future reference. I read several and eventually figure everything out, but this article is so detail and easy to follow. This would of saved several painful headaches.
    Thanks

    Reply
  8. Hello Onur,

    I want show falied and pass test cases log on report.
    Can you please tell me where we to change this.
    If possible tell me class name and code.

    Reply
  9. Wonderful article!

    I have one query please, i used same as you mentioned but logs are printed on console only not inside the test ng report. could yo uplease guide

    Reply
  10. Thanks for great article and response. I am using latest extent build 3.1. Could yo please give the same berief for latest build.

    Reply
  11. HI OB,

    First of all, very nice article. Finally someone who writes practical solution that can be implemented in day2day! :)

    I am having an issue while implementing the ExtentTestManager class:

    public static synchronized void endTest() {
    extent.endTest((ExtentTest)extentTestMap.get((int) (long) (Thread.currentThread().getId())));
    }

    In extent.endTest(….) I am getting the exception ‘Cannot resolve method endTest(com.aventstack.extentreports.Exports)’

    Any help will be highly appreciated.

    Cheers!

    Reply
  12. Thanks Onur, for the detailed tutorial implementing Extent Reports.
    I have a issue where the failed test is showing unknown tag in report.

    Reply
    • Welcome Sam. I think you need to debug it failure condition in your environment. I can not say an exact solution without debugging your project. I suggest you put some breakpoints on especially aftermethod() and failure condition in the listener class and see what happens.

      Reply
      • Hi Onur, Do I have to change something for screenshot method as I using the extent reports from Android Appium automation framework.

        I am getting Null pointer exception:

        //Take base64Screenshot screenshot.
        String base64Screenshot = “data:image/png;base64,”+((TakesScreenshot)webDriver).
        getScreenshotAs(OutputType.BASE64);

        Reply
        • Yes, you can change and check the results. If your change works well. Keep the modified version. I wrote these part for web automation. For mobile, please try your implementation and keep us updated. Thank you.

          Reply
    • I am getting Null pointer exception:

      //Take base64Screenshot screenshot.
      String base64Screenshot = “data:image/png;base64,”+((TakesScreenshot)webDriver).
      getScreenshotAs(OutputType.BASE64);

      Reply
      • I am using the same code for 1 year and did not get any null pointer exception. It is better to debug your project Sam. I am sharing the Failure code of the listener as follows.

        @Override
        public void onTestFailure(ITestResult iTestResult) {
        Object testClass = iTestResult.getInstance();
        WebDriver webDriver = ((BaseTest) testClass).getDriver();
        String base64Screenshot = “data:image/png;base64,”+((TakesScreenshot)webDriver).getScreenshotAs(OutputType.BASE64);
        ExtentTestManager.getTest().log(LogStatus.FAIL,iTestResult.getThrowable().getMessage(), ExtentTestManager.getTest().addBase64ScreenShot(base64Screenshot));
        ExtentManager.getReporter().endTest(ExtentTestManager.getTest());
        }

        Reply
  13. Hi
    i am facing the issue after following your model as you mentioned above,
    when i execute the code the Null Pointer Exception occurred in ExtentManager class the ,getId() method didnot any id there if you can assist me its really appreciated Thanks

    Reply
    • Hi,

      I downloaded chromedriver 2.38
      I changed TestNG version from 6.11 to 6.14.3
      I changed Selenium version from 3.6.0 to 3.11.0

      Then, run the project and I didn’t see any problems.

      I hope this will help you.

      BR.
      Onur

      Reply
  14. Hello Onur,

    Very good article, Thanks!!!!!!!!!! I have an issue of Screenshot when I run through Jenkins server. Screenshots are crashing only when I run through Jenkins. working fine in my local. Can you help me out?

    Reply
    • Hi, it may be about Jenkins server’s operating system. Are your local machine and Jenkins both Windows? And maybe folder permission problem. It is really hard to detect it with these inputs.

      Reply
    • I am running “–headless” for ChromeOptions,
      Onur I am using you JS waiters and other “waiters” class quite intensively with modification ;)

      Reply
  15. Hi Onur,

    I wanted to show the validation error in the failed report. Can you please let me know how we can code it?

    Reply
  16. Hi Onur,
    can you please help out in the case of Failed scenario, basically i dont need to retry the step/scenario in case of fail.
    and the second thing is if any scenario is failed the next method is mark failed instead of current failed method

    for example

    1st testcase(){
    }

    2nd testcase(){
    }

    3rd testcase(){

    }

    if the 2nd testcase(){
    }

    will failed but report will mark 3rd testcase as fail instead of 2nd which were actually failed

    can you please explain it and resolve it Thanks

    Reply
  17. Onur I am working on appium cucumber testing extent reports. Ur posts are one stop show for me. I have learnt so many topics from your posts. Keep up the good work. Cheers ??

    Reply
  18. Hi Onur,

    I am able to generate Extent Reports by passing parameters from testng.xml for single devices.

    Tests are getting passed for multiple devices but not able to generate report for multiple devices. Please suggest. ?

    Reply
  19. I am able to generate Extent Report. But, I would like to make some changes in Emailable-Report.html and generate Emailable-report.html in the form of Extent Report. Is there a way to do it? By the way, I am using Jenkins as well as the CICD tool.

    Reply
  20. hi Ontur, your article are great, can you help me how can I append testng testsuitename to the file name in ExtentManager.java class

    Reply
  21. (2) Q I had was when I am executing / debugging from from test class, what I mean is in eclipse after all set up say I want to fix something in test class and I have to do debug as testng or run as testng (note I am not doing a right click on testng.xml to be executed or run as testng suite) I am getting null pointer exception for ExtentTestManager.getTest().log(LogStatus.PASS, “Step02 -“); which makes sense in a debug mode. How do I over come this challenge of executing this set up in debug or run as testng

    Reply
    • I really did not figure out the problem. If you are getting null pointer, you are using an object without any assignment. In debug mode, you can try to comment out extentreport parts? I really can not provide a super solution.

      Reply
  22. Vasu
    Basically you you will get the null pointer excption when u not run you test suit via right clik on testng l.xml ans run as testng suit’ so if you need to get rid of this run you test always via right clik and testng.xml as testng suit

    If u nees to debug your test from test class put breakpoint and run it as debug but conment the extent report part from the class or method bexuz debug mode is not available for suit as per my knowledge thanks

    Reply
  23. hi Onur,

    Wonderfull Article , need you help in customizing the ‘Report’ ?
    When the Report get generated , I want to change few heading – for example on the top of the report there is a heading “Automation Report” , HOw can I change this to something else ??
    I tried finding the code for it but din’t find it..

    Thanks,
    Rajeev

    Reply
  24. Hi Onur,

    Could you please help me getting null pointer exception on this line “ExtentTestManager.getTest().setDescription(“Invalid Login Scenario with wrong username and password.”) its points to here

    public static synchronized ExtentTest startTest(String testName, String desc) {
    ExtentTest test = extent.startTest(testName, desc);
    extentTestMap.put((int) (long) (Thread.currentThread().getId()), test);
    return test;

    Reply
    • Hello Manihs,

      I don’t know your whole project structure but I can assure that it is caused by the empty object. You are using unassigned/empty/null object and getting null pointer exception. I highly suggest you put some breakpoints and debug your project. Then, I believe that you will figure out the null object.

      When I looked at your code, I do think that the problem maybe is about you can use getTest() before startTest Method call.

      Reply
  25. Hi Onur,

    If a test case fails in first execution, retryAnalyzer would again execute it. if first time execution fails and second time execution passes, I want to show the results of only second execution in Extent Reports. But I am getting both the test case results in the report how to overcome this problem could you please guide me and more thing we cannot get report if we execute main class instead of testng.xml .

    Thanks

    Reply
    • I am not %100 sure but when the test fails, the listener class reports the failure scenario and Retry class reruns the test. Maybe you can add a fail counter into your TestListener class and when the fail counter will be increment by one then you can print the result on the report. This is one of the solutions that you can apply and it is very easy to implement. Please try this and let me know. Just add an int failcounter = 0; and in onTestFailure method first check failcounter == 1, if not increment it by 1. In this way, you can only show the second result of the failed test in your report. Also you can play this number based on your retry count. Thanks.

      Reply
  26. Hi Onur ,Thanks for response i will implement and let you know d status it’s very grateful these type of articles are very useful who are facing challenges in automation.

    Reply
  27. Thank you for the detailed explaination! It is super helpful.

    However your exact same code with your tests above is throwing a null pointer exception. I am using v2 of extent reports. The only difference is I am not tunning t from an xml file, which shouldn’t matter. What’s the solution to this?

    Thanks in advance!

    Reply
  28. Hi Onur, I am getting a null pointer exception too on getTest(). I’ve used your project without any change and have added a basic test. Please suggest a solution.

    Reply
  29. Hello Onur,

    Wonderful article!, I only have one question, how did you get SO good at coding? :) I have been following your articles for some time now, and there’s a plethora of knowledge here and I like your coding style, is there anything that you can suggest so that people like me who are learning to be better at coding can well, be better at coding?

    Cheers, Keep up the good work :)

    Reply
  30. This is just beautiful. Thank you so much for the efforts. Very detailed and easy to implement steps given.
    Works well with me when ran using testng.xml. But when i am running as a pom.xml (For e.g from Jenkins), i am getting null pointer exception ExtentTestManager.getTest()

    Can you pleaseeeee help, this is the last step remaining. Any pointer to resolve the problem will be really a big help.
    Maven build fails with null pointer, but runs from testng.xml

    Reply
  31. Hi Onur. The solution is very helpful. Can you please explain wht the test end time and total time taken fields are not displaying for every test case but displaying only for he last one? This will really help

    Reply
  32. Hi onur, Thanks for such wonderful explanation. Can you provide some solution to display the test ended time and time taken to finish fields? Currently they as displayed null for starting testcaces where as it’s displayed fine for last test case.

    Reply
  33. Hi Onur,

    How can we add Classname.testmethod name in extent report ? in test pane.

    By the way wishing you happy new year and thanks for great article.

    Reply
  34. Hey Onur,

    great article, it helped me a lot.

    Still, i have a question: Do you know how to perform a linebreak inside the details-column? Tried “\n” but it doesn’t work, as well as multiple blank characters (” “) are not shown in the result of the ExtentManager.

    Do you have any idea how to fix it or maybe create more columns?

    Reply
  35. Hi Onur,

    Thanks for the article.
    I have one question as it seems that the relevant code for extent report has been moved to aventstack. So i tried updating the code but it gives me error in all classes. Can you help me with that?

    Reply
  36. Hi Onur, great article BTW.
    I have a query; I am running multiple classes via TestNG.xml in parallel, all my Test Classes extends BaseTest; will the tests use the correct driver instance that that particular test???

    Reply
    • I did not use 4.x version honestly but I will write a new article for that too. Here are the differences between version 3.

      API: ChartLocation

      Affected type: ChartLocation
      ChartLocation is no longer available, and can be removed from your setup code
      Suggested fix: removal of ChartLocation

      ExtentEmailReporter::EmailTemplate
      Affected type: EmailTemplate
      EmailTemplate has moved from package com.aventstack.extentreports.reporter to com.aventstack.extentreports.reporter.configuration
      Suggested fix: Re-import package imports to fix

      Reply
  37. I’m getting the same error as Prasad said in this line:

    ExtentTestManager.getTest().log(LogStatus.PASS, “Test passed”);

    Error:

    java.lang.NullPointerException at Listeners.Listener.onTestSuccess(Listener.java:45)

    And I’m using the version you use in this tutorial. I copied and pasted the same code you put and I’m getting the same erorr.

    Reply
  38. Hi,

    This is a very good article. Thanks!

    Could you please create a similar article using extent reporting with NUnit (C#). It really helps me.

    Thanks in advance.

    Reply
  39. Same issue as Armando, but in case of failure :

    java.lang.NullPointerException
    at.Listeners.TestListener.onTestFailure

    Reply
  40. Hi,
    Can you please say How to add a column in extent reports for browser and timestamp (start and end time)for each and every step.

    Reply
  41. Hi Baskirt,

    I tried automating amazon website and tried extent reports, its a great article, but I am getting null pointer exception, not sure why. I tried all the solutions mentioned above, added ExtentTestManager.startTest and ExtentTestManager.getTest(); Here is my git project link, please help me out. https://github.com/DeepikaKS1/AmazonWeb

    Reply
    • Hi Deepika, it is better to debug it on intelliJ. If I will have time I will look at it but I have a very hectic life nowadays. I can say that generally, null pointer exceptions is about initialization related problems. Would you please send the error message here? Which part of your code creates null pointer exception?

      Reply
  42. Do we need to create : “\\ExtentReports\\ExtentReportResults.html”, true); this directory and the file manually
    because for me(on my mac) the html report is not getting generated and not even the directory
    i have used the exact same code and also looked into code using debugger
    Not sure where exactly is the problem

    Reply
    • Hi Rahul, when I find the time, I will check it on my MAC and reply back. Would you try below code for MAC.
      path = System.getProperty(“user.dir”)+”/ExtentReports/extentreport.html”;
      System.out.println(“ExtentReport Path for MAC: ” + path);

      Reply
  43. Hi,

    In my reports, For failed scenarios, I want to see screenshots in larger/big size than normal., when i was using extent report 2 i used extent-config.xml file and added

    Now in extent report 4 how can i set this one?

    Reply
  44. Hi ,Thanks for the wonderfull article i am getting null pointer exception when i run testng.xml file
    java.lang.NullPointerException
    at ExtentReports.TestListner.onTestFailure(TestListner.java:58) it is not executing any test script
    it would be great help if you can help me in this:(

    Reply
  45. hi,
    It is very good article i really liked it.i have one doubt first time my script fails then it will rerun the failed scripts.Second time my test scripts passes then my pass percentage should be 100% but it is showing 80% .is it showing right or wrong? pls pls help me out

    Reply
  46. Hi Onur Baskirt,

    I am facing the issue when i was trying to generate the report in the mac os my code is working fine in windows only have a problem once i run the application in mac os even it is not giving an any error

    i am using this code please have a look where i am missing will be waiting to your response thanks

    [OneTimeSetUp]
    protected void Setup()
    {
    string dir = TestContext.CurrentContext.TestDirectory+”/” ;
    var fileName = “test” + “.htm”;
    ExtentV3HtmlReporter htmlReporter = new ExtentV3HtmlReporter(dir + fileName);

    _extent = new ExtentReports();
    _extent.AttachReporter(htmlReporter);
    }

    Reply
  47. Hi onur

    Thank you for this beautiful article.
    i have one question regarding the parallel testing report generation
    If i use this process for parallel testing using the selenium grid will it generate a proper reports or we have to make any changes?

    Reply
    • Hi Nil,

      We were using the same framework with Docker-Selenium Grid and we did not face any problem. I think you will not face problems as well but if you will, please let us know. We will try to help as much as we can. Thanks.

      Reply
  48. Hi onur,

    If i want to change the environment such as user name, host name etc in the report how to change. please help me

    Reply
  49. Hello Onur,

    I have a problem with ExtentReport. The html is generated but its empty. The @Test are not generated on html. Can u please help me ?

    Thx

    Reply
  50. Hello Onur,

    Great article. I have a doubt what is the role of extent.properties. since we specify the targeted output here as well in the ExtentManager class.

    Reply
  51. Hello Onur

    We are are getting environment variable twice here

    Blog Name SW Test Academy
    Author Onur Baskirt
    Blog Name SW Test Academy
    Author Onur Baskirt

    Reply
    • Hi Imran,

      I am currently at holiday and I do not have too much time to debug the problem but as I see it maybe about below code:

      public static synchronized ExtentTest startTest(String testName, String desc) {
      ExtentTest test = extent.createTest(testName, desc);
      extentTestMap.put((int) Thread.currentThread().getId(), test);
      return test;
      }

      We are calling this method two times in the tests and here extent instance has these author info. I think this logic should be fixed. Whenever I will have time, I will debug and fix it but you can also play with this part to see the results. Thanks for pointing out this problem.

      Reply
      • The code which is writing the duplicate environment variables is happening inside the TestListener class in onFinish() method when it calls the getExtentReports() method again for flushing the reports.

        To avoid this, we need to check if the extentReports object is null and if its not, we can return the existing object instead of creating a new one.

        Add this method in ExtentManager.java and call the new getExtent() method in onFinish() method in TestListener.

        public synchronized static ExtentReports getExtent() {
        if (extentReports != null) {
        return extentReports;
        }
        else
        {
        return getExtentReports();
        }
        }

        Reply
  52. getting this when executing the project.
    java: java.lang.IllegalAccessError: class lombok.javac.apt.LombokProcessor (in unnamed module @0x7c6a76a9) cannot access class com.sun.tools.javac.processing.JavacProcessingEnvironment (in module jdk.compiler) because module jdk.compiler does not export com.sun.tools.javac.processing to unnamed module @0x7c6a76a9

    Reply
    • It got fixed adding the dependency. thanks! , yes the report is working properly, i was doing something wrong.

      org.projectlombok
      lombok
      1.18.20

      Reply
  53. getting this error : The method requireNonNull(WebDriver) is undefined for the type Objects

    at:#
    //Take base64Screenshot screenshot for extent reports
    String base64Screenshot =
    “data:image/png;base64,” + ((TakesScreenshot) Objects.requireNonNull(driver)).getScreenshotAs(OutputType.BASE64);

    Reply
  54. Cannot invoke “com.aventstack.extentreports.ExtentTest.addScreenCaptureFromBase64String(String)” because the return value of “com.utils.extentReports.ExtentTestManager.getTest()” is null

    Hi
    My test runs only the first scenario and exits with the above null pointer exception. could you please help me with this.

    Thanks

    Reply
  55. hey man, im here again haha, just wondering how much effort it takes to make the results to display by “testClass” executed? or if it is already there and i am not aware.
    I mean if you run TestAClass, TestBClass, with their tests. The testClasses are displayed and you click on it and collapse all the tests inside it.
    I hope i made myself clear.

    Reply
  56. [RemoteTestNG] detected TestNG version 7.4.0
    [INFO ] 2021-09-09 09:30:51.670 [main] Log – I am in onStart method LoginTest
    [INFO ] 2021-09-09 09:30:51.696 [main] Log – Tests is starting!
    [INFO ] 2021-09-09 09:30:51.745 [main] Log – invalidLoginTest_InvalidUserNameInvalidPassword test is starting.
    [INFO ] 2021-09-09 09:30:51.747 [main] Log – invalidLoginTest_InvalidUserNameInvalidPassword test is skipped.
    [INFO ] 2021-09-09 09:30:51.944 [main] Log – invalidLoginTest_InvalidUserNameInvalidPassword test is failed.
    [INFO ] 2021-09-09 09:30:51.981 [main] Log – I am in onFinish method LoginTest
    DEBUG 16311 [freemark] (): Couldn’t find template in cache for “spark/spark.spa.ftl”(“en_IN”, UTF-8, parsed); will try to load it.
    DEBUG 16311 [freemark] (): TemplateLoader.findTemplateSource(“spark/spark.spa_en_IN.ftl”): Not found

    DEBUG 16311 [freemark] (): Loading template for “commons/commons-inject-js.ftl”(“en_IN”, UTF-8, parsed) from “jar:file:/C:/Users/mynak/.m2/repository/com/aventstack/extentreports/5.0.8/extentreports-5.0.8.jar!/com/aventstack/extentreports/templates/commons/commons-inject-js.ftl”
    java.lang.NullPointerException
    at java.base/java.util.Objects.requireNonNull(Objects.java:208)
    at utils.listeners.TestListener.onTestFailure(TestListener.java:49)

    This error is shown at
    startTest(method.getName(), “Invalid Login Scenario with empty username and password.”);

    Could you suggest what could be causing this.. getting initiated and then failing and Report triggering if i am not wrong.

    Reply
  57. thanks for the response @Onur Baskirt, I have update the snapshot version error to 4.0.8 from 5.0.8 in POM.XML and now we are seeing error at a later point.

    getTest().addScreenCaptureFromBase64String(base64Screenshot).getModel().getMedia().get(0));

    It is saying “java.lang.Error: Unresolved compilation problem: The method getMedia() is undefined for the type Test”
    at utils.listeners.TestListener.onTestFailure(TestListener.java:52)

    Could you please suggest….

    Reply
  58. Really, really useful! Thanks for sharing!

    I just have one question: What’s the purpose of the JSErrorLogs class? Is it needed for the report or for the framework?

    Thanks!

    Reply
  59. Hi Onur, Thanks for this fantastic article. Is there any way we customize extent report to modify status “FAIL” to “FAIL_Category” in the test pane? Thanks.

    Reply
  60. Hi Onur,
    Great article !. I have a question around sending extent reports as email attachment after test execution . When I do that , the html looses its styling due to incorrect refrences to .js and .css files . I tried to zip the file but gmail blocks .js files to be sent as mail attachment . How can we share extent reports in an emailable format ?

    Reply
  61. Onur,
    Thanks for this great article. I was trying to get thumbnails appear on the report page instead of screenshot link “base 64”?
    Your help is much appreciated!

    Reply
  62. Hi, Onur.

    I find that the extent report does not jump back to top when switching test cases. May I ask how can we add this feature into extent report?

    Reply
    • Hi Ben, would you pull the latest code and re-try? I have updated the dependencies and the code worked fine. I do not understand very well your question. In my case, I have two test cases, 1 passed, 1 failed and failed one was re-triggered with retry logic and all of these are visible on the report.

      Reply
  63. Hi Onur,
    Thank you for this very informative article.
    I have a query, I used Logger factory to capture the logs, how I can add the those loggers in the extent report.

    Reply
  64. Hi,
    Extent report is getting generated. But, is there a way to generate extent report on gitlab pipeline. What should I add in .yaml file for it?

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.