Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
Expand Up @@ -4,6 +4,7 @@

## Improvements:

* The 'Define Steps' command honors the StepDefinitionSkeletonStyle setting in the project reqnroll.json configuration file and will generate step skeletons using 'Async' appropriately.
* Update docs - .NET 10, TUnit, VS2026 (#138)

## Bug fixes:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@ public void Populate(string jsonString, DeveroomConfiguration config)
config.ConfiguredBindingCulture = bindingCulture;
if (reqnrollJsonConfiguration.Trace != null &&
reqnrollJsonConfiguration.Trace.TryGetValue("stepDefinitionSkeletonStyle", out var sdSnippetStyle)) {
if (sdSnippetStyle == "CucumberExpressionAttribute")
config.SnippetExpressionStyle = SnippetExpressionStyle.CucumberExpression;
if (sdSnippetStyle == "RegexAttribute")
config.SnippetExpressionStyle = SnippetExpressionStyle.RegularExpression;
config.SnippetExpressionStyle = sdSnippetStyle switch
{
"CucumberExpressionAttribute" => SnippetExpressionStyle.CucumberExpression,
"RegexAttribute" => SnippetExpressionStyle.RegularExpression,
"AsyncCucumberExpressionAttribute" => SnippetExpressionStyle.AsyncCucumberExpression,
"AsyncRegexAttribute" => SnippetExpressionStyle.AsyncRegularExpression,
_ => SnippetExpressionStyle.CucumberExpression
};
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ namespace Reqnroll.VisualStudio.Snippets.Fallback;

public class CucumberExpressionSkeletonProvider : DeveroomStepDefinitionSkeletonProvider
{
public CucumberExpressionSkeletonProvider(ReqnrollProjectTraits projectTraits)
: base(projectTraits)
public CucumberExpressionSkeletonProvider(ReqnrollProjectTraits projectTraits, bool useAsync)
: base(projectTraits, useAsync)
{

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ public abstract class DeveroomStepDefinitionSkeletonProvider
{
protected ReqnrollProjectTraits ProjectTraits { get; }
protected abstract bool UseVerbatimStringForExpression { get; }
protected bool UseAsync { get; }

protected DeveroomStepDefinitionSkeletonProvider(ReqnrollProjectTraits projectTraits)
protected DeveroomStepDefinitionSkeletonProvider(ReqnrollProjectTraits projectTraits, bool useAsync)
{
ProjectTraits = projectTraits;
UseAsync = useAsync;
}

public string GetStepDefinitionSkeletonSnippet(UndefinedStepDescriptor undefinedStep,
Expand All @@ -23,9 +25,10 @@ public string GetStepDefinitionSkeletonSnippet(UndefinedStepDescriptor undefined
var methodName = GetMethodName(undefinedStep, analyzedStepText);
var parameters = string.Join(", ", analyzedStepText.Parameters.Select(ToDeclaration));
var stringPrefix = UseVerbatimStringForExpression ? "@" : "";
var returnSignature = UseAsync ? "async Task" : "void";

var method = $"[{undefinedStep.ScenarioBlock}({stringPrefix}\"{regex}\")]" + newLine +
$"public void {methodName}({parameters})" + newLine +
$"public {returnSignature} {methodName}{(UseAsync ? "Async" : "")}({parameters})" + newLine +
"{" + newLine +
$"{indent}throw new PendingStepException();" + newLine +
"}" + newLine;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ namespace Reqnroll.VisualStudio.Snippets.Fallback;

public class RegexStepDefinitionSkeletonProvider : DeveroomStepDefinitionSkeletonProvider
{
public RegexStepDefinitionSkeletonProvider(ReqnrollProjectTraits projectTraits) : base(projectTraits)
public RegexStepDefinitionSkeletonProvider(ReqnrollProjectTraits projectTraits, bool useAsync) : base(projectTraits, useAsync)
{
}

Expand Down
23 changes: 22 additions & 1 deletion Reqnroll.VisualStudio/Snippets/SnippetExpressionStyle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,26 @@ namespace Reqnroll.VisualStudio.Snippets;
public enum SnippetExpressionStyle
{
RegularExpression,
CucumberExpression
CucumberExpression,
AsyncRegularExpression,
AsyncCucumberExpression
}

public static class SnippetExpressionStyleExtensions
{
public static bool IsAsync(this SnippetExpressionStyle style)
{
if (style == SnippetExpressionStyle.AsyncRegularExpression
|| style == SnippetExpressionStyle.AsyncCucumberExpression)
return true;
return false;
}

public static bool IsCucumber(this SnippetExpressionStyle style)
{
if (style == SnippetExpressionStyle.CucumberExpression
|| style == SnippetExpressionStyle.AsyncCucumberExpression)
return true;
return false;
}
}
6 changes: 3 additions & 3 deletions Reqnroll.VisualStudio/Snippets/SnippetService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ public string GetStepDefinitionSkeletonSnippet(UndefinedStepDescriptor undefined
try
{
var projectTraits = _projectScope.GetProjectSettings().ReqnrollProjectTraits;
var skeletonProvider = expressionStyle == SnippetExpressionStyle.CucumberExpression
? (DeveroomStepDefinitionSkeletonProvider) new CucumberExpressionSkeletonProvider(projectTraits)
: new RegexStepDefinitionSkeletonProvider(projectTraits);
var skeletonProvider = expressionStyle.IsCucumber()
? (DeveroomStepDefinitionSkeletonProvider) new CucumberExpressionSkeletonProvider(projectTraits, expressionStyle.IsAsync())
: new RegexStepDefinitionSkeletonProvider(projectTraits, expressionStyle.IsAsync());

var configuration = _projectScope.GetDeveroomConfiguration();
newLine = newLine ?? Environment.NewLine;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,44 @@ Scenario: DefineSteps command properly escapes empty brackets when using Regex e
| type | expression |
| When | I use \\(parenthesis\), \\{curly braces}, \\\ backslash, and/or \\. period |

Scenario: DefineSteps command abides by reqnroll.json configuration for async method declaration
Given there is a Reqnroll project scope
And the following feature file in the editor
"""
Feature: Feature Using Regex Style

Scenario: Client has a simple basket
Given the client has a basket
"""
And the reqnroll.json configuration file contains
"""
{
"trace": { "stepDefinitionSkeletonStyle": "AsyncRegexAttribute" }
}
"""
And the project is built and the initial binding discovery is performed
When I invoke the "Define Steps" command
Then the define steps dialog should be opened with the following step definition skeletons
| Method |
| MyProject.StepDefinitions1.GivenTheClientHasABasketAsync |

Scenario: DefineSteps command abides by reqnroll.json configuration for synchronous method declaration
Given there is a Reqnroll project scope
And the following feature file in the editor
"""
Feature: Feature Using Regex Style

Scenario: Client has a simple basket
Given the client has a basket
"""
And the reqnroll.json configuration file contains
"""
{
"trace": { "stepDefinitionSkeletonStyle": "RegexAttribute" }
}
"""
And the project is built and the initial binding discovery is performed
When I invoke the "Define Steps" command
Then the define steps dialog should be opened with the following step definition skeletons
| Method |
| MyProject.StepDefinitions1.GivenTheClientHasABasket |
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,8 @@ private StepDefinitionSnippetData[] ParseSnippetsFromFile(string text,
{
Type = sd.Type,
Regex = sd.Regex,
Expression = sd.Expression
Expression = sd.Expression,
Method = sd.Method
}).ToArray();
}

Expand Down Expand Up @@ -987,5 +988,6 @@ private class StepDefinitionSnippetData
public string Type { get; set; }
public string Regex { get; set; }
public string Expression { get; set; }
public string Method { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using FluentAssertions;
using Reqnroll.VisualStudio.Configuration;
using Reqnroll.VisualStudio.Snippets;
using Xunit;

namespace Reqnroll.VisualStudio.Tests.Configuration;
Expand Down Expand Up @@ -149,4 +150,37 @@ public void Should_prioritize_language_binding_over_legacy_bindingCulture()
config.ConfiguredBindingCulture.Should().Be("fr-FR"); // language.binding takes priority
config.BindingCulture.Should().Be("fr-FR");
}

[Theory]
[InlineData("RegexAttribute", SnippetExpressionStyle.RegularExpression)]
[InlineData("CucumberExpressionAttribute", SnippetExpressionStyle.CucumberExpression)]
[InlineData("AsyncRegexAttribute", SnippetExpressionStyle.AsyncRegularExpression)]
[InlineData("AsyncCucumberExpressionAttribute", SnippetExpressionStyle.AsyncCucumberExpression)]
[InlineData("InvalidValue", SnippetExpressionStyle.CucumberExpression)] // Default fallback
[InlineData("", SnippetExpressionStyle.CucumberExpression)] // Default fallback
[InlineData(null, SnippetExpressionStyle.CucumberExpression)] // Default fallback
public void Should_set_stepDefinitionSkeletonStyle_from_reqnroll_json(string styleValue, SnippetExpressionStyle expectedStyle)
{
// Arrange
var deserializer = new ReqnrollConfigDeserializer();
var config = new DeveroomConfiguration();
var styleJson = styleValue != null
? $@"
{{
""trace"": {{
""stepDefinitionSkeletonStyle"": ""{styleValue}""
}}
}}"
: @"
{
""trace"": {
}
}";

// Act
deserializer.Populate(styleJson, config);

// Assert
config.SnippetExpressionStyle.Should().Be(expectedStyle);
}
}
53 changes: 53 additions & 0 deletions Tests/Reqnroll.VisualStudio.Tests/Snippets/SnippetServiceTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using FluentAssertions;
using NSubstitute;
using Reqnroll.VisualStudio.Snippets;
using Reqnroll.VisualStudio.ProjectSystem;
using Reqnroll.VisualStudio.ProjectSystem.Configuration;
using Xunit;

namespace Reqnroll.VisualStudio.Tests.Snippets
{
public class SnippetServiceTests
{
private readonly IProjectScope _projectScope;
private readonly IIdeScope _ideScope;
private readonly IDeveroomLogger _logger;
private readonly SnippetService _service;
private readonly DeveroomConfiguration _defaultDeveroomConfig;
private readonly ITestOutputHelper testOutputHelper;

public SnippetServiceTests(ITestOutputHelper testOutputHelper)
{
_ideScope = new StubIdeScope(testOutputHelper);
_logger = new StubLogger();
_projectScope = new StubProjectScope(@"C:\", "bin", _ideScope, new List<NuGetPackageReference>(), "net8");

_defaultDeveroomConfig = new DeveroomConfiguration();

// Construct the service with the substitute
_service = new SnippetService(_projectScope);
this.testOutputHelper = testOutputHelper;
}

[Theory]
[InlineData(SnippetExpressionStyle.RegularExpression, "[Given(@\"pattern\")]\npublic void GivenPattern()\n{\nthrow new PendingStepException();\n}\n")]
[InlineData(SnippetExpressionStyle.AsyncRegularExpression, "[Given(@\"pattern\")]\npublic async Task GivenPatternAsync()\n{\nthrow new PendingStepException();\n}\n")]
[InlineData(SnippetExpressionStyle.CucumberExpression, "[Given(\"pattern\")]\npublic void GivenPattern()\n{\nthrow new PendingStepException();\n}\n")]
[InlineData(SnippetExpressionStyle.AsyncCucumberExpression, "[Given(\"pattern\")]\npublic async Task GivenPatternAsync()\n{\nthrow new PendingStepException();\n}\n")]
public void Generates_correct_step_definition_snippet(SnippetExpressionStyle style, string expectedSnippet)
{
// Arrange
var undefinedStep = new DeveroomGherkinStep(new Gherkin.Ast.Location(0, 0), "Given ", Gherkin.StepKeywordType.Context, "pattern", null, StepKeyword.Given, ScenarioBlock.Given);
var undefinedStepDescriptor = new UndefinedStepDescriptor(undefinedStep, "pattern");
var indent = "";
var newLine = "\n";

// Act
var snippet = _service.GetStepDefinitionSkeletonSnippet(
undefinedStepDescriptor, style, indent, newLine);

// Assert
snippet.Should().Be(expectedSnippet);
}
}
}
Loading