diff --git a/CHANGELOG.md b/CHANGELOG.md
index c991c393..fdbf6442 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
Back to [Readme](README.md).
+## [3.11.0] - 2025-02-19
+
+### Added
+
+* "Copy to clipboard" button for step outputs, docstrings, text attachments and exception messages (#371)
+* Custom logo capability (#367)
+* New failures page that shows scenarios based on their exception (#362)
+* Tree view now takes the directory structure into account (#366)
+
+### Changed
+
+* Updated junit to `5.12.0-RC2`
+* Updated javadoc to `3.11.2`
+* Updated dagger to `2.55`
+* Updated gson to `2.12.1`
+
+### Fixed
+
+* Correct pluralization for zero elements everywhere
+
## [3.10.0] - 2025-01-06
### Added
@@ -962,6 +982,8 @@ the core component is now the reporting engine that is the base for other forms
Initial project version on GitHub and Maven Central.
+[3.11.0]: https://github.com/trivago/cluecumber-report-plugin/tree/v3.11.0
+
[3.10.0]: https://github.com/trivago/cluecumber-report-plugin/tree/v3.10.0
[3.9.0]: https://github.com/trivago/cluecumber-report-plugin/tree/v3.9.0
diff --git a/README.md b/README.md
index 2fd007ec..2db0c4ec 100644
--- a/README.md
+++ b/README.md
@@ -34,10 +34,12 @@ Cluecumber generates the following report pages:
* __Scenario Details__: all steps, hooks, stack traces and attachments of a single scenario
* __All Features__: an overview of all features
* __All Tags__: all used tags in scenarios, features and example tables including their individual status information
+* __All Exceptions__: all exception types that occurred in the test suite
* __All Steps__: all steps in use including their individual status information
* __Scenarios by Tag__: all scenarios including a specific tag
* __Scenarios by Feature__: all scenarios belonging to a specific feature
* __Scenario by Step__: all scenarios that include a specific step
+* __Scenario by Exception__: all scenarios that failed with a specific exception type
* __Tree View__: all features and scenarios in a tree for an easy overview of the test suite
## Changelog
@@ -48,7 +50,7 @@ All changes are documented in the [full changelog](CHANGELOG.md).
## Building
-Cluecumber requires Java >= 17 and Maven >= 3.6.3.
+Cluecumber requires Java >= 11 and Maven >= 3.6.3.
It is available in [Maven central](https://central.sonatype.com/search?q=g%3Acom.trivago.rta++a%3Acluecumber-core+a%3Acluecumber-maven&smo=true).
## Star History
diff --git a/core/README.md b/core/README.md
index 47b83b6f..af6ca72e 100644
--- a/core/README.md
+++ b/core/README.md
@@ -30,6 +30,7 @@ _Clear and concise JVM reporting for the Cucumber BDD JSON format_
- [Defining the report start page](#defining-the-report-start-page)
- [Defining a custom report title](#defining-a-custom-report-title)
- [Defining a custom CSS file](#defining-a-custom-css-file)
+ - [Defining a custom logo](#defining-a-custom-logo)
- [Defining a custom favicon](#defining-a-custom-favicon)
- [Defining custom passed, skipped and failed colors](#defining-custom-passed-skipped-and-failed-colors)
- [Enabling a compact view of multiple runs of the same scenarios](#enabling-a-compact-view-of-multiple-runs-of-the-same-scenarios)
@@ -45,7 +46,7 @@ _Clear and concise JVM reporting for the Cucumber BDD JSON format_
com.trivago.rtacluecumber-core
- 3.5.1
+ 3.11.0
```
@@ -346,6 +347,18 @@ Likewise, if you want to hide elements from the report, you can also add this to
}
```
+## Defining a custom logo
+
+The logo is displayed on every page in the top right corner and can be customized by setting the `customLogo` property. This must be
+a png file. It is automatically set to a maximum width of 300px and/or height of 100px if its size exceeds these values.
+
+
+
+```java
+new CluecumberCore.Builder()
+ .setCustomLogo("custom/logo.png")
+ .build().generateReports(jsonDirectory, reportDirectory);
+```
## Defining a custom favicon
diff --git a/core/src/main/java/com/trivago/cluecumber/core/CluecumberCore.java b/core/src/main/java/com/trivago/cluecumber/core/CluecumberCore.java
index dbaf1c67..8a77d24a 100644
--- a/core/src/main/java/com/trivago/cluecumber/core/CluecumberCore.java
+++ b/core/src/main/java/com/trivago/cluecumber/core/CluecumberCore.java
@@ -40,6 +40,7 @@ private CluecumberCore(final Builder builder) throws CluecumberException {
cluecumberEngine = DaggerCluecumberCoreGraph.create().getCluecumberEngine();
cluecumberEngine.setCustomCssFile(builder.customCssFile);
cluecumberEngine.setCustomFavicon(builder.customFavicon);
+ cluecumberEngine.setCustomLogo(builder.customLogo);
cluecumberEngine.setCustomNavigationLinks(builder.customNavigationLinks);
cluecumberEngine.setCustomPageTitle(builder.customPageTitle);
cluecumberEngine.setCustomParameters(builder.customParameters);
@@ -78,6 +79,7 @@ public void generateReports(final String jsonDirectory, final String reportDirec
public static class Builder {
private String customCssFile;
private String customFavicon;
+ private String customLogo;
private LinkedHashMap customNavigationLinks;
private String customPageTitle;
private LinkedHashMap customParameters;
@@ -137,6 +139,17 @@ public Builder setCustomFaviconFile(final String customFavicon) {
return this;
}
+ /**
+ * Custom logo to display in the page headers.
+ *
+ * @param customLogo The path to a logo png file.
+ * @return The {@link Builder}.
+ */
+ public Builder setCustomLogoFile(final String customLogo) {
+ this.customLogo = customLogo;
+ return this;
+ }
+
/**
* Custom navigation links to display at the end of the default navigation.
*
diff --git a/documentation/img/custom_logo.jpg b/documentation/img/custom_logo.jpg
new file mode 100644
index 00000000..696ffd30
Binary files /dev/null and b/documentation/img/custom_logo.jpg differ
diff --git a/engine/pom.xml b/engine/pom.xml
index f59ae2be..c25a69c6 100644
--- a/engine/pom.xml
+++ b/engine/pom.xml
@@ -32,8 +32,8 @@
2.8.0-M12.3.341.9.0
- 2.11.0
- 2.54
+ 2.12.1
+ 2.551.5.01.1.00.9.1
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/CluecumberEngine.java b/engine/src/main/java/com/trivago/cluecumber/engine/CluecumberEngine.java
index 844c3ead..a74c5296 100644
--- a/engine/src/main/java/com/trivago/cluecumber/engine/CluecumberEngine.java
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/CluecumberEngine.java
@@ -304,6 +304,19 @@ public void setCustomFavicon(final String customFavicon) throws MissingFileExcep
propertyManager.setCustomFaviconFile(customFavicon);
}
+ /**
+ * Custom logo image file to use for the report.
+ *
+ * @param customLogo The path to a logo file.
+ * @throws MissingFileException Thrown if the specified file does not exist.
+ */
+ public void setCustomLogo(final String customLogo) throws MissingFileException {
+ if (customLogo == null) {
+ return;
+ }
+ propertyManager.setCustomLogoFile(customLogo);
+ }
+
/**
* Set a custom color for passed scenarios.
*
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/constants/Navigation.java b/engine/src/main/java/com/trivago/cluecumber/engine/constants/Navigation.java
index 8b55eccf..2f3a0c2e 100644
--- a/engine/src/main/java/com/trivago/cluecumber/engine/constants/Navigation.java
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/constants/Navigation.java
@@ -42,6 +42,7 @@ public Navigation() {
new Link("tag_summary", "pages/tag-summary.html", LinkType.INTERNAL),
new Link("step_summary", "pages/step-summary.html", LinkType.INTERNAL),
new Link("feature_summary", "pages/feature-summary.html", LinkType.INTERNAL),
+ new Link("exception_summary", "pages/exception-summary.html", LinkType.INTERNAL),
new Link("tree_view", "pages/tree-view.html", LinkType.INTERNAL)
);
}
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/constants/Settings.java b/engine/src/main/java/com/trivago/cluecumber/engine/constants/Settings.java
index f6377dc2..cdc6cceb 100644
--- a/engine/src/main/java/com/trivago/cluecumber/engine/constants/Settings.java
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/constants/Settings.java
@@ -79,6 +79,18 @@ public Settings() {
* The first part of the name of scenario by tag pages.
*/
public static final String TAG_SCENARIO_PAGE_FRAGMENT = "/" + TAG_SCENARIO_PAGE_PATH + "/tag_";
+ /**
+ * The name of the exception summary page.
+ */
+ public final static String EXCEPTION_SUMMARY_PAGE = "exception-summary";
+ /**
+ * The folder of the scenarios by exception pages.
+ */
+ public static final String EXCEPTION_SCENARIO_PAGE_PATH = "exception-scenarios";
+ /**
+ * The first part of the name of scenario by exception pages.
+ */
+ public static final String EXCEPTION_SCENARIO_PAGE_FRAGMENT = "/" + EXCEPTION_SCENARIO_PAGE_PATH + "/exception_";
/**
* The name of the step summary page.
*/
@@ -129,6 +141,10 @@ public enum StartPage {
* The tag overview page.
*/
ALL_TAGS(TAG_SUMMARY_PAGE),
+ /**
+ * The tag overview page.
+ */
+ ALL_EXCEPTIONS(EXCEPTION_SUMMARY_PAGE),
/**
* The step overview page.
*/
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/json/pojo/Element.java b/engine/src/main/java/com/trivago/cluecumber/engine/json/pojo/Element.java
index 9140b899..03cbb708 100644
--- a/engine/src/main/java/com/trivago/cluecumber/engine/json/pojo/Element.java
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/json/pojo/Element.java
@@ -392,18 +392,26 @@ public Status getStatus() {
}
/**
- * Determine the first exception class in the stack trace to display on the scenario overview page.
+ * Get the first exception class in the stack trace to display
*
* @return The exception class string.
*/
public String getFirstExceptionClass() {
+ return getFirstExceptionSummary().split(":")[0].split(" ")[0].trim();
+ }
+
+ /**
+ * Determine the first exception summary in the stack trace to display on the scenario overview page.
+ *
+ * @return The exception class string.
+ */
+ public String getFirstExceptionSummary() {
String firstException = getFirstException();
String exceptionClass = firstException.split("\n")[0].trim();
if (exceptionClass.isEmpty()) {
exceptionClass = "";
}
-
return exceptionClass;
}
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/properties/PropertyManager.java b/engine/src/main/java/com/trivago/cluecumber/engine/properties/PropertyManager.java
index eb53dd34..a5e8e2a7 100644
--- a/engine/src/main/java/com/trivago/cluecumber/engine/properties/PropertyManager.java
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/properties/PropertyManager.java
@@ -63,6 +63,7 @@ public class PropertyManager {
private boolean expandPreviousScenarioRuns = false;
private String customCssFile;
private String customFaviconFile;
+ private String customLogoFile;
private String customParametersFile;
private Settings.CustomParamDisplayMode customParametersDisplayMode =
Settings.CustomParamDisplayMode.ALL_PAGES;
@@ -451,6 +452,32 @@ public void setCustomFaviconFile(final String customFaviconFile) throws MissingF
}
}
+ /**
+ * Get the custom logo file path.
+ *
+ * @return The path.
+ */
+ public String getCustomLogoFile() {
+ return customLogoFile;
+ }
+
+ /**
+ * Set the custom logo file path.
+ *
+ * @param customLogoFile The path.
+ * @throws MissingFileException Thrown if the file is not found.
+ */
+ public void setCustomLogoFile(final String customLogoFile) throws MissingFileException {
+ System.out.println("CUSTOM LOGO: " + customLogoFile);
+ this.customLogoFile = customLogoFile;
+ if (!isSet(customLogoFile)) {
+ return;
+ }
+ if (!fileIO.isExistingFile(customLogoFile)) {
+ throw new MissingFileException(customLogoFile + " (customLogoFile)");
+ }
+ }
+
/**
* Get the custom hex color for passed elements.
*
@@ -585,6 +612,9 @@ public void logProperties() {
if (isSet(customFaviconFile)) {
logger.info("- custom favicon file : " + customFaviconFile, DEFAULT);
}
+ if (isSet(customLogoFile)) {
+ logger.info("- custom logo file : " + customLogoFile, DEFAULT);
+ }
logger.info("- colors (passed, failed, skipped) : " +
customStatusColorPassed + ", " + customStatusColorFailed + ", " + customStatusColorSkipped, DEFAULT);
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/ReportGenerator.java b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/ReportGenerator.java
index fabb5859..3155e08b 100644
--- a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/ReportGenerator.java
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/ReportGenerator.java
@@ -93,6 +93,7 @@ public void generateReport(final AllScenariosPageCollection allScenariosPageColl
copyStaticReportAssets(reportDirectory);
copyCustomCss(reportDirectory);
copyCustomFavicon(reportDirectory);
+ copyCustomLogo(reportDirectory);
boolean redirectToFirstScenarioPage =
propertyManager.getStartPage() == Settings.StartPage.ALL_SCENARIOS &&
@@ -126,6 +127,7 @@ private void createDirectories(final String reportDirectory) throws PathCreation
fileSystemManager.createDirectory(pagesDirectory + Settings.SCENARIO_DETAIL_PAGE_PATH);
fileSystemManager.createDirectory(pagesDirectory + Settings.FEATURE_SCENARIOS_PAGE_PATH);
fileSystemManager.createDirectory(pagesDirectory + Settings.TAG_SCENARIO_PAGE_PATH);
+ fileSystemManager.createDirectory(pagesDirectory + Settings.EXCEPTION_SCENARIO_PAGE_PATH);
fileSystemManager.createDirectory(pagesDirectory + Settings.STEP_SCENARIO_PAGE_PATH);
}
@@ -161,6 +163,18 @@ private void copyCustomFavicon(final String reportDirectory) throws CluecumberEx
}
}
+ /**
+ * Copy custom logo to the specified target directory.
+ */
+ private void copyCustomLogo(final String reportDirectory) throws CluecumberException {
+ String customLogo = propertyManager.getCustomLogoFile();
+ if (customLogo != null && !customLogo.isEmpty()) {
+ fileSystemManager.copyResource(customLogo, reportDirectory + "/img/logo.png");
+ } else {
+ copyFileFromJarToReportDirectory("/img/logo.png");
+ }
+ }
+
/**
* Copy all needed static report assets to the specified target directory.
*
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/pojos/pagecollections/AllExceptionsPageCollection.java b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/pojos/pagecollections/AllExceptionsPageCollection.java
new file mode 100644
index 00000000..34b141fa
--- /dev/null
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/pojos/pagecollections/AllExceptionsPageCollection.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2023 trivago N.V.
+ *
+ * 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.trivago.cluecumber.engine.rendering.pages.pojos.pagecollections;
+
+import com.trivago.cluecumber.engine.json.pojo.Report;
+import com.trivago.cluecumber.engine.rendering.pages.pojos.ResultCount;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Page collection for the exception overview page.
+ */
+public class AllExceptionsPageCollection extends ScenarioSummaryPageCollection {
+ private final Map exceptionResultCounts = new HashMap<>();
+
+ /**
+ * Constructor.
+ *
+ * @param reports The {@link Report} list.
+ * @param pageTitle The page title.
+ */
+ public AllExceptionsPageCollection(List reports, final String pageTitle) {
+ super(pageTitle);
+ calculateExceptionResultCounts(reports);
+ }
+
+ /**
+ * Get a map of {@link ResultCount} lists connected to tag names.
+ *
+ * @return a map of {@link ResultCount} lists with tags as keys.
+ */
+ public Map getExceptionResultCounts() {
+ return exceptionResultCounts;
+ }
+
+ /**
+ * Get all exceptions.
+ *
+ * @return The exception set.
+ */
+ public Set getExceptions() {
+ return exceptionResultCounts.keySet();
+ }
+
+ /**
+ * Get the number of exceptions.
+ *
+ * @return The count.
+ */
+ public int getTotalNumberOfExceptions() {
+ return exceptionResultCounts.size();
+ }
+
+ /**
+ * Calculate the numbers of failures, successes and skips per exception.
+ *
+ * @param reports The {@link Report} list.
+ */
+ private void calculateExceptionResultCounts(final List reports) {
+ if (reports == null) return;
+ reports.forEach(report -> report.getElements().forEach(element -> {
+ String exceptionClass = element.getFirstExceptionClass();
+ if (exceptionClass != null && !exceptionClass.isEmpty()) {
+ ResultCount exceptionResultCount = exceptionResultCounts.getOrDefault(exceptionClass, new ResultCount());
+ updateResultCount(exceptionResultCount, element.getStatus());
+ exceptionResultCounts.put(exceptionClass, exceptionResultCount);
+ addScenarioIndexByStatus(element.getStatus(), element.getScenarioIndex());
+ }
+ }));
+ }
+}
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/pojos/pagecollections/AllScenariosPageCollection.java b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/pojos/pagecollections/AllScenariosPageCollection.java
index 222c95df..5340e1fc 100644
--- a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/pojos/pagecollections/AllScenariosPageCollection.java
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/pojos/pagecollections/AllScenariosPageCollection.java
@@ -59,6 +59,7 @@ public class AllScenariosPageCollection extends PageCollection implements Visita
private Tag tagFilter;
private Feature featureFilter;
private Step stepFilter;
+ private String exceptionFilter;
/**
* Constructor.
@@ -269,7 +270,7 @@ private ZonedDateTime getEarliestStartDateTime() {
for (Element element : report.getElements()) {
ZonedDateTime currentStartDateTime = element.getStartDateTime();
if (currentStartDateTime != null &&
- (earliestStartDateTime == null || currentStartDateTime.isBefore(earliestStartDateTime))) {
+ (earliestStartDateTime == null || currentStartDateTime.isBefore(earliestStartDateTime))) {
earliestStartDateTime = currentStartDateTime;
}
}
@@ -283,7 +284,7 @@ private ZonedDateTime getLatestEndDateTime() {
for (Element element : report.getElements()) {
ZonedDateTime currentEndDateTime = element.getEndDateTime();
if (currentEndDateTime != null &&
- (latestEndDateTime == null || currentEndDateTime.isAfter(latestEndDateTime))) {
+ (latestEndDateTime == null || currentEndDateTime.isAfter(latestEndDateTime))) {
latestEndDateTime = currentEndDateTime;
}
}
@@ -300,7 +301,7 @@ public String returnStartDateTimeString() {
ZonedDateTime earliestStartDateTime = getEarliestStartDateTime();
if (earliestStartDateTime != null) {
return RenderingUtils.convertZonedDateTimeToDateString(earliestStartDateTime) + " " +
- RenderingUtils.convertZonedDateTimeToTimeString(earliestStartDateTime);
+ RenderingUtils.convertZonedDateTimeToTimeString(earliestStartDateTime);
}
return "";
}
@@ -314,7 +315,7 @@ public String returnEndDateTimeString() {
ZonedDateTime latestEndDateTime = getLatestEndDateTime();
if (latestEndDateTime != null) {
return RenderingUtils.convertZonedDateTimeToDateString(latestEndDateTime) + " " +
- RenderingUtils.convertZonedDateTimeToTimeString(latestEndDateTime);
+ RenderingUtils.convertZonedDateTimeToTimeString(latestEndDateTime);
}
return "";
}
@@ -337,6 +338,24 @@ public void setTagFilter(final Tag tagFilter) {
this.tagFilter = tagFilter;
}
+ /**
+ * Get the current exception filter to filter scenarios by exception message.
+ *
+ * @return The exception filter.
+ */
+ public String getExceptionFilter() {
+ return exceptionFilter;
+ }
+
+ /**
+ * Set the current exception filter to filter scenarios by exception message.
+ *
+ * @param exceptionFilter The exception filter.
+ */
+ public void setExceptionFilter(final String exceptionFilter) {
+ this.exceptionFilter = exceptionFilter;
+ }
+
/**
* Return the feature by which scenarios are filtered.
*
@@ -420,6 +439,7 @@ public AllScenariosPageCollection clone() throws CloneNotSupportedException {
clone.setFeatureFilter(null);
clone.setStepFilter(null);
clone.setTagFilter(null);
+ clone.setExceptionFilter(null);
clone.clearReports();
List clonedReports = new ArrayList<>();
for (Report r : getReports()) {
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/pojos/pagecollections/TreeViewPageCollection.java b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/pojos/pagecollections/TreeViewPageCollection.java
index 13d52950..b93d1b78 100644
--- a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/pojos/pagecollections/TreeViewPageCollection.java
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/pojos/pagecollections/TreeViewPageCollection.java
@@ -15,54 +15,42 @@
*/
package com.trivago.cluecumber.engine.rendering.pages.pojos.pagecollections;
-import com.trivago.cluecumber.engine.json.pojo.Element;
-import com.trivago.cluecumber.engine.rendering.pages.pojos.Feature;
-
-import java.util.List;
-import java.util.Map;
+import com.trivago.cluecumber.engine.rendering.pages.renderering.TreeNode;
/**
* Page collection for the tree view page.
*/
public class TreeViewPageCollection extends PageCollection {
- private final Map> elements;
+ private final TreeNode rootTreeNode;
+ private final int numberOfFeatures;
+ private final int numberOfScenarios;
/**
* Constructor.
*
- * @param elements The map of features and associated scenarios.
- * @param pageTitle The title of the tree view page.
+ * @param rootTreeNode The root node of the tree view.
+ * @param pageTitle The title of the tree view page.
*/
- public TreeViewPageCollection(final Map> elements, final String pageTitle) {
+ public TreeViewPageCollection(final TreeNode rootTreeNode,
+ final String pageTitle,
+ final int numberOfFeatures,
+ final int numberOfScenarios) {
super(pageTitle);
- this.elements = elements;
+ this.rootTreeNode = rootTreeNode;
+ this.numberOfFeatures = numberOfFeatures;
+ this.numberOfScenarios = numberOfScenarios;
}
- /**
- * Get the list of features and their scenarios.
- *
- * @return The map of features and associated scenarios.
- */
- public Map> getElements() {
- return elements;
+ public TreeNode getRootTreeNode() {
+ return rootTreeNode;
}
- /**
- * Retrieve the total number of features.
- *
- * @return The count.
- */
- public int getNumberOfFeatures() {
- return elements.size();
+ public int getNumberOfFeatures(){
+ return numberOfFeatures;
}
- /**
- * Retrieve the total number of scenarios.
- *
- * @return The count.
- */
- public int getNumberOfScenarios() {
- return elements.values().stream().mapToInt(List::size).sum();
+ public int getNumberOfScenarios(){
+ return numberOfScenarios;
}
}
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/renderering/AllExceptionsPageRenderer.java b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/renderering/AllExceptionsPageRenderer.java
new file mode 100644
index 00000000..7514a0e3
--- /dev/null
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/renderering/AllExceptionsPageRenderer.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2023 trivago N.V.
+ *
+ * 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.trivago.cluecumber.engine.rendering.pages.renderering;
+
+import com.trivago.cluecumber.engine.constants.ChartConfiguration;
+import com.trivago.cluecumber.engine.constants.Settings;
+import com.trivago.cluecumber.engine.constants.Status;
+import com.trivago.cluecumber.engine.exceptions.CluecumberException;
+import com.trivago.cluecumber.engine.properties.PropertyManager;
+import com.trivago.cluecumber.engine.rendering.pages.charts.ChartJsonConverter;
+import com.trivago.cluecumber.engine.rendering.pages.charts.StackedBarChartBuilder;
+import com.trivago.cluecumber.engine.rendering.pages.charts.pojos.Chart;
+import com.trivago.cluecumber.engine.rendering.pages.pojos.ResultCount;
+import com.trivago.cluecumber.engine.rendering.pages.pojos.pagecollections.AllExceptionsPageCollection;
+import freemarker.template.Template;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The renderer for the exceptions overview page.
+ */
+@Singleton
+public class AllExceptionsPageRenderer extends PageWithChartRenderer {
+
+ private final ChartConfiguration chartConfiguration;
+ private final PropertyManager propertyManager;
+
+ /**
+ * Constructor for dependency injection.
+ *
+ * @param chartJsonConverter The {@link ChartJsonConverter} instance.
+ * @param chartConfiguration The {@link ChartConfiguration} instance.
+ * @param propertyManager The {@link PropertyManager} instance.
+ */
+ @Inject
+ public AllExceptionsPageRenderer(
+ final ChartJsonConverter chartJsonConverter,
+ final ChartConfiguration chartConfiguration,
+ final PropertyManager propertyManager
+ ) {
+ super(chartJsonConverter);
+ this.chartConfiguration = chartConfiguration;
+ this.propertyManager = propertyManager;
+ }
+
+ /**
+ * Get the rendered HTML content.
+ *
+ * @param allExceptionsPageCollection The {@link AllExceptionsPageCollection} instance.
+ * @param template THe {@link Template} instance.
+ * @return The HTML string.
+ * @throws CluecumberException Thrown on any error.
+ */
+ public String getRenderedContent(
+ final AllExceptionsPageCollection allExceptionsPageCollection, final Template template)
+ throws CluecumberException {
+
+ addChartJsonToReportDetails(allExceptionsPageCollection);
+
+ if (propertyManager.getCustomParametersDisplayMode() == Settings.CustomParamDisplayMode.ALL_PAGES) {
+ addCustomParametersToReportDetails(allExceptionsPageCollection, propertyManager.getCustomParameters());
+ }
+
+ return processedContent(template, allExceptionsPageCollection, propertyManager.getNavigationLinks());
+ }
+
+ private void addChartJsonToReportDetails(final AllExceptionsPageCollection allExceptionsPageCollection) {
+
+ List passed = new ArrayList<>();
+ List failed = new ArrayList<>();
+ List skipped = new ArrayList<>();
+ Map urlLookup = new HashMap<>();
+
+ int maximumNumberOfRuns = 0;
+ for (Map.Entry entry : allExceptionsPageCollection.getExceptionResultCounts().entrySet()) {
+ urlLookup.put(
+ entry.getKey(),
+ Settings.PAGES_DIRECTORY + Settings.EXCEPTION_SCENARIO_PAGE_FRAGMENT +
+ entry.getKey() + Settings.HTML_FILE_EXTENSION);
+ ResultCount exceptionResultCount = entry.getValue();
+ passed.add((float) exceptionResultCount.getPassed());
+ failed.add((float) exceptionResultCount.getFailed());
+ skipped.add((float) exceptionResultCount.getSkipped());
+ if (exceptionResultCount.getTotal() > maximumNumberOfRuns) {
+ maximumNumberOfRuns = exceptionResultCount.getTotal();
+ }
+ }
+
+ List keys = new ArrayList<>();
+ for (String exception : allExceptionsPageCollection.getExceptionResultCounts().keySet()) {
+ keys.add(exception);
+ }
+
+ Chart chart =
+ new StackedBarChartBuilder(chartConfiguration)
+ .setLabels(keys)
+ .setxAxisLabel(allExceptionsPageCollection.getTotalNumberOfExceptions() + " Exceptions")
+ .setyAxisLabel("Number of Scenarios")
+ .setyAxisStepSize(maximumNumberOfRuns)
+ .addValues(passed, Status.PASSED)
+ .addValues(failed, Status.FAILED)
+ .addValues(skipped, Status.SKIPPED)
+ .build();
+
+ allExceptionsPageCollection.getReportDetails().setChartJson(convertChartToJson(chart));
+ allExceptionsPageCollection.getReportDetails().setChartUrlLookup(urlLookup);
+ }
+}
+
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/renderering/AllScenariosPageRenderer.java b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/renderering/AllScenariosPageRenderer.java
index 9986dbd2..4b38de5e 100644
--- a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/renderering/AllScenariosPageRenderer.java
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/renderering/AllScenariosPageRenderer.java
@@ -80,8 +80,9 @@ public String getRenderedContent(
/**
* Get the rendered HTML content for the reruns page.
+ *
* @param allScenariosPageCollection The {@link AllScenariosPageCollection} instance.
- * @param template The {@link Template} instance.
+ * @param template The {@link Template} instance.
* @return The HTML content as a string.
* @throws CluecumberException Thrown on any error.
*/
@@ -130,6 +131,36 @@ public String getRenderedContentByTagFilter(
return processedContent(template, allScenariosPageCollectionClone, propertyManager.getNavigationLinks());
}
+ /**
+ * Get the rendered HTML content after applying an exception filter.
+ *
+ * @param allScenariosPageCollection The {@link AllScenariosPageCollection} instance.
+ * @param template The {@link Template} instance.
+ * @param exceptionClass The exception class to filter by.
+ * @return The HTML content as a string.
+ * @throws CluecumberException Thrown on any error.
+ */
+ public String getRenderedContentByExceptionFilter(
+ final AllScenariosPageCollection allScenariosPageCollection,
+ final Template template,
+ final String exceptionClass) throws CluecumberException {
+
+ AllScenariosPageCollection allScenariosPageCollectionClone = getAllScenariosPageCollectionClone(allScenariosPageCollection);
+ allScenariosPageCollectionClone.setExceptionFilter(exceptionClass);
+
+ allScenariosPageCollectionClone.getReports().forEach(report -> {
+ List elements = report.getElements()
+ .stream()
+ .filter(element -> element.getFirstExceptionClass().equals(exceptionClass))
+ .collect(Collectors.toList());
+ report.setElements(elements);
+ });
+
+ addChartJsonToReportDetails(allScenariosPageCollectionClone);
+ return processedContent(template, allScenariosPageCollectionClone, propertyManager.getNavigationLinks());
+ }
+
+
/**
* Get the rendered HTML content after applying a step filter.
*
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/renderering/TreeNode.java b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/renderering/TreeNode.java
new file mode 100644
index 00000000..ac01e1ce
--- /dev/null
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/renderering/TreeNode.java
@@ -0,0 +1,31 @@
+package com.trivago.cluecumber.engine.rendering.pages.renderering;
+
+import com.trivago.cluecumber.engine.json.pojo.Element;
+import com.trivago.cluecumber.engine.rendering.pages.pojos.Feature;
+
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class TreeNode {
+ private final String name;
+ private final TreeMap children = new TreeMap<>();
+ private final Map> features;
+
+ public TreeNode(final String name, final Map> features) {
+ this.name = name;
+ this.features = features;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Map getChildren() {
+ return children;
+ }
+
+ public Map> getFeatures() {
+ return features;
+ }
+}
\ No newline at end of file
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/renderering/TreeViewPageRenderer.java b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/renderering/TreeViewPageRenderer.java
index d4f91797..f1400325 100644
--- a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/renderering/TreeViewPageRenderer.java
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/renderering/TreeViewPageRenderer.java
@@ -41,6 +41,7 @@
public class TreeViewPageRenderer extends PageRenderer {
private final PropertyManager propertyManager;
+ private TreeNode rootTreeNode;
/**
* Constructor for dependency injection.
@@ -48,9 +49,7 @@ public class TreeViewPageRenderer extends PageRenderer {
* @param propertyManager The {@link PropertyManager} instance.
*/
@Inject
- public TreeViewPageRenderer(
- final PropertyManager propertyManager
- ) {
+ public TreeViewPageRenderer(final PropertyManager propertyManager) {
this.propertyManager = propertyManager;
}
@@ -69,19 +68,48 @@ public String getRenderedContent(
final Template template)
throws CluecumberException {
- Map> scenariosPerFeatures = new LinkedHashMap<>();
Set features = allFeaturesPageCollection.getFeatures()
.stream().sorted(Comparator.comparing(Feature::getName))
.collect(Collectors.toCollection(LinkedHashSet::new));
+
+ rootTreeNode = new TreeNode("root", null);
+ int numberOfFeatures = features.size();
+ int numberOfScenarios = 0;
for (Feature feature : features) {
- scenariosPerFeatures.put(feature, allScenariosPageCollection.getElementsByFeatureIndex(feature.getIndex()));
+ Map> scenariosPerFeatures = new LinkedHashMap<>();
+ String uri = feature.getUri();
+ List scenarios = allScenariosPageCollection.getElementsByFeatureIndex(feature.getIndex());
+ numberOfScenarios += scenarios.size();
+ scenariosPerFeatures.put(feature, scenarios);
+ addPath(uri, scenariosPerFeatures);
}
return processedContent(
template,
- new TreeViewPageCollection(scenariosPerFeatures, allFeaturesPageCollection.getPageTitle()),
+ new TreeViewPageCollection(
+ rootTreeNode,
+ allFeaturesPageCollection.getPageTitle(),
+ numberOfFeatures,
+ numberOfScenarios
+ ),
propertyManager.getNavigationLinks()
);
}
-}
\ No newline at end of file
+ public void addPath(final String path, final Map> features) {
+ String[] parts = path.split("/");
+ TreeNode current = rootTreeNode;
+
+ for (String part : parts) {
+ if (!part.isEmpty()) {
+ Map> tmpFeatures;
+ if (part.endsWith(".feature")) {
+ tmpFeatures = features;
+ } else {
+ tmpFeatures = null;
+ }
+ current = current.getChildren().computeIfAbsent(part, k -> new TreeNode(part, tmpFeatures));
+ }
+ }
+ }
+}
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/templates/TemplateConfiguration.java b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/templates/TemplateConfiguration.java
index f02a5169..64b2f818 100644
--- a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/templates/TemplateConfiguration.java
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/templates/TemplateConfiguration.java
@@ -44,7 +44,7 @@ public TemplateConfiguration() {
* @param basePath The base path for the templates.
*/
public void init(final String basePath) {
- cfg = new Configuration(Configuration.VERSION_2_3_31);
+ cfg = new Configuration(Configuration.VERSION_2_3_34);
cfg.setClassForTemplateLoading(this.getClass(), basePath);
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/templates/TemplateEngine.java b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/templates/TemplateEngine.java
index d1cb49ab..e57d631b 100644
--- a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/templates/TemplateEngine.java
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/templates/TemplateEngine.java
@@ -82,6 +82,10 @@ public enum Template {
* Tag overview template.
*/
ALL_TAGS("tag-summary"),
+ /**
+ * Exception overview template.
+ */
+ ALL_EXCEPTIONS("exception-summary"),
/**
* Scenario detail template.
*/
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/visitors/ExceptionVisitor.java b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/visitors/ExceptionVisitor.java
new file mode 100644
index 00000000..06bc89cb
--- /dev/null
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/visitors/ExceptionVisitor.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2023 trivago N.V.
+ *
+ * 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.trivago.cluecumber.engine.rendering.pages.visitors;
+
+import com.trivago.cluecumber.engine.constants.Settings;
+import com.trivago.cluecumber.engine.exceptions.CluecumberException;
+import com.trivago.cluecumber.engine.filesystem.FileIO;
+import com.trivago.cluecumber.engine.properties.PropertyManager;
+import com.trivago.cluecumber.engine.rendering.pages.pojos.pagecollections.AllExceptionsPageCollection;
+import com.trivago.cluecumber.engine.rendering.pages.pojos.pagecollections.AllScenariosPageCollection;
+import com.trivago.cluecumber.engine.rendering.pages.renderering.AllExceptionsPageRenderer;
+import com.trivago.cluecumber.engine.rendering.pages.renderering.AllScenariosPageRenderer;
+import com.trivago.cluecumber.engine.rendering.pages.templates.TemplateEngine;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import static com.trivago.cluecumber.engine.rendering.pages.templates.TemplateEngine.Template.ALL_EXCEPTIONS;
+import static com.trivago.cluecumber.engine.rendering.pages.templates.TemplateEngine.Template.ALL_SCENARIOS;
+
+/**
+ * The visitor for exception related pages.
+ */
+@Singleton
+public class ExceptionVisitor implements PageVisitor {
+
+ private final FileIO fileIO;
+ private final TemplateEngine templateEngine;
+ private final PropertyManager propertyManager;
+ private final AllExceptionsPageRenderer allExceptionsPageRenderer;
+ private final AllScenariosPageRenderer allScenariosPageRenderer;
+
+ /**
+ * The constructor for dependency injection.
+ *
+ * @param fileIO The {@link FileIO} instance.
+ * @param templateEngine The Freemarker template engine.
+ * @param propertyManager The {@link PropertyManager} instance.
+ * @param allExceptionsPageRenderer The renderer for exception pages.
+ * @param allScenariosPageRenderer The renderer for the scenario pages.
+ */
+ @Inject
+ public ExceptionVisitor(
+ final FileIO fileIO,
+ final TemplateEngine templateEngine,
+ final PropertyManager propertyManager,
+ final AllExceptionsPageRenderer allExceptionsPageRenderer,
+ final AllScenariosPageRenderer allScenariosPageRenderer
+ ) {
+ this.fileIO = fileIO;
+ this.templateEngine = templateEngine;
+ this.propertyManager = propertyManager;
+ this.allExceptionsPageRenderer = allExceptionsPageRenderer;
+ this.allScenariosPageRenderer = allScenariosPageRenderer;
+ }
+
+ /**
+ * The main method that is called on this visitor.
+ *
+ * @param allScenariosPageCollection The scenarios page collection.
+ * @throws CluecumberException Thrown on all errors.
+ */
+ @Override
+ public void visit(final AllScenariosPageCollection allScenariosPageCollection) throws CluecumberException {
+ AllExceptionsPageCollection allExceptionsPageCollection = new AllExceptionsPageCollection(
+ allScenariosPageCollection.getReports(), propertyManager.getCustomPageTitle()
+ );
+
+ // All exceptions page
+ fileIO.writeContentToFile(
+ allExceptionsPageRenderer.getRenderedContent(
+ allExceptionsPageCollection,
+ templateEngine.getTemplate(ALL_EXCEPTIONS)
+ ),
+ propertyManager.getGeneratedHtmlReportDirectory() + "/" + Settings.PAGES_DIRECTORY + "/" +
+ Settings.EXCEPTION_SUMMARY_PAGE + Settings.HTML_FILE_EXTENSION);
+
+ // Scenarios by exception pages
+ for (String exception : allExceptionsPageCollection.getExceptions()) {
+ fileIO.writeContentToFile(
+ allScenariosPageRenderer.getRenderedContentByExceptionFilter(
+ allScenariosPageCollection, templateEngine.getTemplate(ALL_SCENARIOS), exception),
+ propertyManager.getGeneratedHtmlReportDirectory() + "/" +
+ Settings.PAGES_DIRECTORY + Settings.EXCEPTION_SCENARIO_PAGE_FRAGMENT +
+ exception + Settings.HTML_FILE_EXTENSION);
+ }
+ }
+}
\ No newline at end of file
diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/visitors/VisitorDirectory.java b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/visitors/VisitorDirectory.java
index b2facb27..b6deb663 100644
--- a/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/visitors/VisitorDirectory.java
+++ b/engine/src/main/java/com/trivago/cluecumber/engine/rendering/pages/visitors/VisitorDirectory.java
@@ -31,22 +31,25 @@ public class VisitorDirectory {
/**
* Constructor for dependency injection.
*
- * @param featureVisitor The {@link FeatureVisitor} instance.
- * @param scenarioVisitor The {@link ScenarioVisitor} instance.
- * @param stepVisitor The {@link StepVisitor} instance.
- * @param tagVisitor The {@link TagVisitor} instance.
+ * @param scenarioVisitor The {@link ScenarioVisitor} instance.
+ * @param featureVisitor The {@link FeatureVisitor} instance.
+ * @param tagVisitor The {@link TagVisitor} instance.
+ * @param exceptionVisitor The {@link ExceptionVisitor} instance.
+ * @param stepVisitor The {@link StepVisitor} instance.
*/
@Inject
public VisitorDirectory(
final ScenarioVisitor scenarioVisitor,
final FeatureVisitor featureVisitor,
final TagVisitor tagVisitor,
+ final ExceptionVisitor exceptionVisitor,
final StepVisitor stepVisitor
) {
visitors = new ArrayList<>();
visitors.add(scenarioVisitor);
visitors.add(featureVisitor);
visitors.add(tagVisitor);
+ visitors.add(exceptionVisitor);
visitors.add(stepVisitor);
}
diff --git a/engine/src/main/resources/template/css/cluecumber.css b/engine/src/main/resources/template/css/cluecumber.css
index 1c0eca63..1e76540c 100644
--- a/engine/src/main/resources/template/css/cluecumber.css
+++ b/engine/src/main/resources/template/css/cluecumber.css
@@ -24,6 +24,10 @@ html {
max-width: 2000px;
}
+h3 {
+ margin-top: 0;
+}
+
h2, h3, h4, h5 {
overflow-wrap: break-word;
white-space: pre-line;
@@ -81,11 +85,8 @@ a {
}
#tree-view li {
- list-style-type: none;
+ list-style-type: disclosure-open;
text-align: left;
-}
-
-#tree-view ul li {
margin-bottom: .4rem;
}
diff --git a/engine/src/main/resources/template/exception-summary.ftl b/engine/src/main/resources/template/exception-summary.ftl
new file mode 100644
index 00000000..64d5e22c
--- /dev/null
+++ b/engine/src/main/resources/template/exception-summary.ftl
@@ -0,0 +1,84 @@
+<#--
+Copyright 2023 trivago N.V.
+
+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.
+-->
+
+<#import "macros/page.ftl"as page>
+<#import "macros/common.ftl" as common>
+<#import "macros/navigation.ftl" as navigation>
+<#import "macros/custom-parameters.ftl" as customparams>
+
+<@page.page
+title="${pageTitle} - All Exceptions"
+base=".."
+highlight="exception_summary"
+headline="All Exceptions"
+subheadline=""
+subsubheadline=""
+preheadline=""
+preheadlineLink="">
+
+ <#if hasCustomParameters()>
+ <@customparams.card customParams=customParameters/>
+ #if>
+
+
@page.page>
diff --git a/engine/src/test/java/com/trivago/cluecumber/engine/rendering/ReportGeneratorTest.java b/engine/src/test/java/com/trivago/cluecumber/engine/rendering/ReportGeneratorTest.java
index d51419dd..6f932a07 100644
--- a/engine/src/test/java/com/trivago/cluecumber/engine/rendering/ReportGeneratorTest.java
+++ b/engine/src/test/java/com/trivago/cluecumber/engine/rendering/ReportGeneratorTest.java
@@ -92,7 +92,7 @@ public void fileOperationsTest() throws CluecumberException {
reportGenerator.generateReport(allScenariosPageCollection);
- verify(fileSystemManager, times(9)).createDirectory(anyString());
- verify(fileSystemManager, times(18)).copyResourceFromJar(anyString(), anyString());
+ verify(fileSystemManager, times(10)).createDirectory(anyString());
+ verify(fileSystemManager, times(19)).copyResourceFromJar(anyString(), anyString());
}
}
diff --git a/engine/src/test/java/com/trivago/cluecumber/engine/rendering/pages/pojos/pagecollections/PojoTest.java b/engine/src/test/java/com/trivago/cluecumber/engine/rendering/pages/pojos/pagecollections/PojoTest.java
index b57c00b0..0d28b7ab 100644
--- a/engine/src/test/java/com/trivago/cluecumber/engine/rendering/pages/pojos/pagecollections/PojoTest.java
+++ b/engine/src/test/java/com/trivago/cluecumber/engine/rendering/pages/pojos/pagecollections/PojoTest.java
@@ -15,7 +15,7 @@
import java.util.List;
public class PojoTest {
- private static final int EXPECTED_CLASS_COUNT = 12;
+ private static final int EXPECTED_CLASS_COUNT = 13;
private static final String POJO_PACKAGE = "com.trivago.cluecumber.engine.rendering.pages.pojos.pagecollections";
@BeforeAll
diff --git a/engine/src/test/java/com/trivago/cluecumber/engine/rendering/pages/visitors/VisitorDirectoryTest.java b/engine/src/test/java/com/trivago/cluecumber/engine/rendering/pages/visitors/VisitorDirectoryTest.java
index 624de2e7..da99d210 100644
--- a/engine/src/test/java/com/trivago/cluecumber/engine/rendering/pages/visitors/VisitorDirectoryTest.java
+++ b/engine/src/test/java/com/trivago/cluecumber/engine/rendering/pages/visitors/VisitorDirectoryTest.java
@@ -14,17 +14,19 @@ public void setUp() {
ScenarioVisitor scenarioVisitor = mock(ScenarioVisitor.class);
FeatureVisitor featureVisitor = mock(FeatureVisitor.class);
TagVisitor tagVisitor = mock(TagVisitor.class);
+ ExceptionVisitor exceptionVisitor = mock(ExceptionVisitor.class);
StepVisitor stepVisitor = mock(StepVisitor.class);
visitorDirectory = new VisitorDirectory(
scenarioVisitor,
featureVisitor,
tagVisitor,
+ exceptionVisitor,
stepVisitor
);
}
@Test
public void getVisitorDirectoryTest() {
- assertEquals(visitorDirectory.getVisitors().size(), 4);
+ assertEquals(visitorDirectory.getVisitors().size(), 5);
}
}
diff --git a/examples/core-example/pom.xml b/examples/core-example/pom.xml
index 210eb1df..00cf9b9d 100644
--- a/examples/core-example/pom.xml
+++ b/examples/core-example/pom.xml
@@ -6,7 +6,7 @@
blog.softwaretestercore-example
- 3.10.0
+ 3.11.0jar
diff --git a/examples/maven-example/README.md b/examples/maven-example/README.md
index 208d6c48..5abe7f19 100644
--- a/examples/maven-example/README.md
+++ b/examples/maven-example/README.md
@@ -4,8 +4,8 @@
- [Cluecumber Maven Example](#cluecumber-maven-example)
- - [Configuration options](#configuration-options)
- - [Run the project](#run-the-project)
+ - [Configuration options](#configuration-options)
+ - [Run the project](#run-the-project)
@@ -24,8 +24,10 @@ You can add different options as explained in the [Cluecumber Maven Readme](../.
To run the project you need to have at least Java 11 and Maven 3.3.9 installed on your system.
-Just run the Maven command ```mvn clean verify``` to see the report generation of Cluecumber in action.
+Just run the Maven command `mvn clean verify` to see the report generation of Cluecumber in action.
+This can also be run via `make test` from Cluecumber's root directory.
-The example Cucumber JSON files are located in the project's `json` directory. These are based on the https://github.com/aslakhellesoy/cucumber-json-formatter project.
+The example Cucumber JSON files are located in the project's `json` directory. These are based on
+the https://github.com/aslakhellesoy/cucumber-json-formatter project.
The report is generated inside the `target/cluecumber-report` directory.
diff --git a/examples/maven-example/custom/logo.png b/examples/maven-example/custom/logo.png
new file mode 100644
index 00000000..30003fda
Binary files /dev/null and b/examples/maven-example/custom/logo.png differ
diff --git a/examples/maven-example/pom.xml b/examples/maven-example/pom.xml
index c9f19523..7eb77650 100644
--- a/examples/maven-example/pom.xml
+++ b/examples/maven-example/pom.xml
@@ -6,7 +6,7 @@
blog.softwaretestermaven-example
- 3.10.0
+ 3.11.0pom
@@ -72,10 +72,13 @@
-
+
-
+ ${project.basedir}/custom/favicon.png
+
+
+ ${project.basedir}/custom/logo.pngfalse
diff --git a/maven/README.md b/maven/README.md
index f855d8c8..c1cd9c7f 100644
--- a/maven/README.md
+++ b/maven/README.md
@@ -33,6 +33,7 @@ _Clear and concise Maven reporting for the Cucumber BDD JSON format_
- [Defining the report start page](#defining-the-report-start-page)
- [Defining a custom report title](#defining-a-custom-report-title)
- [Defining a custom CSS file](#defining-a-custom-css-file)
+ - [Defining a custom logo](#defining-a-custom-logo)
- [Defining a custom favicon](#defining-a-custom-favicon)
- [Defining custom passed, skipped and failed colors](#defining-custom-passed-skipped-and-failed-colors)
- [Enabling a compact view of multiple runs of the same scenarios](#enabling-a-compact-view-of-multiple-runs-of-the-same-scenarios)
@@ -52,7 +53,7 @@ _Clear and concise Maven reporting for the Cucumber BDD JSON format_
com.trivago.rtacluecumber-maven
- 3.1.0
+ 3.11.0report
@@ -390,6 +391,20 @@ Likewise, if you want to hide elements from the report, you can also add this to
}
```
+## Defining a custom logo
+
+The logo is displayed on every page in the top right corner and can be customized by setting the `customLogo` property. This must be
+a png file. It is automatically set to a maximum width of 300px and/or height of 100px if its size exceeds these values.
+
+
+
+```xml
+
+ custom/logo.png
+ ...
+
+```
+
## Defining a custom favicon
The favicon is displayed in the browser tab and can be customized by setting the `customFavicon` property. This must be
@@ -398,7 +413,6 @@ a png file of size 16x16 or 32x32 pixels

```xml
-
custom/favicon.png
...
diff --git a/maven/src/main/java/com/trivago/cluecumber/maven/CluecumberMaven.java b/maven/src/main/java/com/trivago/cluecumber/maven/CluecumberMaven.java
index ade0e57f..ccf36faa 100644
--- a/maven/src/main/java/com/trivago/cluecumber/maven/CluecumberMaven.java
+++ b/maven/src/main/java/com/trivago/cluecumber/maven/CluecumberMaven.java
@@ -95,6 +95,12 @@ public final class CluecumberMaven extends AbstractMojo {
@Parameter(property = "reporting.customFavicon")
private String customFavicon = "";
+ /**
+ * Custom logo that is used for the generated report.
+ */
+ @Parameter(property = "reporting.customLogo")
+ private String customLogo = "";
+
/**
* Custom flag that determines if step output sections of scenario detail pages should be expanded (default: false).
*/
@@ -197,6 +203,7 @@ public void execute() throws MojoExecutionException {
.setLogLevel(CluecumberLogger.CluecumberLogLevel.valueOf(logLevel.toUpperCase()))
.setCustomCssFile(customCss)
.setCustomFaviconFile(customFavicon)
+ .setCustomLogoFile(customLogo)
.setCustomNavigationLinks(customNavigationLinks)
.setCustomParameters(customParameters)
.setCustomParametersDisplayMode(Settings.CustomParamDisplayMode.valueOf(customParametersDisplayMode.toUpperCase()))
diff --git a/pom.xml b/pom.xml
index 60cd6a0d..b3f7bbdd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
- 3.10.0
+ 3.11.0111111
@@ -33,11 +33,11 @@
3.11.03.2.71.7.0
- 5.11.4
+ 5.12.0-RC25.15.23.5.23.3.1
- 3.11.1
+ 3.11.23.1.13.3.13.1.3