From a3fb176700f161f053014cff2aa4bfd1a0cae732 Mon Sep 17 00:00:00 2001 From: Chris Rudolphi <1702962+clrudolphi@users.noreply.github.com> Date: Sat, 4 Oct 2025 15:56:40 -0500 Subject: [PATCH 1/5] Initial Commit. Reads value from reqnroll.json. Defaults async to true. Snippet Service creates async method. Wired in to DefineStepsCommand and GoToDefinitionCommand. --- .../Configuration/DeveroomConfiguration.cs | 2 +- .../Configuration/ReqnrollConfigDeserializer.cs | 6 ++++++ Reqnroll.VisualStudio/Editor/Commands/DefineStepsCommand.cs | 3 ++- .../Editor/Commands/GoToDefinitionCommand.cs | 2 +- .../Fallback/DeveroomStepDefinitionSkeletonProvider.cs | 5 +++-- Reqnroll.VisualStudio/Snippets/SnippetService.cs | 5 +++-- 6 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Reqnroll.VisualStudio/Configuration/DeveroomConfiguration.cs b/Reqnroll.VisualStudio/Configuration/DeveroomConfiguration.cs index 084582d9..8bda616d 100644 --- a/Reqnroll.VisualStudio/Configuration/DeveroomConfiguration.cs +++ b/Reqnroll.VisualStudio/Configuration/DeveroomConfiguration.cs @@ -21,7 +21,7 @@ public class DeveroomConfiguration public string ConfiguredBindingCulture { get; set; } = null; public string BindingCulture => ConfiguredBindingCulture ?? DefaultFeatureLanguage; public SnippetExpressionStyle SnippetExpressionStyle { get; set; } = SnippetExpressionStyle.CucumberExpression; - + public bool GenerateAsyncSkeletonMethods { get; set; } = true; private void FixEmptyContainers() { diff --git a/Reqnroll.VisualStudio/Configuration/ReqnrollConfigDeserializer.cs b/Reqnroll.VisualStudio/Configuration/ReqnrollConfigDeserializer.cs index 2f4c49a5..863171c1 100644 --- a/Reqnroll.VisualStudio/Configuration/ReqnrollConfigDeserializer.cs +++ b/Reqnroll.VisualStudio/Configuration/ReqnrollConfigDeserializer.cs @@ -26,6 +26,12 @@ public void Populate(string jsonString, DeveroomConfiguration config) if (sdSnippetStyle == "RegexAttribute") config.SnippetExpressionStyle = SnippetExpressionStyle.RegularExpression; } + if (reqnrollJsonConfiguration.Trace != null && + reqnrollJsonConfiguration.Trace.TryGetValue("generateStepDefinitionSkeletonAsAsync", out var generateStepDefinitionSkeletonAsAsync) && + bool.TryParse(generateStepDefinitionSkeletonAsAsync, out bool generateAsyncSkeletonMethods)) + { + config.GenerateAsyncSkeletonMethods = generateAsyncSkeletonMethods; + } } private class ReqnrollJsonConfiguration diff --git a/Reqnroll.VisualStudio/Editor/Commands/DefineStepsCommand.cs b/Reqnroll.VisualStudio/Editor/Commands/DefineStepsCommand.cs index 507d804f..3d205c07 100644 --- a/Reqnroll.VisualStudio/Editor/Commands/DefineStepsCommand.cs +++ b/Reqnroll.VisualStudio/Editor/Commands/DefineStepsCommand.cs @@ -67,6 +67,7 @@ public override bool PreExec(IWpfTextView textView, DeveroomEditorCommandTargetK var viewModel = new CreateStepDefinitionsDialogViewModel(); viewModel.ClassName = feature.Name.ToIdentifier() + "StepDefinitions"; viewModel.ExpressionStyle = snippetService.DefaultExpressionStyle; + bool generateAsyncSnippet = snippetService.DefaultGenerateSkeletonMethodsAsAsync; foreach (var undefinedStepTag in undefinedStepTags) { @@ -74,7 +75,7 @@ public override bool PreExec(IWpfTextView textView, DeveroomEditorCommandTargetK foreach (var match in matchResult.Items.Where(mi => mi.Type == MatchResultType.Undefined)) { var snippet = snippetService.GetStepDefinitionSkeletonSnippet(match.UndefinedStep, - viewModel.ExpressionStyle, indent, newLine); + viewModel.ExpressionStyle, generateAsyncSnippet, indent, newLine); if (viewModel.Items.Any(i => i.Snippet == snippet)) continue; diff --git a/Reqnroll.VisualStudio/Editor/Commands/GoToDefinitionCommand.cs b/Reqnroll.VisualStudio/Editor/Commands/GoToDefinitionCommand.cs index aeee3bb3..7d0fdbce 100644 --- a/Reqnroll.VisualStudio/Editor/Commands/GoToDefinitionCommand.cs +++ b/Reqnroll.VisualStudio/Editor/Commands/GoToDefinitionCommand.cs @@ -88,7 +88,7 @@ private void PerformOfferCopySnippet(MatchResultItem match, ITextBuffer textBuff string newLine = Environment.NewLine; var snippet = snippetService.GetStepDefinitionSkeletonSnippet(match.UndefinedStep, - snippetService.DefaultExpressionStyle, indent, newLine); + snippetService.DefaultExpressionStyle, snippetService.DefaultGenerateSkeletonMethodsAsAsync, indent, newLine); IdeScope.Actions.ShowQuestion(new QuestionDescription(GoToStepDefinitionsPopupHeader, $"The step is undefined. Do you want to copy a step definition skeleton snippet to the clipboard?{Environment.NewLine}{Environment.NewLine}{snippet}", diff --git a/Reqnroll.VisualStudio/Snippets/Fallback/DeveroomStepDefinitionSkeletonProvider.cs b/Reqnroll.VisualStudio/Snippets/Fallback/DeveroomStepDefinitionSkeletonProvider.cs index 11f0afa9..538eedf9 100644 --- a/Reqnroll.VisualStudio/Snippets/Fallback/DeveroomStepDefinitionSkeletonProvider.cs +++ b/Reqnroll.VisualStudio/Snippets/Fallback/DeveroomStepDefinitionSkeletonProvider.cs @@ -13,7 +13,7 @@ protected DeveroomStepDefinitionSkeletonProvider(ReqnrollProjectTraits projectTr } public string GetStepDefinitionSkeletonSnippet(UndefinedStepDescriptor undefinedStep, - string indent, string newLine, string bindingCultureName) + string indent, bool generateAsyncSnippet, string newLine, string bindingCultureName) { var bindingCulture = CultureInfo.GetCultureInfo(bindingCultureName); @@ -23,9 +23,10 @@ public string GetStepDefinitionSkeletonSnippet(UndefinedStepDescriptor undefined var methodName = GetMethodName(undefinedStep, analyzedStepText); var parameters = string.Join(", ", analyzedStepText.Parameters.Select(ToDeclaration)); var stringPrefix = UseVerbatimStringForExpression ? "@" : ""; + var returnSignature = generateAsyncSnippet ? "async Task" : "void"; var method = $"[{undefinedStep.ScenarioBlock}({stringPrefix}\"{regex}\")]" + newLine + - $"public void {methodName}({parameters})" + newLine + + $"public {returnSignature} {methodName}{(generateAsyncSnippet ? "Async" : "")}({parameters})" + newLine + "{" + newLine + $"{indent}throw new PendingStepException();" + newLine + "}" + newLine; diff --git a/Reqnroll.VisualStudio/Snippets/SnippetService.cs b/Reqnroll.VisualStudio/Snippets/SnippetService.cs index 9a5c9f1f..348ae470 100644 --- a/Reqnroll.VisualStudio/Snippets/SnippetService.cs +++ b/Reqnroll.VisualStudio/Snippets/SnippetService.cs @@ -14,9 +14,10 @@ public SnippetService(IProjectScope projectScope) public SnippetExpressionStyle DefaultExpressionStyle => _projectScope.GetDeveroomConfiguration().SnippetExpressionStyle; + public bool DefaultGenerateSkeletonMethodsAsAsync => _projectScope.GetDeveroomConfiguration().GenerateAsyncSkeletonMethods; public string GetStepDefinitionSkeletonSnippet(UndefinedStepDescriptor undefinedStep, - SnippetExpressionStyle expressionStyle, string indent = " ", string newLine = null) + SnippetExpressionStyle expressionStyle, bool generateAsyncSkeletonSnippet, string indent = " ", string newLine = null) { try { @@ -28,7 +29,7 @@ public string GetStepDefinitionSkeletonSnippet(UndefinedStepDescriptor undefined var configuration = _projectScope.GetDeveroomConfiguration(); newLine = newLine ?? Environment.NewLine; var result = - skeletonProvider.GetStepDefinitionSkeletonSnippet(undefinedStep, indent, newLine, + skeletonProvider.GetStepDefinitionSkeletonSnippet(undefinedStep, indent, generateAsyncSkeletonSnippet, newLine, configuration.BindingCulture); _logger.LogInfo( $"Step definition snippet generated for step '{undefinedStep.StepText}': {Environment.NewLine}{result}"); From eabb3a1b971a618f5d315dbecd35673d28c17dbb Mon Sep 17 00:00:00 2001 From: Chris Rudolphi <1702962+clrudolphi@users.noreply.github.com> Date: Sat, 4 Oct 2025 17:53:39 -0500 Subject: [PATCH 2/5] Wired the new step definition behavior into the ViewModel and provide a check-box to switch between sync and async methods. --- .../Dialogs/CreateStepDefinitionsDialog.xaml | 3 ++ .../Editor/Commands/DefineStepsCommand.cs | 42 +++++++++------ .../CreateStepDefinitionsDialogViewModel.cs | 52 +++++++++++++++++-- 3 files changed, 79 insertions(+), 18 deletions(-) diff --git a/Reqnroll.VisualStudio.UI/Dialogs/CreateStepDefinitionsDialog.xaml b/Reqnroll.VisualStudio.UI/Dialogs/CreateStepDefinitionsDialog.xaml index 524459d0..365f2165 100644 --- a/Reqnroll.VisualStudio.UI/Dialogs/CreateStepDefinitionsDialog.xaml +++ b/Reqnroll.VisualStudio.UI/Dialogs/CreateStepDefinitionsDialog.xaml @@ -55,6 +55,9 @@ Regular Expressions Cucumber Expressions --> + diff --git a/Reqnroll.VisualStudio/Editor/Commands/DefineStepsCommand.cs b/Reqnroll.VisualStudio/Editor/Commands/DefineStepsCommand.cs index 3d205c07..7fb06c76 100644 --- a/Reqnroll.VisualStudio/Editor/Commands/DefineStepsCommand.cs +++ b/Reqnroll.VisualStudio/Editor/Commands/DefineStepsCommand.cs @@ -63,25 +63,20 @@ public override bool PreExec(IWpfTextView textView, DeveroomEditorCommandTargetK const string indent = " "; string newLine = Environment.NewLine; - var feature = (Feature) featureTag.Data; + var feature = (Feature)featureTag.Data; var viewModel = new CreateStepDefinitionsDialogViewModel(); + viewModel.IsInitializing = true; + viewModel.Generator = GenerateSnippets; viewModel.ClassName = feature.Name.ToIdentifier() + "StepDefinitions"; viewModel.ExpressionStyle = snippetService.DefaultExpressionStyle; - bool generateAsyncSnippet = snippetService.DefaultGenerateSkeletonMethodsAsAsync; + viewModel.GenerateAsyncMethods = snippetService.DefaultGenerateSkeletonMethodsAsAsync; + viewModel.Indent = indent; + viewModel.NewLine = newLine; + viewModel.UndefinedStepTags = undefinedStepTags; + viewModel.SnippetService = snippetService; + viewModel.IsInitializing = false; - foreach (var undefinedStepTag in undefinedStepTags) - { - var matchResult = (MatchResult) undefinedStepTag.Data; - foreach (var match in matchResult.Items.Where(mi => mi.Type == MatchResultType.Undefined)) - { - var snippet = snippetService.GetStepDefinitionSkeletonSnippet(match.UndefinedStep, - viewModel.ExpressionStyle, generateAsyncSnippet, indent, newLine); - if (viewModel.Items.Any(i => i.Snippet == snippet)) - continue; - - viewModel.Items.Add(new StepDefinitionSnippetItemViewModel {Snippet = snippet}); - } - } + viewModel.Items = new ObservableCollection(GenerateSnippets(viewModel)); IdeScope.WindowManager.ShowDialog(viewModel); @@ -114,6 +109,23 @@ public override bool PreExec(IWpfTextView textView, DeveroomEditorCommandTargetK return true; } + public IEnumerable GenerateSnippets(CreateStepDefinitionsDialogViewModel viewModel) + { + foreach (var undefinedStepTag in viewModel.UndefinedStepTags) + { + var matchResult = (MatchResult)undefinedStepTag.Data; + foreach (var match in matchResult.Items.Where(mi => mi.Type == MatchResultType.Undefined)) + { + var snippet = viewModel.SnippetService.GetStepDefinitionSkeletonSnippet(match.UndefinedStep, + viewModel.ExpressionStyle, viewModel.GenerateAsyncMethods, viewModel.Indent, viewModel.NewLine); + if (viewModel.Items.Any(i => i.Snippet == snippet)) + continue; + + yield return new StepDefinitionSnippetItemViewModel { Snippet = snippet }; + } + } + } + private void SaveAsStepDefinitionClass(IProjectScope projectScope, string combinedSnippet, string className, string indent, string newLine) { diff --git a/Reqnroll.VisualStudio/UI/ViewModels/CreateStepDefinitionsDialogViewModel.cs b/Reqnroll.VisualStudio/UI/ViewModels/CreateStepDefinitionsDialogViewModel.cs index f9ab5ac6..0afabd7c 100644 --- a/Reqnroll.VisualStudio/UI/ViewModels/CreateStepDefinitionsDialogViewModel.cs +++ b/Reqnroll.VisualStudio/UI/ViewModels/CreateStepDefinitionsDialogViewModel.cs @@ -1,17 +1,21 @@ #nullable disable +using Reqnroll.VisualStudio.Snippets; using System; using System.Linq; +using System.ComponentModel; +using System.Collections.ObjectModel; +using System.Runtime.CompilerServices; namespace Reqnroll.VisualStudio.UI.ViewModels; -public class CreateStepDefinitionsDialogViewModel +public class CreateStepDefinitionsDialogViewModel : INotifyPropertyChanged { #if DEBUG public static CreateStepDefinitionsDialogViewModel DesignData = new() { ClassName = "MyFeatureSteps", ExpressionStyle = SnippetExpressionStyle.CucumberExpression, - Items = new List + Items = new ObservableCollection { new() { @@ -40,8 +44,50 @@ public void GivenThereIsASimpleReqnrollProjectForVersion(Version reqnrollVersion } }; #endif + public string ClassName { get; set; } public SnippetExpressionStyle ExpressionStyle { get; set; } - public List Items { get; set; } = new(); + private bool _generateAsyncMethods; + public bool GenerateAsyncMethods + { + get => _generateAsyncMethods; + set + { + if (_generateAsyncMethods != value) + { + _generateAsyncMethods = value; + OnPropertyChanged(nameof(GenerateAsyncMethods)); + if (!IsInitializing) + { + RegenerateItems(); // Regenerate when property changes + } + } + } + } + public ObservableCollection Items { get; set; } = new(); public CreateStepDefinitionsDialogResult Result { get; set; } + public Func> Generator { get; set; } + public DeveroomTag[] UndefinedStepTags { get; set; } + public SnippetService SnippetService { get; set; } + public string Indent { get; set; } + public string NewLine { get; set; } + + public bool IsInitializing; + + public event PropertyChangedEventHandler PropertyChanged; + + protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + public void RegenerateItems() + { + Items.Clear(); + foreach (var item in Generator(this)) + { + Items.Add(item); + } + OnPropertyChanged(nameof(Items)); + } } From a804fa3bddf6b65709c63be819e79f3f82151d67 Mon Sep 17 00:00:00 2001 From: Chris Rudolphi <1702962+clrudolphi@users.noreply.github.com> Date: Sun, 5 Oct 2025 11:11:12 -0500 Subject: [PATCH 3/5] Modified UI Tester to support switching between async and sync method signatures. --- .../CreateStepDefinitionsDialogViewModel.cs | 34 ++++++++++++++++++- .../Reqnroll.VisualStudio.UI.Tester.csproj | 15 ++++++++ .../UiTesterWindow.xaml.cs | 20 ++++++++++- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/Reqnroll.VisualStudio/UI/ViewModels/CreateStepDefinitionsDialogViewModel.cs b/Reqnroll.VisualStudio/UI/ViewModels/CreateStepDefinitionsDialogViewModel.cs index 0afabd7c..5785468a 100644 --- a/Reqnroll.VisualStudio/UI/ViewModels/CreateStepDefinitionsDialogViewModel.cs +++ b/Reqnroll.VisualStudio/UI/ViewModels/CreateStepDefinitionsDialogViewModel.cs @@ -37,6 +37,38 @@ public void GivenThereIsASimpleReqnrollProjectForVersion(Version reqnrollVersion { Snippet = @"[When(@""there is a simple Reqnroll project for (.*)"")] public void GivenThereIsASimpleReqnrollProjectForVersion(Version reqnrollVersion) +{ + throw new PendingStepException(); +}" + } + } + }; + public static CreateStepDefinitionsDialogViewModel DesignDataAsync = new() + { + ClassName = "MyFeatureSteps", + ExpressionStyle = SnippetExpressionStyle.CucumberExpression, + Items = new ObservableCollection + { + new() + { + Snippet = @"[Given(@""there is a simple Reqnroll project for (.*)"")] +public async Task GivenThereIsASimpleReqnrollProjectForVersionAsync(Version reqnrollVersion) +{ + throw new PendingStepException(); +}" + }, + new() + { + Snippet = @"[When(@""there is a simple Reqnroll project for (.*)"")] +public async Task GivenThereIsASimpleReqnrollProjectForVersionAsync(Version reqnrollVersion) +{ + throw new PendingStepException(); +}" + }, + new() + { + Snippet = @"[When(@""there is a simple Reqnroll project for (.*)"")] +public async Task GivenThereIsASimpleReqnrollProjectForVersionAsync(Version reqnrollVersion) { throw new PendingStepException(); }" @@ -47,7 +79,7 @@ public void GivenThereIsASimpleReqnrollProjectForVersion(Version reqnrollVersion public string ClassName { get; set; } public SnippetExpressionStyle ExpressionStyle { get; set; } - private bool _generateAsyncMethods; + private bool _generateAsyncMethods = true; public bool GenerateAsyncMethods { get => _generateAsyncMethods; diff --git a/Tests/Reqnroll.VisualStudio.UI.Tester/Reqnroll.VisualStudio.UI.Tester.csproj b/Tests/Reqnroll.VisualStudio.UI.Tester/Reqnroll.VisualStudio.UI.Tester.csproj index fe9fa4d3..e20ba396 100644 --- a/Tests/Reqnroll.VisualStudio.UI.Tester/Reqnroll.VisualStudio.UI.Tester.csproj +++ b/Tests/Reqnroll.VisualStudio.UI.Tester/Reqnroll.VisualStudio.UI.Tester.csproj @@ -12,4 +12,19 @@ + + + + True + True + Settings.settings + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + \ No newline at end of file diff --git a/Tests/Reqnroll.VisualStudio.UI.Tester/UiTesterWindow.xaml.cs b/Tests/Reqnroll.VisualStudio.UI.Tester/UiTesterWindow.xaml.cs index 520dbf0f..d9925011 100644 --- a/Tests/Reqnroll.VisualStudio.UI.Tester/UiTesterWindow.xaml.cs +++ b/Tests/Reqnroll.VisualStudio.UI.Tester/UiTesterWindow.xaml.cs @@ -48,7 +48,25 @@ private void Test_ContextMenu_At100x100(object sender, RoutedEventArgs e) private void Test_GenerateStepDefinitions(object sender, RoutedEventArgs e) { - var viewModel = CreateStepDefinitionsDialogViewModel.DesignData; + var syncViewModel = CreateStepDefinitionsDialogViewModel.DesignData; + var viewModel = new CreateStepDefinitionsDialogViewModel() { + ClassName = syncViewModel.ClassName, + ExpressionStyle = syncViewModel.ExpressionStyle }; + viewModel.IsInitializing = true; + foreach (var item in syncViewModel.Items) + { + viewModel.Items.Add(item); + } + viewModel.GenerateAsyncMethods = false; + viewModel.Generator = (m) => + { + if (m.GenerateAsyncMethods) + return CreateStepDefinitionsDialogViewModel.DesignDataAsync.Items.ToList(); + else + return CreateStepDefinitionsDialogViewModel.DesignData.Items.ToList(); + }; + viewModel.IsInitializing = false; + var dialog = new CreateStepDefinitionsDialog(viewModel); dialog.ShowDialog(); From 4ed010320c0f72eaeeedd9f06e15bd96202d516d Mon Sep 17 00:00:00 2001 From: Chris Rudolphi <1702962+clrudolphi@users.noreply.github.com> Date: Sun, 5 Oct 2025 12:16:15 -0500 Subject: [PATCH 4/5] Add Spec tests for async step generation --- .../Editor/Commands/DefineStepsCommand.cs | 28 +++++---- .../Commands/DefineStepsCommand.feature | 62 ++++++++++++++++--- .../StepDefinitions/ProjectSystemSteps.cs | 4 +- 3 files changed, 71 insertions(+), 23 deletions(-) diff --git a/Reqnroll.VisualStudio/Editor/Commands/DefineStepsCommand.cs b/Reqnroll.VisualStudio/Editor/Commands/DefineStepsCommand.cs index 7fb06c76..1d2e8ab5 100644 --- a/Reqnroll.VisualStudio/Editor/Commands/DefineStepsCommand.cs +++ b/Reqnroll.VisualStudio/Editor/Commands/DefineStepsCommand.cs @@ -64,16 +64,18 @@ public override bool PreExec(IWpfTextView textView, DeveroomEditorCommandTargetK string newLine = Environment.NewLine; var feature = (Feature)featureTag.Data; - var viewModel = new CreateStepDefinitionsDialogViewModel(); - viewModel.IsInitializing = true; - viewModel.Generator = GenerateSnippets; - viewModel.ClassName = feature.Name.ToIdentifier() + "StepDefinitions"; - viewModel.ExpressionStyle = snippetService.DefaultExpressionStyle; - viewModel.GenerateAsyncMethods = snippetService.DefaultGenerateSkeletonMethodsAsAsync; - viewModel.Indent = indent; - viewModel.NewLine = newLine; - viewModel.UndefinedStepTags = undefinedStepTags; - viewModel.SnippetService = snippetService; + var viewModel = new CreateStepDefinitionsDialogViewModel + { + IsInitializing = true, + Generator = GenerateSnippets, + ClassName = feature.Name.ToIdentifier() + "StepDefinitions", + ExpressionStyle = snippetService.DefaultExpressionStyle, + GenerateAsyncMethods = snippetService.DefaultGenerateSkeletonMethodsAsAsync, + Indent = indent, + NewLine = newLine, + UndefinedStepTags = undefinedStepTags, + SnippetService = snippetService + }; viewModel.IsInitializing = false; viewModel.Items = new ObservableCollection(GenerateSnippets(viewModel)); @@ -111,6 +113,7 @@ public override bool PreExec(IWpfTextView textView, DeveroomEditorCommandTargetK public IEnumerable GenerateSnippets(CreateStepDefinitionsDialogViewModel viewModel) { + var result = new List(); foreach (var undefinedStepTag in viewModel.UndefinedStepTags) { var matchResult = (MatchResult)undefinedStepTag.Data; @@ -118,12 +121,13 @@ public IEnumerable GenerateSnippets(CreateSt { var snippet = viewModel.SnippetService.GetStepDefinitionSkeletonSnippet(match.UndefinedStep, viewModel.ExpressionStyle, viewModel.GenerateAsyncMethods, viewModel.Indent, viewModel.NewLine); - if (viewModel.Items.Any(i => i.Snippet == snippet)) + if (result.Any(i => i.Snippet == snippet)) continue; - yield return new StepDefinitionSnippetItemViewModel { Snippet = snippet }; + result.Add(new StepDefinitionSnippetItemViewModel { Snippet = snippet }); } } + return result; } private void SaveAsStepDefinitionClass(IProjectScope projectScope, string combinedSnippet, string className, diff --git a/Tests/Reqnroll.VisualStudio.Specs/Features/Editor/Commands/DefineStepsCommand.feature b/Tests/Reqnroll.VisualStudio.Specs/Features/Editor/Commands/DefineStepsCommand.feature index 2e3ebe70..cdb0b7bc 100644 --- a/Tests/Reqnroll.VisualStudio.Specs/Features/Editor/Commands/DefineStepsCommand.feature +++ b/Tests/Reqnroll.VisualStudio.Specs/Features/Editor/Commands/DefineStepsCommand.feature @@ -47,7 +47,7 @@ Scenario: Two undefined step has the same step definition skeleton 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 - | type | expression | + | type | expression | | Given | the operand {int} has been entered | Scenario: All steps are defined @@ -121,11 +121,11 @@ Scenario: DefineSteps command abides by reqnroll.json configuration for regex sk "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 - | type | expression | - | Given | the client added (.*) pcs to the basket | + 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 + | type | expression | + | Given | the client added (.*) pcs to the basket | Scenario: DefineSteps command properly escapes empty brackets when using Cucumber expressions Given there is a Reqnroll project scope @@ -139,8 +139,8 @@ Scenario: DefineSteps command properly escapes empty brackets when using Cucumbe 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 - | type | expression | - | When | I use \\(parenthesis), \\{curly braces} and\\/or \\\ backslash | + | type | expression | + | When | I use \\(parenthesis), \\{curly braces} and\\/or \\\\ backslash | Scenario: DefineSteps command properly escapes empty brackets when using Regex expressions Given there is a Reqnroll project scope @@ -160,6 +160,48 @@ Scenario: DefineSteps command properly escapes empty brackets when using Regex e 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 - | type | expression | - | When | I use \\(parenthesis\), \\{curly braces}, \\\ backslash, and/or \\. period | + | 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": { "generateStepDefinitionSkeletonAsAsync": true } + } + """ + 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": { "generateStepDefinitionSkeletonAsAsync": false } + } + """ + 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 | diff --git a/Tests/Reqnroll.VisualStudio.Specs/StepDefinitions/ProjectSystemSteps.cs b/Tests/Reqnroll.VisualStudio.Specs/StepDefinitions/ProjectSystemSteps.cs index 17bc2a84..67b71e42 100644 --- a/Tests/Reqnroll.VisualStudio.Specs/StepDefinitions/ProjectSystemSteps.cs +++ b/Tests/Reqnroll.VisualStudio.Specs/StepDefinitions/ProjectSystemSteps.cs @@ -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(); } @@ -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; } } } From c2dcc0bc37ef3c19e25062bad580ad6c938b373e Mon Sep 17 00:00:00 2001 From: Chris Rudolphi <1702962+clrudolphi@users.noreply.github.com> Date: Sun, 5 Oct 2025 12:18:16 -0500 Subject: [PATCH 5/5] Update ChangeLog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0265dcdc..0c97efb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * New Project Wizard references the latest versions of supported test frameworks and .NET frameworks * Format Document will now right-align numeric values in tables. This can be overridden to left align them by setting `gherkin_table_cell_right_align_numeric_content = false` in .editorconfig file within a `[*.feature]` section. +* Define Steps Command now supports generating async method definitions. ## Bug fixes: