# How to Set Up Extent Reports with ExtentReportManager for HTML Test Reports in anhtester/automationframeworkselenium

> Learn to set up Extent Reports with ExtentReportManager in the anhtester/automationframeworkselenium project. Generate thread-safe HTML test reports with ease, including screenshots and metadata.

- Repository: [Anh Tester/automationframeworkselenium](https://github.com/anhtester/automationframeworkselenium)
- Tags: how-to-guide
- Published: 2026-02-24

---

**The anhtester/automationframeworkselenium repository provides a ready-to-use ExtentReportManager that integrates ExtentReports with TestNG via a custom listener to generate thread-safe HTML test reports with screenshots and metadata.**

The anhtester/automationframeworkselenium framework ships with a built-in reporting architecture that simplifies setting up Extent Reports with ExtentReportManager for HTML test reports. This implementation abstracts the ExtentReports API into manageable components that handle initialization, thread-safe test logging, and automatic HTML generation without requiring boilerplate code in your test classes.

## Core Architecture Components

The framework implements a three-layer architecture to manage ExtentReports lifecycle and thread safety.

### ExtentReportManager

The **`ExtentReportManager`** class in [`src/main/java/com/anhtester/reports/ExtentReportManager.java`](https://github.com/anhtester/automationframeworkselenium/blob/main/src/main/java/com/anhtester/reports/ExtentReportManager.java) serves as the central utility that creates the singleton `ExtentReports` instance. It configures the **Spark** HTML reporter, sets document titles, captures screenshots as Base64, assigns authors and categories, and handles the final flush operation that writes the HTML file to disk.

### ExtentTestManager

The **`ExtentTestManager`** class in [`src/main/java/com/anhtester/reports/ExtentTestManager.java`](https://github.com/anhtester/automationframeworkselenium/blob/main/src/main/java/com/anhtester/reports/ExtentTestManager.java) maintains a `ThreadLocal<ExtentTest>` variable. This design ensures that each test method running in parallel execution receives its own isolated `ExtentTest` object, preventing race conditions when multiple threads log simultaneously.

### TestListener

The **`TestListener`** class in [`src/test/java/com/anhtester/listeners/TestListener.java`](https://github.com/anhtester/automationframeworkselenium/blob/main/src/test/java/com/anhtester/listeners/TestListener.java) implements TestNG's `ITestListener` interface. This listener wires the manager into the test lifecycle by triggering initialization on suite start, creating test entries when methods begin, logging results after execution, and flushing reports when the suite finishes.

## Maven Dependency Configuration

The project declares the ExtentReports dependency in [`pom.xml`](https://github.com/anhtester/automationframeworkselenium/blob/main/pom.xml) using version 5.1.2. No additional configuration is required unless upgrading the library.

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

```

The property `extentreports.version` is defined in the properties section of [`pom.xml`](https://github.com/anhtester/automationframeworkselenium/blob/main/pom.xml). Update this value to upgrade to newer ExtentReports releases.

## Configuring Report Paths and Behavior

All report configuration resides in **`FrameworkConstants`** ([`src/main/java/com/anhtester/constants/FrameworkConstants.java`](https://github.com/anhtester/automationframeworkselenium/blob/main/src/main/java/com/anhtester/constants/FrameworkConstants.java)), which reads values from `config.properties` at startup. Modify these settings in `src/main/resources/config.properties`:

- **`EXTENT_REPORT_FOLDER`** – Directory where HTML reports are written (e.g., `reports/ExtentReports/`)
- **`EXTENT_REPORT_NAME`** – Base filename without extension (e.g., `ExtentReport`)
- **`OVERRIDE_REPORTS`** – Set to `"yes"` to overwrite the same file on each run, or `"no"` to generate timestamped files
- **`OPEN_REPORTS_AFTER_EXECUTION`** – Set to `"yes"` to automatically open the HTML report in the default browser after test completion
- **`SCREENSHOT_PASSED_TCS`**, **`SCREENSHOT_FAILED_TCS`**, **`SCREENSHOT_SKIPPED_TCS`** – Enable screenshots for specific test statuses by setting to `"yes"`

## Initializing the Extent Report

The framework initializes the report automatically when the `TestListener` triggers. The `onStart()` method invokes:

```java
ExtentReportManager.initReports();

```

This method creates the `ExtentReports` instance, instantiates an `ExtentSparkReporter` with the configured theme and document title, attaches system information (framework name, author, environment), and stores the output file path in a private static variable for later flushing.

## Creating Thread-Safe Test Entries

When each test method begins execution, the listener's `onTestStart()` method creates a dedicated test entry:

```java
ExtentReportManager.createTest(iTestResult.getName());

```

You can enrich test metadata immediately after creation:

```java
ExtentReportManager.addAuthors(getAuthorType(iTestResult));
ExtentReportManager.addCategories(getCategoryType(iTestResult));
ExtentReportManager.addDevices();
ExtentReportManager.info(BrowserInfoUtils.getOSInfo());

```

These calls delegate to `ExtentTestManager.setExtentTest()`, which stores the `ExtentTest` object in a thread-local variable, ensuring isolated logging for parallel test execution.

## Logging Steps and Capturing Screenshots

Use the static helper methods from `ExtentReportManager` anywhere in your test code to append log entries and visual evidence:

| Method | Usage |
|--------|-------|
| `logMessage(String msg)` | General informational logging |
| `logMessage(Status status, String msg)` | Log with explicit status (PASS, FAIL, WARNING) |
| `pass(String msg)` / `fail(String msg)` / `skip(String msg)` | Shorthand for status-specific logging |
| `addScreenShot(Status status, String name)` | Captures Base64 screenshot from the Selenium WebDriver and attaches it to the current step |
| `addScreenShot(String name)` | Captures screenshot with INFO status |
| `info(Markup markup)` | Adds rich HTML content like tables or code blocks |

Screenshot capture respects the configuration flags set in `config.properties`. When enabled, the framework automatically captures the browser state and embeds it directly into the HTML report using Base64 encoding to ensure portability.

## Flushing and Opening the Final Report

When the test suite completes, the listener's `onFinish()` method finalizes the report:

```java
ExtentReportManager.flushReports();
ReportUtils.openReports(link);

```

The `flushReports()` method writes all accumulated data to the HTML file, closes the ExtentReports instance, and calls `ExtentTestManager.unload()` to clear thread-local storage. If `OPEN_REPORTS_AFTER_EXECUTION` is enabled, the generated HTML file opens automatically in the system default browser.

## Complete Working Example

The following minimal test class demonstrates the integration. Because `TestListener` handles the lifecycle automatically, you only write logging statements:

```java
import com.anhtester.reports.ExtentReportManager;
import com.aventstack.extentreports.Status;
import org.testng.annotations.Test;

public class LoginTest {

    @Test
    public void verifyValidLogin() {
        // Log navigation step
        ExtentReportManager.logMessage("Navigating to login URL");
        
        // Perform login actions here...
        
        // Attach screenshot after login
        ExtentReportManager.addScreenShot(Status.PASS, "Post-login dashboard");
        
        // Log verification
        ExtentReportManager.pass("Login successful with valid credentials");
    }
}

```

Ensure your [`testng.xml`](https://github.com/anhtester/automationframeworkselenium/blob/main/testng.xml) registers the listener:

```xml
<suite name="Automation Suite">
    <listeners>
        <listener class-name="com.anhtester.listeners.TestListener"/>
    </listeners>
    <test name="Regression Tests">
        <classes>
            <class name="LoginTest"/>
        </classes>
    </test>
</suite>

```

## Summary

- **ExtentReportManager** in [`src/main/java/com/anhtester/reports/ExtentReportManager.java`](https://github.com/anhtester/automationframeworkselenium/blob/main/src/main/java/com/anhtester/reports/ExtentReportManager.java) handles singleton instance creation, Spark reporter configuration, and HTML generation.
- **ExtentTestManager** maintains thread-local storage via `ThreadLocal<ExtentTest>` to support parallel test execution safely.
- **TestListener** automates the entire lifecycle from initialization through flushing without requiring manual setup in test classes.
- Configuration is centralized in `FrameworkConstants` and driven by `config.properties` values for report paths, naming conventions, and screenshot behavior.
- Screenshots are captured as Base64 and embedded directly into the HTML report to ensure single-file portability.
- The framework supports automatic report opening post-execution via the `OPEN_REPORTS_AFTER_EXECUTION` property.

## Frequently Asked Questions

### How do I enable screenshots only for failed test cases?

Set the property `SCREENSHOT_FAILED_TCS=yes` in `src/main/resources/config.properties`, and ensure `SCREENSHOT_PASSED_TCS` and `SCREENSHOT_SKIPPED_TCS` are set to `no`. The `ExtentReportManager` checks these flags before invoking the screenshot capture logic in `addScreenShot()`.

### Can I run tests in parallel without mixing log entries?

Yes. The `ExtentTestManager` class uses a `ThreadLocal<ExtentTest>` variable to isolate each thread's `ExtentTest` instance. When `createTest()` is called, the manager stores the test object in thread-local storage, ensuring that parallel test methods write to their respective report nodes without interference.

### Where is the final HTML report file located?

The report writes to the directory specified by `EXTENT_REPORT_FOLDER` in `config.properties`, typically under `reports/ExtentReports/`. If `OVERRIDE_REPORTS` is set to `no`, the filename includes a timestamp prefix (e.g., [`20240115_143022_ExtentReport.html`](https://github.com/anhtester/automationframeworkselenium/blob/main/20240115_143022_ExtentReport.html)). The exact path is constructed in `ExtentReportManager.initReports()` using `FrameworkConstants.EXTENT_REPORT_FOLDER_PATH`.

### How do I add custom system information to the report header?

Modify the `initReports()` method in [`ExtentReportManager.java`](https://github.com/anhtester/automationframeworkselenium/blob/main/ExtentReportManager.java) or extend the manager to call `extentReports.setSystemInfo(key, value)` before the suite starts. Common additions include build numbers, test environments, or browser versions captured via `BrowserInfoUtils`.