Skip to content

Commit 30f1ce5

Browse files
Feature generate async snippets from 'DefineSteps' command (#129)
* Snippet generator honors the StepDefinitionSkeletonStyle setting from the reqnroll.json file when generating snippets (sync or async). Added unit tests for the new skeletonStyle enum deserialization. Added unit test for the SnippetService. Added Spec test in the DefineStepsCommand spec for the generation of async and sync snippets. * Updated Changelog * Add PR number to CHANGELOG --------- Co-authored-by: Gáspár Nagy <[email protected]>
1 parent 18eec74 commit 30f1ce5

File tree

11 files changed

+173
-14
lines changed

11 files changed

+173
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
## Improvements:
66

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

910
## Bug fixes:

Reqnroll.VisualStudio/Configuration/ReqnrollConfigDeserializer.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,14 @@ public void Populate(string jsonString, DeveroomConfiguration config)
2121
config.ConfiguredBindingCulture = bindingCulture;
2222
if (reqnrollJsonConfiguration.Trace != null &&
2323
reqnrollJsonConfiguration.Trace.TryGetValue("stepDefinitionSkeletonStyle", out var sdSnippetStyle)) {
24-
if (sdSnippetStyle == "CucumberExpressionAttribute")
25-
config.SnippetExpressionStyle = SnippetExpressionStyle.CucumberExpression;
26-
if (sdSnippetStyle == "RegexAttribute")
27-
config.SnippetExpressionStyle = SnippetExpressionStyle.RegularExpression;
24+
config.SnippetExpressionStyle = sdSnippetStyle switch
25+
{
26+
"CucumberExpressionAttribute" => SnippetExpressionStyle.CucumberExpression,
27+
"RegexAttribute" => SnippetExpressionStyle.RegularExpression,
28+
"AsyncCucumberExpressionAttribute" => SnippetExpressionStyle.AsyncCucumberExpression,
29+
"AsyncRegexAttribute" => SnippetExpressionStyle.AsyncRegularExpression,
30+
_ => SnippetExpressionStyle.CucumberExpression
31+
};
2832
}
2933
}
3034

Reqnroll.VisualStudio/Snippets/Fallback/CucumberExpressionSkeletonProvider.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ namespace Reqnroll.VisualStudio.Snippets.Fallback;
44

