com.seleniumtests.reporter.reporters.SeleniumTestsReporter2 Maven / Gradle / Ivy
/**
* Orignal work: Copyright 2015 www.seleniumtests.com
* Modified work: Copyright 2016 www.infotel.com
* Copyright 2017-2019 B.Hecquet
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seleniumtests.reporter.reporters;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import com.seleniumtests.driver.DriverMode;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.testng.IReporter;
import org.testng.IResultMap;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import com.seleniumtests.core.Mask;
import com.seleniumtests.core.SeleniumTestsContext;
import com.seleniumtests.core.SeleniumTestsContextManager;
import com.seleniumtests.core.utils.TestNGResultUtils;
import com.seleniumtests.driver.TestType;
import com.seleniumtests.reporter.logger.GenericFile;
import com.seleniumtests.reporter.logger.TestStep;
import com.seleniumtests.reporter.logger.TestStep.StepStatus;
import com.seleniumtests.util.ExceptionUtility;
import com.seleniumtests.util.StringUtility;
import com.seleniumtests.util.logging.SeleniumRobotLogger;
/**
* Class for generating test report
* @author behe
*
*/
public class SeleniumTestsReporter2 extends CommonReporter implements IReporter {
public static final String RESOURCES_FOLDER = "resources";
private static final String STATUS = "status";
private static final String HEADER = "header";
private static final String APPLICATION = "application";
private static final String APPLICATION_TYPE = "applicationType";
private static final String METHOD_RESULT_FILE_NAME = "methodResultFileName";
protected PrintWriter mOut;
private String outputDirectory;
private String generationErrorMessage = null;
public SeleniumTestsReporter2() {
setOutputDirectory(new File(SeleniumTestsContextManager.getGlobalContext().getOutputDirectory()).getAbsolutePath());
}
/**
* Copy resources necessary for result file
* @throws IOException
*/
public void copyResources() throws IOException {
List styleFiles = Arrays.asList("seleniumRobot.css", "seleniumtests_test1.gif",
"seleniumtests_test2.gif", "seleniumtests_test3.gif", "seleniumRobot.js");
styleFiles = new ArrayList<>(styleFiles);
if (!SeleniumTestsContextManager.getGlobalContext().getOptimizeReports()) {
styleFiles.add("bootstrap.min.css");
styleFiles.add("bootstrap.min.css.map");
styleFiles.add("bootstrap.bundle.min.js");
styleFiles.add("bootstrap.bundle.min.js.map");
styleFiles.add("Chart.min.js");
styleFiles.add("jquery-3.4.1.min.js");
styleFiles.add("AdminLTE.min.css");
styleFiles.add("lobsterTwo.css");
styleFiles.add("css/all.min.css");
styleFiles.add("webfonts/fa-solid-900.eot");
styleFiles.add("webfonts/fa-solid-900.svg");
styleFiles.add("webfonts/fa-solid-900.ttf");
styleFiles.add("webfonts/fa-solid-900.woff");
styleFiles.add("webfonts/fa-solid-900.woff2");
}
for (String fileName: styleFiles) {
File destFile = Paths.get(outputDirectory, RESOURCES_DIR, "templates", fileName).toFile();
// do not copy resources if it has already been done
if (destFile.exists()) {
break;
}
FileUtils.copyInputStreamToFile(Thread.currentThread().getContextClassLoader().getResourceAsStream("reporter/templates/" + fileName),
destFile);
}
}
/**
* Returns the test status as a string
* @param testResult
* @return
*/
private String getTestStatus(ITestResult testResult) {
String testStatus = SKIPPED_TEST;
if (testResult.getStatus() == ITestResult.SUCCESS) {
testStatus = PASSED_TEST;
} else if (testResult.getStatus() == ITestResult.FAILURE) {
testStatus = FAILED_TEST;
}
return testStatus;
}
@Override
protected void generateReport(Map> resultSet, final String outdir, boolean optimizeReport, boolean finalGeneration) {
ITestContext testCtx = SeleniumTestsContextManager.getGlobalContext().getTestNGContext();
if (testCtx == null) {
logger.error("Looks like your class does not extend from SeleniumTestPlan!");
return;
}
setOutputDirectory(new File(SeleniumTestsContextManager.getGlobalContext().getOutputDirectory()).getAbsolutePath());
// Generate general report
Map> methodResultsMap = new HashMap<>();
try {
methodResultsMap = generateSuiteSummaryReport(resultSet, optimizeReport);
copyResources();
logger.info("Completed Summary Report generation.");
} catch (IOException e) {
logger.error("Error writing summary report", e);
}
// Generate test method reports for each result which has not already been generated
for (Map.Entry> entry: methodResultsMap.entrySet()) {
for (ITestResult testResult: entry.getValue()) {
// do not generate twice the same file, except at the end of test suites execution so that final results contains all information
// HTML report created after each test method cannot contain @AfterClass post steps because they have not already been executed
// so we need to regenerate after all tests have executed
if (!TestNGResultUtils.isHtmlReportCreated(testResult) || finalGeneration) {
generateSingleTestReport(testResult, optimizeReport);
}
}
}
}
/**
* Generate HTML report for a single test
* @param testResult
* @param resourcesFromCdn if true (optimizeReport), resources are linked from CDN
*/
public void generateSingleTestReport(ITestResult testResult, boolean resourcesFromCdn) {
// issue #81: recreate test context from this context (due to multithreading, this context may be null if parallel testing is done)
SeleniumTestsContext testContext = SeleniumTestsContextManager.setThreadContextFromTestResult(testResult.getTestContext(), testResult);
try {
copyResources();
// issue #284: copy resources specific to the single test report. They are moved here so that the file can be used without global resources
FileUtils.copyInputStreamToFile(Thread.currentThread().getContextClassLoader().getResourceAsStream("reporter/templates/seleniumRobot_solo.css"), Paths.get(testContext.getOutputDirectory(), RESOURCES_FOLDER, "seleniumRobot_solo.css").toFile());
FileUtils.copyInputStreamToFile(Thread.currentThread().getContextClassLoader().getResourceAsStream("reporter/templates/app.min.js"), Paths.get(testContext.getOutputDirectory(), RESOURCES_FOLDER, "app.min.js").toFile());
if (!SeleniumTestsContextManager.getGlobalContext().getOptimizeReports()) {
FileUtils.copyInputStreamToFile(Thread.currentThread().getContextClassLoader().getResourceAsStream("reporter/templates/iframeResizer.min.js"), Paths.get(testContext.getOutputDirectory(), RESOURCES_FOLDER, "iframeResizer.min.js").toFile());
}
generateExecutionReport(testContext, testResult, getTestStatus(testResult), resourcesFromCdn);
logger.info("Completed Test Report Generation.");
// do not recreate this report anymore
TestNGResultUtils.setHtmlReportCreated(testResult, true);
} catch (Exception e) {
logger.error("Error writing test report: " + getVisualTestName(testResult), e);
}
}
public void generateSingleTestReport(ITestResult testResult) {
generateSingleTestReport(testResult, false);
}
private boolean isVideoInReport(ITestResult testResult) {
boolean videoInReport = false;
TestStep lastTestStep = TestNGResultUtils.getSeleniumRobotTestContext(testResult).getTestStepManager().getLastTestStep();
if (lastTestStep != null) {
for (GenericFile f: lastTestStep.getFiles()) {
if (f.getFile().getName().contains("video")) {
videoInReport = true;
}
}
}
return videoInReport;
}
public void generateExecutionReport(SeleniumTestsContext testContext, ITestResult testResult, String testStatus, boolean resourcesFromCdn) throws IOException {
VelocityEngine ve = initVelocityEngine();
Template t = ve.getTemplate("/reporter/templates/report.test.vm");
VelocityContext context = new VelocityContext();
context.put("staticPathPrefix", "../");
boolean displaySnapshots = testContext.getSeleniumRobotServerCompareSnapshot() && TestNGResultUtils.getSnapshotTestCaseInSessionId(testResult) != null && TestNGResultUtils.getSnapshotComparisonResult(testResult) != null;
context.put("snapshots", displaySnapshots);
context.put("snapshotServer", testContext.getSeleniumRobotServerUrl());
context.put("snapshotComparisonResult", TestNGResultUtils.getSnapshotComparisonResult(testResult));
context.put("snapshotSessionId", TestNGResultUtils.getSnapshotTestCaseInSessionId(testResult));
// optimize reports means that resources are get from internet
context.put("localResources", !resourcesFromCdn);
context.put(HEADER, testStatus);
// test header
Object[] testParameters = testResult.getParameters();
StringBuilder testName = new StringBuilder(getVisualTestName(testResult));
// issue #163: add test parameter to test name
if (testParameters.length > 0) {
testName.append(" with params: (");
int i = 0;
for (Object param: testParameters) {
// method parameters that should be masked are stored inside TestStepManager
if (param != null && testContext.getTestStepManager().getPwdToReplace().contains(param.toString())) {
testName.append("******");
} else {
testName.append(param == null ? "null": param.toString());
}
if (i < testParameters.length - 1) {
testName.append(",");
}
i++;
}
testName.append(")");
}
context.put("testName", StringUtility.encodeString(testName.toString(), "html"));
// by default, encodeString replaces line breaks with
which is not suitable for description
context.put("description", StringUtility.encodeString(TestNGResultUtils.getTestDescription(testResult), "html"));
// error causes
Map testInfos = TestNGResultUtils.getTestInfoEncoded(testResult, "html");
if (!TestNGResultUtils.getErrorCauses(testResult).isEmpty()) {
String causes = String.join("
", TestNGResultUtils.getErrorCauses(testResult)
.stream()
.map(e -> String.format("%s ", e))
.collect(Collectors.toList()));
testInfos.put("Possible error causes", String.format("%s
", causes));
}
context.put("testInfos", relocateTestInfos(testResult, testInfos));
// Application information
fillContextWithTestParams(context, testResult);
// test steps
List testSteps = TestNGResultUtils.getSeleniumRobotTestContext(testResult).getTestStepManager().getTestSteps();
if (testSteps == null) {
testSteps = new ArrayList<>();
}
boolean videoInReport = isVideoInReport(testResult);
List> steps = new ArrayList<>();
for (TestStep testStep: testSteps) {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy