Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
71e1751
Upgraded dependencies to latest releases of Cucumber Gherkin 37.0.1, …
clrudolphi Jan 3, 2026
aebf21d
Update CHANGELOG.md
clrudolphi Jan 3, 2026
9f05a23
undo whitespace changes in Reqnroll.csproj
gasparnagy Jan 6, 2026
fbdf013
add PR number to CHANGELOG
gasparnagy Jan 6, 2026
053d604
Merge branch 'main' into update_Cucumber_Dependencies_01_2026
clrudolphi Jan 14, 2026
5eaad11
Merge branch 'main' into update_Cucumber_Dependencies_01_2026
clrudolphi Jan 20, 2026
c263421
Update Formatters.Tests samples to CCK v27 release (adds a new All-St…
clrudolphi Jan 20, 2026
bb0de35
Merge branch 'main' into update_Cucumber_Dependencies_01_2026
clrudolphi Jan 27, 2026
faea58d
Merge branch 'main' into update_Cucumber_Dependencies_01_2026
clrudolphi Feb 9, 2026
27d4387
Updated to Gherkin 38, Messages 32.0.1, and HtmlFormatter 23
clrudolphi Feb 9, 2026
796fe56
Eliminated (deleted) the CCK assets that will be provided by the CCK …
clrudolphi Feb 23, 2026
dffd569
Add CCK package.
clrudolphi Feb 24, 2026
d52c43f
Modified tests to use the new path to the CCK assets.
clrudolphi Feb 24, 2026
45af513
Fixes to Formatters test infrastucture for using the new CCK package.
clrudolphi Feb 24, 2026
05c05ab
Fix Formatter.Tests csproj for cross-platform compatibility of embedd…
clrudolphi Feb 25, 2026
f3110a3
Fix test for ambiguous step matching
clrudolphi Feb 25, 2026
e7792ae
Prototype of External Attachment handling. Each test framework will e…
clrudolphi Mar 10, 2026
fab0fe4
Merge branch 'main' into prototype_Formatters_ExternalAttachmentsAlig…
clrudolphi Mar 11, 2026
ca13a44
Fix-up a test after merging main back to branch.
clrudolphi Mar 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# [vNext]

## Improvements:
* Updated Cucumber dependencies to: Gherkin v38.0.0, Cucumber.Messages v32.0.1 and Cucumber.HtmlFormatter v23.0.0. (#984)

## Bug fixes:
* Fix: Formatters incorrectly handle Unicode text file content of attachments.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using Reqnroll.BoDi;
using Reqnroll.Formatters.Configuration;
using Reqnroll.UnitTestProvider;

namespace Reqnroll.MSTest.ReqnrollPlugin;
Expand All @@ -8,6 +9,8 @@ public class MsTestRuntimeProvider(IObjectContainer container) : IUnitTestRuntim
{
private readonly Lazy<IMsTestRuntimeAdapter> _runtimeAdapter = new(container.Resolve<IMsTestRuntimeAdapter>);

public AttachmentHandlingOption AttachmentHandlingOption => AttachmentHandlingOption.External;

public void TestPending(string message)
{
TestInconclusive(message);
Expand Down
3 changes: 3 additions & 0 deletions Plugins/Reqnroll.NUnit.ReqnrollPlugin/NUnitRuntimeProvider.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using System;
using NUnit.Framework;
using Reqnroll.Formatters.Configuration;
using Reqnroll.UnitTestProvider;

namespace Reqnroll.NUnit.ReqnrollPlugin;

public class NUnitRuntimeProvider : IUnitTestRuntimeProvider
{
public AttachmentHandlingOption AttachmentHandlingOption => AttachmentHandlingOption.External;

public void TestPending(string message)
{
TestInconclusive(message);
Expand Down
4 changes: 4 additions & 0 deletions Plugins/Reqnroll.TUnit.ReqnrollPlugin/TUnitRuntimeProvider.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using Reqnroll.ErrorHandling;
using Reqnroll.Formatters.Configuration;
using Reqnroll.UnitTestProvider;
using TUnit.Core.Exceptions;

Expand All @@ -10,6 +11,9 @@ namespace Reqnroll.TUnit.ReqnrollPlugin;
/// </summary>
public class TUnitRuntimeProvider : IUnitTestRuntimeProvider
{
/// <inheritdoc/>
public AttachmentHandlingOption AttachmentHandlingOption => AttachmentHandlingOption.External;

/// <inheritdoc />
public void TestPending(string message)
{
Expand Down
3 changes: 3 additions & 0 deletions Plugins/Reqnroll.xUnit.ReqnrollPlugin/XUnitRuntimeProvider.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using System;
using Reqnroll.Formatters.Configuration;
using Reqnroll.UnitTestProvider;
using Xunit;

namespace Reqnroll.xUnit.ReqnrollPlugin;

public class XUnitRuntimeProvider : IUnitTestRuntimeProvider
{
public AttachmentHandlingOption AttachmentHandlingOption => AttachmentHandlingOption.None;

public void TestPending(string message)
{
throw new XUnitPendingStepException($"Test pending: {message}");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using System;
using Reqnroll.Formatters.Configuration;
using Reqnroll.UnitTestProvider;
using Xunit.Sdk;

namespace Reqnroll.xUnit3.ReqnrollPlugin;

public class XUnit3RuntimeProvider : IUnitTestRuntimeProvider
{
public AttachmentHandlingOption AttachmentHandlingOption => AttachmentHandlingOption.Embed;

public void TestPending(string message) => throw new XUnitPendingException($"Test pending: {message}");

public void TestInconclusive(string message) => throw new XUnitInconclusiveException($"Test inconclusive: {message}");
Expand Down
2 changes: 1 addition & 1 deletion Reqnroll.Parser/Reqnroll.Parser.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Gherkin" Version="35.0.0" />
<PackageReference Include="Gherkin" Version="38.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
13 changes: 13 additions & 0 deletions Reqnroll/Formatters/Configuration/AttachmentHandlingOption.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Reqnroll.Formatters.Configuration;

[Flags]
public enum AttachmentHandlingOption
{
None = 1, // Attachment events are ignored and not included in the Cucumber Messages output
Embed = 2, // Attachments are embedded directly into the Cucumber Messages output as base64-encoded data
External = 4 // Attachments are referenced as external files in the Cucumber Messages output
}
4 changes: 3 additions & 1 deletion Reqnroll/Formatters/ExecutionTracking/AttachmentTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public async Task ProcessEvent(AttachmentAddedEvent attachmentAddedEvent)
{
FilePath = attachmentAddedEvent.FilePath;
Timestamp = attachmentAddedEvent.Timestamp;
await _publisher.PublishAsync(Envelope.Create(_messageFactory.ToAttachment(this)));

if (_messageFactory.TryCreateAttachmentEnvelope(this, out var envelope))
await _publisher.PublishAsync(envelope);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
using Io.Cucumber.Messages.Types;
using Reqnroll.Bindings;
using Reqnroll.EnvironmentAccess;
using Reqnroll.Formatters.Configuration;
using Reqnroll.Formatters.ExecutionTracking;
using Reqnroll.UnitTestProvider;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
Expand All @@ -19,6 +22,12 @@ namespace Reqnroll.Formatters.PayloadProcessing.Cucumber;
/// </summary>
public class CucumberMessageFactory : ICucumberMessageFactory
{
private readonly AttachmentHandlingOption _attachmentHandlingOption;

public CucumberMessageFactory(IUnitTestRuntimeProvider unitTestRuntimeProvider)
{
_attachmentHandlingOption = unitTestRuntimeProvider.AttachmentHandlingOption;
}
private Timestamp ToTimestamp(DateTime timestamp)
{
return Converters.ToTimestamp(timestamp.ToUniversalTime());
Expand Down Expand Up @@ -188,7 +197,7 @@ public virtual StepMatchArgument ToStepMatchArgument(TestStepArgument argument)
{
return new StepMatchArgument(
new Group(
[],
null,
argument.StartOffset,
argument.Value
),
Expand Down Expand Up @@ -268,6 +277,45 @@ public virtual TestStepFinished ToTestStepFinished(HookStepExecutionTracker hook
ToTestStepResult(hookStepExecutionTracker), ToTimestamp(hookStepExecutionTracker.StepFinishedAt));
}

public virtual bool TryCreateAttachmentEnvelope(AttachmentTracker tracker, out Envelope attachmentEnvelope)
{
var attachmentMessage = CreateAttachment(tracker);
switch (attachmentMessage)
{
case Attachment a:
attachmentEnvelope = Envelope.Create(a);
return true;
case ExternalAttachment ea:
attachmentEnvelope = Envelope.Create(ea);
return true;
default:
attachmentEnvelope = null;
return false;
}
}
public virtual object CreateAttachment(AttachmentTracker tracker)
{
return _attachmentHandlingOption switch
{
AttachmentHandlingOption.Embed => ToAttachment(tracker),
AttachmentHandlingOption.External => ToExternalAttachment(tracker),
AttachmentHandlingOption.None => null,
_ => throw new NotImplementedException($"Attachment handling option {_attachmentHandlingOption} is not implemented.")
};
}

public virtual ExternalAttachment ToExternalAttachment(AttachmentTracker tracker)
{
var filePath = tracker.FilePath;
return new ExternalAttachment(
filePath,
FileExtensionToMimeTypeMap.GetMimeType(Path.GetExtension(filePath)),
tracker.TestCaseStartedId,
tracker.TestCaseStepId,
tracker.TestRunStartedId,
Converters.ToTimestamp(tracker.Timestamp));
}

public virtual Attachment ToAttachment(AttachmentTracker tracker)
{
var filePath = tracker.FilePath;
Expand Down Expand Up @@ -316,7 +364,7 @@ private static string ToTestStepResultMessage(System.Exception exception, Scenar
return status switch
{
ScenarioExecutionStatus.OK => null,
ScenarioExecutionStatus.StepDefinitionPending => exception.Message,
ScenarioExecutionStatus.StepDefinitionPending => null,
ScenarioExecutionStatus.UndefinedStep => exception.Message,
ScenarioExecutionStatus.BindingError => null,
ScenarioExecutionStatus.TestError => exception.Message,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public virtual void Accept(object message)
case Attachment attachment:
Visit(attachment);
break;
case ExternalAttachment externalAttachment:
Visit(externalAttachment);
break;
case GherkinDocument gherkinDocument:
Visit(gherkinDocument);
break;
Expand Down Expand Up @@ -213,6 +216,12 @@ public virtual void Visit(Attachment attachment)
OnVisited(attachment);
}

public virtual void Visit(ExternalAttachment externalAttachment)
{
OnVisiting(externalAttachment);
OnVisited(externalAttachment);
}

public virtual void Visit(GherkinDocument gherkinDocument)
{
OnVisiting(gherkinDocument);
Expand Down Expand Up @@ -713,6 +722,12 @@ public virtual void OnVisiting(Attachment attachment)
public virtual void OnVisited(Attachment attachment)
{ }

public virtual void OnVisiting(ExternalAttachment externalAttachment)
{ }

public virtual void OnVisited(ExternalAttachment externalAttachment)
{ }

public virtual void OnVisiting(Envelope envelope)
{ }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public static string Id(this object message)
public static readonly Type[] EnvelopeContentTypes =
[
typeof(Attachment),
typeof(ExternalAttachment),
typeof(GherkinDocument),
typeof(Hook),
typeof(Meta),
Expand All @@ -88,6 +89,7 @@ public static object Content(this Envelope envelope)
{
object result = null;
if (envelope.Attachment != null) { result = envelope.Attachment; }
else if (envelope.ExternalAttachment != null) { result = envelope.ExternalAttachment; }
else if (envelope.GherkinDocument != null) { result = envelope.GherkinDocument; }
else if (envelope.Hook != null) { result = envelope.Hook; }
else if (envelope.Meta != null) { result = envelope.Meta; }
Expand Down Expand Up @@ -122,7 +124,18 @@ public static Timestamp Timestamp(this Envelope envelope)
else if (envelope.TestRunHookStarted != null) { result = envelope.TestRunHookStarted.Timestamp; }
else if (envelope.TestRunHookFinished != null) { result = envelope.TestRunHookFinished.Timestamp; }
else if (envelope.Attachment != null) { result = envelope.Attachment.Timestamp; }
else if (envelope.ExternalAttachment != null) { result = envelope.ExternalAttachment.Timestamp; }
else throw new ArgumentException($"Envelope of type: {envelope.Content().GetType()} does not contain a timestamp");
return result;
}

public static Envelope CreateFromAttachment(this object attachment)
{
return attachment switch
{
Attachment a => Envelope.Create(a),
ExternalAttachment ea => Envelope.Create(ea),
_ => null
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
using Io.Cucumber.Messages.Types;
using Reqnroll.Bindings;
using Reqnroll.EnvironmentAccess;
using Reqnroll.Formatters.Configuration;
using Reqnroll.Formatters.ExecutionTracking;
using System;
using System.Collections.Generic;

namespace Reqnroll.Formatters.PayloadProcessing.Cucumber;

Expand Down Expand Up @@ -37,15 +39,23 @@ public interface ICucumberMessageFactory
TestStep ToTestStep(HookStepTracker hookStepTracker);
TestStepStarted ToTestStepStarted(HookStepExecutionTracker hookStepExecutionTracker);
TestStepFinished ToTestStepFinished(HookStepExecutionTracker hookStepExecutionTracker);

// Attachment methods

bool TryCreateAttachmentEnvelope(AttachmentTracker tracker, out Envelope attachmentEnvelope);
Attachment ToAttachment(AttachmentTracker tracker);
ExternalAttachment ToExternalAttachment(AttachmentTracker tracker);

// Creates either an <see cref="Attachment"/> or <see cref="ExternalAttachment"/> based on the <see cref="AttachmentHandlingOption"> specified by the <see cref="IUnitTestRuntimeProvider"/>.
object CreateAttachment(AttachmentTracker attachment);

Attachment ToAttachment(OutputMessageTracker tracker);

// Metadata methods
Meta ToMeta(string reqnrollVersion, string netCoreVersion, string osPlatform, BuildMetadata buildMetaData);

// Utility methods
string CanonicalizeStepDefinitionPattern(IStepDefinitionBinding stepDefinition);
string CanonicalizeHookBinding(IHookBinding hookBinding);
}

}
12 changes: 4 additions & 8 deletions Reqnroll/Reqnroll.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Gherkin" Version="35.0.0" />
<PackageReference Include="Gherkin" Version="38.0.0" />
<PackageReference Include="Cucumber.CucumberExpressions" Version="17.1.0" />
<PackageReference Include="Cucumber.Messages" Version="30.1.0" />
<PackageReference Include="Cucumber.HtmlFormatter" Version="22.2.0" />
<PackageReference Include="Cucumber.Messages" Version="32.0.1" />
<PackageReference Include="Cucumber.HtmlFormatter" Version="23.0.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.6" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="8.0.2" />
<!-- System.Runtime.Loader is used for .NET (not .NET Framework) based frameworks only.
Expand Down Expand Up @@ -72,11 +72,7 @@
</ItemGroup>

<!-- Embeds the Application Insights instrumentation key -->
<Target
Name="EmbedAppInsightsInstrumentationKey"
Inputs="@(AppInsightsInstrumentationKeyFile)"
Outputs="$(IntermediateOutputPath)%(AppInsightsInstrumentationKeyFile.Filename).$(AppInsightsInstrumentationKey)%(AppInsightsInstrumentationKeyFile.Extension)"
BeforeTargets="CoreCompile">
<Target Name="EmbedAppInsightsInstrumentationKey" Inputs="@(AppInsightsInstrumentationKeyFile)" Outputs="$(IntermediateOutputPath)%(AppInsightsInstrumentationKeyFile.Filename).$(AppInsightsInstrumentationKey)%(AppInsightsInstrumentationKeyFile.Extension)" BeforeTargets="CoreCompile">

<!-- Read the lines from the template. -->
<ReadLinesFromFile File="%(AppInsightsInstrumentationKeyFile.Identity)">
Expand Down
6 changes: 6 additions & 0 deletions Reqnroll/UnitTestProvider/IUnitTestRuntimeProvider.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using Reqnroll.ErrorHandling;
using Reqnroll.Formatters.Configuration;

namespace Reqnroll.UnitTestProvider;

Expand Down Expand Up @@ -33,4 +34,9 @@ public interface IUnitTestRuntimeProvider
/// <param name="exception">The exception that has been thrown during the step execution.</param>
/// <returns>The detected <see cref="ScenarioExecutionStatus"/> or <c>null</c> in all other cases.</returns>
ScenarioExecutionStatus? DetectExecutionStatus(Exception exception);

/// <summary>
/// Gets the <see cref="AttachmentHandlingOption"/> supported by the test execution framework.
/// </summary>
AttachmentHandlingOption AttachmentHandlingOption { get; }
}
7 changes: 7 additions & 0 deletions Tests/Reqnroll.Formatters.Tests/CrossReferenceBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ public override void OnVisiting(Attachment attachment)
_buildCrossReferences(attachment);
base.OnVisiting(attachment);
}

public override void OnVisiting(ExternalAttachment externalAttachment)
{
_buildCrossReferences(externalAttachment);
base.OnVisiting(externalAttachment);
}

public override void OnVisiting(Background background)
{
_buildCrossReferences(background);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ public void ExternalAssembliesAreSupportedInStepDefinitionMessages()
CucumberMessagesAddConfigurationFile("reqnrollConfigurationWithExternalAssembly.json");

//Set up the Default Project (main test assembly)
AddUtilClassWithFileSystemPath();
AddUtilClassWithFileSystemPath("Samples");

AddFeatureFileFromResource($"ExternalBindingAssemblies/{featureNameText}.feature", "Samples", Assembly.GetExecutingAssembly());
AddBindingClassFromResource($"ExternalBindingAssemblies/SampleInternalBindingClass.cs", "Samples", Assembly.GetExecutingAssembly());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ private EquivalencyAssertionOptions<T> ArrangeFluentAssertionOptions<T>(Equivale
// invoking these for each Type in CucumberMessages so that FluentAssertions DOES NOT call .Equal when comparing instances
return options
.ComparingByMembers<Attachment>()
.ComparingByMembers<ExternalAttachment>()
.ComparingByMembers<Background>()
.ComparingByMembers<Ci>()
.ComparingByMembers<Comment>()
Expand Down
Loading
Loading