55
public class CucumberExpressionSkeletonProvider : DeveroomStepDefinitionSkeletonProvider
66
{
7-
public CucumberExpressionSkeletonProvider(ReqnrollProjectTraits projectTraits)
8-
: base(projectTraits)
7+
public CucumberExpressionSkeletonProvider(ReqnrollProjectTraits projectTraits, bool useAsync)
8+
: base(projectTraits, useAsync)
99
{
1010

1111
}

Reqnroll.VisualStudio/Snippets/Fallback/DeveroomStepDefinitionSkeletonProvider.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ public abstract class DeveroomStepDefinitionSkeletonProvider
66
{
77
protected ReqnrollProjectTraits ProjectTraits { get; }
88
protected abstract bool UseVerbatimStringForExpression { get; }
9+
protected bool UseAsync { get; }
910

10-
protected DeveroomStepDefinitionSkeletonProvider(ReqnrollProjectTraits projectTraits)
11+
protected DeveroomStepDefinitionSkeletonProvider(ReqnrollProjectTraits projectTraits, bool useAsync)
1112
{
1213
ProjectTraits = projectTraits;
14+
UseAsync = useAsync;
1315
}
1416

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

2730
var method = $"[{undefinedStep.ScenarioBlock}({stringPrefix}\"{regex}\")]" + newLine +
28-
$"public void {methodName}({parameters})" + newLine +
31+
$"public {returnSignature} {methodName}{(UseAsync ? "Async" : "")}({parameters})" + newLine +
2932
"{" + newLine +
3033
$"{indent}throw new PendingStepException();" + newLine +
3134
"}" + newLine;

Reqnroll.VisualStudio/Snippets/Fallback/RegexStepDefinitionSkeletonProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ namespace Reqnroll.VisualStudio.Snippets.Fallback;
22

33
public class RegexStepDefinitionSkeletonProvider : DeveroomStepDefinitionSkeletonProvider
44
{
5-
public RegexStepDefinitionSkeletonProvider(ReqnrollProjectTraits projectTraits) : base(projectTraits)
5+
public RegexStepDefinitionSkeletonProvider(ReqnrollProjectTraits projectTraits, bool useAsync) : base(projectTraits, useAsync)
66
{
77
}
88

Reqnroll.VisualStudio/Snippets/SnippetExpressionStyle.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,26 @@ namespace Reqnroll.VisualStudio.Snippets;
33
public enum SnippetExpressionStyle
44
{
55
RegularExpression,
6-
CucumberExpression
6+
CucumberExpression,
7+
AsyncRegularExpression,
8+
AsyncCucumberExpression
79
}
10+
11+
public static class SnippetExpressionStyleExtensions
12+
{
13+
public static bool IsAsync(this SnippetExpressionStyle style)
14+
{
15+
if (style == SnippetExpressionStyle.AsyncRegularExpression
16+
|| style == SnippetExpressionStyle.AsyncCucumberExpression)
17+
return true;
18+
return false;
19+
}
20+
21+
public static bool IsCucumber(this SnippetExpressionStyle style)
22+
{
23+
if (style == SnippetExpressionStyle.CucumberExpression
24+
|| style == SnippetExpressionStyle.AsyncCucumberExpression)
25+
return true;
26+
return false;
27+
}
28+
}

Reqnroll.VisualStudio/Snippets/SnippetService.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ public string GetStepDefinitionSkeletonSnippet(UndefinedStepDescriptor undefined
2121
try
2222
{
2323
var projectTraits = _projectScope.GetProjectSettings().ReqnrollProjectTraits;
24-
var skeletonProvider = expressionStyle == SnippetExpressionStyle.CucumberExpression
25-
? (DeveroomStepDefinitionSkeletonProvider) new CucumberExpressionSkeletonProvider(projectTraits)
26-
: new RegexStepDefinitionSkeletonProvider(projectTraits);
24+
var skeletonProvider = expressionStyle.IsCucumber()
25+
? (DeveroomStepDefinitionSkeletonProvider) new CucumberExpressionSkeletonProvider(projectTraits, expressionStyle.IsAsync())
26+
: new RegexStepDefinitionSkeletonProvider(projectTraits, expressionStyle.IsAsync());
2727

2828
var configuration = _projectScope.GetDeveroomConfiguration();
2929
newLine = newLine ?? Environment.NewLine;

Tests/Reqnroll.VisualStudio.Specs/Features/Editor/Commands/DefineStepsCommand.feature

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,44 @@ Scenario: DefineSteps command properly escapes empty brackets when using Regex e
163163
| type | expression |
164164
| When | I use \\(parenthesis\), \\{curly braces}, \\\ backslash, and/or \\. period |
165165

166+
Scenario: DefineSteps command abides by reqnroll.json configuration for async method declaration
167+
Given there is a Reqnroll project scope
168+
And the following feature file in the editor
169+
"""
170+
Feature: Feature Using Regex Style
171+
172+
Scenario: Client has a simple basket
173+
Given the client has a basket
174+
"""
175+
And the reqnroll.json configuration file contains
176+
"""
177+
{
178+
"trace": { "stepDefinitionSkeletonStyle": "AsyncRegexAttribute" }
179+
}
180+
"""
181+
And the project is built and the initial binding discovery is performed
182+
When I invoke the "Define Steps" command
183+
Then the define steps dialog should be opened with the following step definition skeletons
184+
| Method |
185+
| MyProject.StepDefinitions1.GivenTheClientHasABasketAsync |
186+
187+
Scenario: DefineSteps command abides by reqnroll.json configuration for synchronous method declaration
188+
Given there is a Reqnroll project scope
189+
And the following feature file in the editor
190+
"""
191+
Feature: Feature Using Regex Style
192+
193+
Scenario: Client has a simple basket
194+
Given the client has a basket
195+
"""
196+
And the reqnroll.json configuration file contains
197+
"""
198+
{
199+
"trace": { "stepDefinitionSkeletonStyle": "RegexAttribute" }
200+
}
201+
"""
202+
And the project is built and the initial binding discovery is performed
203+
When I invoke the "Define Steps" command
204+
Then the define steps dialog should be opened with the following step definition skeletons
205+
| Method |
206+
| MyProject.StepDefinitions1.GivenTheClientHasABasket |

Tests/Reqnroll.VisualStudio.Specs/StepDefinitions/ProjectSystemSteps.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,8 @@ private StepDefinitionSnippetData[] ParseSnippetsFromFile(string text,
797797
{
798798
Type = sd.Type,
799799
Regex = sd.Regex,
800-
Expression = sd.Expression
800+
Expression = sd.Expression,
801+
Method = sd.Method
801802
}).ToArray();
802803
}
803804

@@ -987,5 +988,6 @@ private class StepDefinitionSnippetData
987988
public string Type { get; set; }
988989
public string Regex { get; set; }
989990
public string Expression { get; set; }
991+
public string Method { get; set; }
990992
}
991993
}

Tests/Reqnroll.VisualStudio.Tests/Configuration/ReqnrollConfigDeserializerTests.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
using FluentAssertions;
44
using Reqnroll.VisualStudio.Configuration;
5+
using Reqnroll.VisualStudio.Snippets;
56
using Xunit;
67

78
namespace Reqnroll.VisualStudio.Tests.Configuration;
@@ -149,4 +150,37 @@ public void Should_prioritize_language_binding_over_legacy_bindingCulture()
149150
config.ConfiguredBindingCulture.Should().Be("fr-FR"); // language.binding takes priority
150151
config.BindingCulture.Should().Be("fr-FR");
151152
}
153+
154+
[Theory]
155+
[InlineData("RegexAttribute", SnippetExpressionStyle.RegularExpression)]
156+
[InlineData("CucumberExpressionAttribute", SnippetExpressionStyle.CucumberExpression)]
157+
[InlineData("AsyncRegexAttribute", SnippetExpressionStyle.AsyncRegularExpression)]
158+
[InlineData("AsyncCucumberExpressionAttribute", SnippetExpressionStyle.AsyncCucumberExpression)]
159+
[InlineData("InvalidValue", SnippetExpressionStyle.CucumberExpression)] // Default fallback
160+
[InlineData("", SnippetExpressionStyle.CucumberExpression)] // Default fallback
161+
[InlineData(null, SnippetExpressionStyle.CucumberExpression)] // Default fallback
162+
public void Should_set_stepDefinitionSkeletonStyle_from_reqnroll_json(string styleValue, SnippetExpressionStyle expectedStyle)
163+
{
164+
// Arrange
165+
var deserializer = new ReqnrollConfigDeserializer();
166+
var config = new DeveroomConfiguration();
167+
var styleJson = styleValue != null
168+
? $@"
169+
{{
170+
""trace"": {{
171+
""stepDefinitionSkeletonStyle"": ""{styleValue}""
172+
}}
173+
}}"
174+
: @"
175+
{
176+
""trace"": {
177+
}
178+
}";
179+
180+
// Act
181+
deserializer.Populate(styleJson, config);
182+
183+
// Assert
184+
config.SnippetExpressionStyle.Should().Be(expectedStyle);
185+
}
152186
}

0 commit comments

Comments
 (0)