package com.mridul.software.automation.listeners;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.mridul.software.automation.aspects.webdriver.TakeScreenshotAspect;
import com.mridul.software.automation.rest.interceptors.ExtentLoggingClientHttpRequestInterceptor;
import com.mridul.software.automation.spring.context.AppPropertiesCtx;
import com.mridul.software.automation.spring.context.UtilsCtx;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Component;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.Reporter;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
@Slf4j
@Component
public class ExtentTestExecutionListener extends AbstractTestExecutionListener {
private ExtentReports reports;
private AppPropertiesCtx config;
private UtilsCtx utilsCtx;
private ExtentTestEventListener extentTestEventListener;
private ExtentLoggingClientHttpRequestInterceptor interceptor;
private TakeScreenshotAspect takeScreenshotAspect;
private static final ThreadLocal<ExtentTest> TEST_THREAD_LOCAL = new ThreadLocal<>();
private void initialize(TestContext testContext) {
log.debug("Initializing spring beans for {}", this.getClass().getCanonicalName());
reports = explicitlyWireBean(testContext, ExtentReports.class);
config = explicitlyWireBean(testContext, AppPropertiesCtx.class);
utilsCtx = explicitlyWireBean(testContext, UtilsCtx.class);
extentTestEventListener = explicitlyWireBean(testContext, ExtentTestEventListener.class);
interceptor = explicitlyWireBean(testContext, ExtentLoggingClientHttpRequestInterceptor.class);
takeScreenshotAspect = explicitlyWireBean(testContext, TakeScreenshotAspect.class);
log.debug("reports : {} and config : {}", reports, config);
checkNotNull(reports, "reports not autowired!");
checkNotNull(config, "config not autowired!");
deleteScreenshotPath();
}
private <T> T explicitlyWireBean(TestContext testContext, Class<T> clazz) {
return testContext.getApplicationContext().getBean(clazz);
}
private enum TestLevel {
CLASS,
METHOD,
EXECUTION
}
private void initializeExtentTest(TestContext testContext, TestLevel testLevel) {
log.debug("Initializing the initializeExtentTest!");
checkNotNull(reports, "reports not autowired!");
ExtentTest test = null;
switch (testLevel) {
case CLASS:
test = reports.createTest("beforeTestClass");
break;
case METHOD:
test = reports.createTest(testContext.getTestClass().getName());
break;
case EXECUTION:
test = reports.createTest(testContext.getTestMethod().getName());
break;
default:
throw new UnsupportedOperationException("test is not created!");
}
checkNotNull(test, "test is not created!");
TEST_THREAD_LOCAL.set(test);
}
private void setExtentTest() {
extentTestEventListener.setExtentTest(TEST_THREAD_LOCAL.get());
interceptor.setExtentTest(TEST_THREAD_LOCAL.get());
}
private void addTestNameToScreenshotPath(TestContext testContext) {
String screenshotPath = config.getReport().getScreenshot().getFilePath();
String pathWithTestMethodName = screenshotPath + testContext.getTestMethod().getName() + File.separator;
config.getReport().getScreenshot().getTest().setMethodName(pathWithTestMethodName);
}
private void deleteScreenshotPath() {
String screenshotPath = config.getReport().getScreenshot().getFilePath();
utilsCtx.getFileSystemUtils().deleteFileIfExists(screenshotPath);
}
@Override
public void beforeTestClass(TestContext testContext) {
log.debug("Initializing test context beforeTestClass!");
initialize(testContext);
}
@Override
public void beforeTestMethod(TestContext testContext) {
log.debug("Initializing extent test beforeTestMethod!");
}
@Override
public void beforeTestExecution(TestContext testContext) {
log.debug("Initializing extent test beforeTestExecution!");
this.initializeExtentTest(testContext, TestLevel.EXECUTION);
setExtentTest();
addTestNameToScreenshotPath(testContext);
}
@Override
public void afterTestExecution(TestContext testContext) {
log.debug("Empty override");
}
@Override
public void afterTestMethod(TestContext testContext) {
log.debug("invoking after test!");
List<ITestResult> currentTestResult = getCorrespondingResultFor(testContext.getTestMethod());
currentTestResult.forEach(this::reportOnStatus);
log.debug("Flushing extent reports!");
reports.flush();
}
private List<ITestResult> getCorrespondingResultFor(Method method) {
ITestContext context = Reporter.getCurrentTestResult().getTestContext();
List<ITestResult> allResults = new ArrayList<>();
allResults.addAll(context.getPassedTests().getAllResults());
allResults.addAll(context.getFailedTests().getAllResults());
allResults.addAll(context.getSkippedTests().getAllResults());
clearRetrievedTests(context);
return allResults
.stream()
.filter(result -> result.getMethod().getConstructorOrMethod().getMethod().equals(method))
.collect(Collectors.toList());
}
private void clearRetrievedTests(ITestContext context) {
context.getPassedTests().getAllResults().clear();
context.getFailedTests().getAllResults().clear();
context.getSkippedTests().getAllResults().clear();
}
private void reportOnStatus(ITestResult currentTestResult) {
switch (currentTestResult.getStatus()) {
case 1:
onTestSuccess(currentTestResult);
break;
case 2:
onTestFailure(currentTestResult);
break;
case 3:
onTestSkipped(currentTestResult);
break;
default:
throw new UnsupportedOperationException(
"TestAgent result with status : " + currentTestResult.getStatus() + " is unsupported!");
}
}
//not testNg method
private void onTestSuccess(ITestResult result) {
log.debug("Initializing on test success!");
String successMessage = config.getMessage().getSuccessMessage().replace("{}", result.getName());
addScreenshotToTestIfEnabled(TEST_THREAD_LOCAL.get(), isScreenshotEnabled())
.pass(successMessage);
}
//not testNg method
private void onTestFailure(ITestResult result) {
log.debug("Initializing on test failure!");
String failureMessage = config.getMessage().getFailureMessage().replace("{}", result.getName());
addScreenshotToTestIfEnabled(TEST_THREAD_LOCAL.get(),
(isScreenshotEnabledForFailure() || isScreenshotEnabled()))
.fail(failureMessage + System.lineSeparator() + result.getThrowable());
}
//not testNg method
private void onTestSkipped(ITestResult result) {
log.debug("Initializing on test skipped!");
String skippedMessage = config.getMessage().getSkippedMessage().replace("{}", result.getName());
addScreenshotToTestIfEnabled(TEST_THREAD_LOCAL.get(), isScreenshotEnabled())
.skip(skippedMessage + System.lineSeparator() + result.getThrowable());
}
private boolean isScreenshotEnabled() {
if (takeScreenshotAspect.getScreenshotNames().isEmpty()) {
return false;
}
return config.getReport().getScreenshot().getTest().getEnable().getForAll();
}
private boolean isScreenshotEnabledForFailure() {
return config.getReport().getScreenshot().getTest().getEnable().getOnFailure();
}
private Set<String> getScreenshotNames() {
return takeScreenshotAspect.getScreenshotNames();
}
private void clearScreeshotNamesForCurrentTest() {
takeScreenshotAspect.getScreenshotNames().clear();
}
private String getBase64EncodedScreenshot(String fileName) {
try {
byte[] bytes = FileUtils.readFileToByteArray(new File(fileName));
log.debug("bytes length : {}", bytes.length);
String base64EncodedImage = Base64.getEncoder().encodeToString(bytes);
log.debug("base64EncodedImage : {}", base64EncodedImage);
return base64EncodedImage;
} catch (final Exception e) {
String message = String.format("Issue while converting file %s to base 64 encoding %s : ", fileName, e);
throw new RuntimeException(message + e);
}
}
private ExtentTest addScreenshotToTestIfEnabled(ExtentTest test, boolean enabled) {
try {
if (enabled) {
String methodName = config.getReport().getScreenshot().getTest().getMethodName();
getScreenshotNames().forEach(
e -> {
if (e.contains(methodName)) {
test.addScreenCaptureFromBase64String(getBase64EncodedScreenshot(e));
}
});
clearScreeshotNamesForCurrentTest();
}
return test;
} catch (final Exception e) {
String message = String.format("Exception while retrieving screenshot %s : ", e);
throw new RuntimeException(message + e);
}
}
}
Comments
Post a Comment