Hi π β we're actively using ExtentReports v5.0.4 for BDD test reporting in a .NET 9 MAUI project with Reqnroll (SpecFlow successor) + NUnit, running parallel Android/iOS tests. We've built a ~667-line ExtentReportManager.cs wrapper to get the reporting we need, and along the way hit several issues that required significant workarounds. Sharing this feedback in case it's useful for future development.
π Critical Bug: Silent crash when BDD node lacks Gherkin model type
Using CreateNode("title") instead of CreateNode("title") produces no error at creation time, but causes a RuntimeBinderException: Cannot perform runtime binding on a null reference at Flush() when the Spark Razor template tries to dynamically access the node's Gherkin model. This was extremely hard to diagnose.
Ask: Throw an ArgumentException at CreateNode() time if a node is added to a BDD tree without a Gherkin type, or default to a sensible
3-level tree depth limit β Spark template is hardcoded for Feature β Scenario β Steps. We need Feature β Platform Group β Scenario β Steps for parallel cross-platform runs. Flattened to 3 levels and prefix scenario titles with [Android/Appium] / [iOS/Xamarin.UITest]
No native tag rendering β Tags like @smoketest should display above the scenario/feature title, styled distinctly.
Inject into node titles + Config.JS DOM manipulation to reposition spans before the auto-prepended keyword
Gherkin keyword auto-prepending can't be controlled β CreateNode("TC001") always renders as Scenario: TC001. When injecting HTML into titles, the keyword gets prepended before the HTML. JS injection via Config.JS to move DOM nodes after render
Thread-safety gaps β No documented concurrency model. We use ConcurrentDictionary for feature/scenario tracking and lock around node creation. Manual thread-safety wrapper with concurrent collections
No .Description() for scenario nodes β Only features support descriptions. Append description as an Info log entry (loses semantic meaning)
No data table / DocString rendering β Gherkin tables and DocStrings from step definitions have no API support.
Format as HTML <table> / <pre> and pass via .Info()
No structured failure details β .Fail() accepts a string or exception but no collapsible sections for stack trace, screenshot, environment info.
HTML string with <details><summary> blocks in .Fail() message
Default BDD theme needs modernization β Step nodes all look the same visually regardless of pass/fail until you read the status icon.
Custom CSS via Config.CSS for status-colored backgrounds
Tag rendering workaround (JS injection)
_sparkReporter.Config.JS = @"
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.tag-line').forEach(function(tag) {
var parent = tag.parentNode;
if (!parent) return;
var firstChild = parent.firstChild;
if (firstChild && firstChild !== tag) {
var br = tag.nextSibling;
if (br && br.nodeName === 'BR') {
parent.removeChild(br);
}
var newBr = document.createElement('br');
parent.insertBefore(tag, firstChild);
tag.after(newBr);
}
});
});
";
Tag-line CSS injection
_sparkReporter.Config.CSS = @"
.tag-line {
display: inline;
font-size: 12px;
color: #1565c0;
font-weight: 600;
letter-spacing: 0.3px;
}
";
Scenario title construction with tags + platform label
```
if (scenarioTags != null && scenarioTags.Length > 0)
{
var tagLine = string.Join(" ", scenarioTags.Select(t => t.StartsWith("@") ? t : $"@{t}"));
scenarioDisplayTitle = $"{tagLine}
{platformLabel} {scenarioTitle}";
}
else
{
scenarioDisplayTitle = $"{platformLabel} {scenarioTitle}";
}
_currentTest = featureNode.CreateNode(scenarioDisplayTitle);
```
Thread-safe feature node tracking
```
private static readonly ConcurrentDictionary _featureNodes = new();
var featureNode = _featureNodes.GetOrAdd(featureTitle, title =>
{
lock (_reportLock)
{
return _extent.CreateTest(featureDisplayTitle);
}
});
</details>
π Full write-up
We've documented all 10 issues with full context, workaround code, and specific asks in a detailed markdown file:
[BDD_FEEDBACK.md](https://github.com/user-attachments/files/28480279/BDD_FEEDBACK.md)
[ExtentReport.html](https://github.com/user-attachments/files/28480305/ExtentReport.html)
Hi π β we're actively using ExtentReports v5.0.4 for BDD test reporting in a .NET 9 MAUI project with Reqnroll (SpecFlow successor) + NUnit, running parallel Android/iOS tests. We've built a ~667-line ExtentReportManager.cs wrapper to get the reporting we need, and along the way hit several issues that required significant workarounds. Sharing this feedback in case it's useful for future development.
π Critical Bug: Silent crash when BDD node lacks Gherkin model type
Using CreateNode("title") instead of CreateNode("title") produces no error at creation time, but causes a RuntimeBinderException: Cannot perform runtime binding on a null reference at Flush() when the Spark Razor template tries to dynamically access the node's Gherkin model. This was extremely hard to diagnose.
Ask: Throw an ArgumentException at CreateNode() time if a node is added to a BDD tree without a Gherkin type, or default to a sensible
3-level tree depth limit β Spark template is hardcoded for Feature β Scenario β Steps. We need Feature β Platform Group β Scenario β Steps for parallel cross-platform runs. Flattened to 3 levels and prefix scenario titles with [Android/Appium] / [iOS/Xamarin.UITest]
No native tag rendering β Tags like @smoketest should display above the scenario/feature title, styled distinctly.
Inject into node titles + Config.JS DOM manipulation to reposition spans before the auto-prepended keyword
Gherkin keyword auto-prepending can't be controlled β CreateNode("TC001") always renders as Scenario: TC001. When injecting HTML into titles, the keyword gets prepended before the HTML. JS injection via Config.JS to move DOM nodes after render
Thread-safety gaps β No documented concurrency model. We use ConcurrentDictionary for feature/scenario tracking and lock around node creation. Manual thread-safety wrapper with concurrent collections
No .Description() for scenario nodes β Only features support descriptions. Append description as an Info log entry (loses semantic meaning)
No data table / DocString rendering β Gherkin tables and DocStrings from step definitions have no API support.
Format as HTML
<table> / <pre> and pass via .Info()No structured failure details β .Fail() accepts a string or exception but no collapsible sections for stack trace, screenshot, environment info.
HTML string with
<details><summary> blocks in .Fail()messageDefault BDD theme needs modernization β Step nodes all look the same visually regardless of pass/fail until you read the status icon.
Custom CSS via Config.CSS for status-colored backgrounds
Tag rendering workaround (JS injection)
Tag-line CSS injection
Scenario title construction with tags + platform label
``` if (scenarioTags != null && scenarioTags.Length > 0) { var tagLine = string.Join(" ", scenarioTags.Select(t => t.StartsWith("@") ? t :{platformLabel} {scenarioTitle}"; } else { scenarioDisplayTitle = $"{platformLabel} {scenarioTitle}"; } _currentTest = featureNode.CreateNode(scenarioDisplayTitle); ```
Thread-safe feature node tracking
``` private static readonly ConcurrentDictionary _featureNodes = new();var featureNode = _featureNodes.GetOrAdd(featureTitle, title =>
{
lock (_reportLock)
{
return _extent.CreateTest(featureDisplayTitle);
}
});