diff --git a/CHANGELOG.md b/CHANGELOG.md index 518e7d2..64f8ade 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # [vNext] +## Improvements: + +* Find Unused Step Definitions Command: Improved handling of Step Definitions decorated with the 'StepDefinition' attribute. If a Step Definition is used in any Given/Then/When step in a Feature file, the step will no longer show in the 'Find Unused Step Definitions' context menu. + +*Contributors of this release (in alphabetical order):* @UL-ChrisGlew + # v2024.2.93 - 2024-06-05 ## Improvements: @@ -19,4 +25,4 @@ * Support for .NET 8 projects * New editor command: "Go To Hooks" (Ctrl B,H) to navigate to the hooks related to the scenario * The "Go To Definition" lists hooks when invoked from scenario header (tags, header line, description) -* Initial release based on v2022.1.91 of the [SpecFlow for Visual Studio](https://github.com/SpecFlowOSS/SpecFlow.VS/) extension. +* Initial release based on v2022.1.91 of the [SpecFlow for Visual Studio](https://github.com/SpecFlowOSS/SpecFlow.VS/) extension. \ No newline at end of file diff --git a/Reqnroll.VisualStudio/Editor/Services/UnusedStepDefinitionsFinder.cs b/Reqnroll.VisualStudio/Editor/Services/UnusedStepDefinitionsFinder.cs index 8ef02db..cee1537 100644 --- a/Reqnroll.VisualStudio/Editor/Services/UnusedStepDefinitionsFinder.cs +++ b/Reqnroll.VisualStudio/Editor/Services/UnusedStepDefinitionsFinder.cs @@ -18,8 +18,7 @@ public UnusedStepDefinitionsFinder(IIdeScope ideScope) : base(ideScope) _ideScope = ideScope; } - public IEnumerable FindUnused(ProjectBindingRegistry bindingRegistry, - string[] featureFiles, DeveroomConfiguration configuration) + public IEnumerable FindUnused(ProjectBindingRegistry bindingRegistry, string[] featureFiles, DeveroomConfiguration configuration) { var stepDefUsageCounts = bindingRegistry.StepDefinitions.ToDictionary(stepDef => stepDef, _ => 0); foreach (var ff in featureFiles) @@ -28,7 +27,9 @@ public IEnumerable FindUnused(ProjectBindingRegist foreach (var step in usedSteps) stepDefUsageCounts[step]++; } - return stepDefUsageCounts.Where(x => x.Value == 0).Select(x => x.Key); + var allUsedSteps = stepDefUsageCounts.Where(x => x.Value > 0).Select(x => x.Key).ToList(); + var allUnusedSteps = stepDefUsageCounts.Where(x => x.Value == 0).Select(x => x.Key); + return allUnusedSteps.Where(x => !allUsedSteps.Any(y => y.Expression.Equals(x.Expression) && ReferenceEquals(x.Implementation, y.Implementation))); } protected IEnumerable FindUsed(ProjectBindingRegistry bindingRegistry, diff --git a/Tests/Reqnroll.VisualStudio.Tests/Editor/Commands/FindUnusedStepDefinitionsCommandTests.cs b/Tests/Reqnroll.VisualStudio.Tests/Editor/Commands/FindUnusedStepDefinitionsCommandTests.cs index a9a46af..836e9d0 100644 --- a/Tests/Reqnroll.VisualStudio.Tests/Editor/Commands/FindUnusedStepDefinitionsCommandTests.cs +++ b/Tests/Reqnroll.VisualStudio.Tests/Editor/Commands/FindUnusedStepDefinitionsCommandTests.cs @@ -39,4 +39,19 @@ public async Task Can_find_a_StepDefinition_With_Multiple_Step_Attributes_Not_Us .HaveCount(2).And .Contain(mi => mi.Label == "Steps.cs(10,9): [When(\"I choose add\")] WhenIPressAdd"); } + + + [Fact] + public async Task Cannot_find_an_unused_StepDefinition_With_StepDefinition_Attribute() + { + var stepDefinition = ArrangeStepDefinition(@"""I press add""", "StepDefinition"); + var featureFile = ArrangeOneFeatureFile(); + var (textView, command) = await ArrangeSut(stepDefinition, featureFile); + + await InvokeAndWaitAnalyticsEvent(command, textView); + + (ProjectScope.IdeScope.Actions as StubIdeActions)!.LastShowContextMenuItems.Should() + .HaveCount(1).And + .Contain(mi => mi.Label == "There are no unused step definitions"); + } } diff --git a/Tests/Reqnroll.VisualStudio.VsxStubs/StepDefinitions/MockableDiscoveryService.cs b/Tests/Reqnroll.VisualStudio.VsxStubs/StepDefinitions/MockableDiscoveryService.cs index 459b041..1ca3c67 100644 --- a/Tests/Reqnroll.VisualStudio.VsxStubs/StepDefinitions/MockableDiscoveryService.cs +++ b/Tests/Reqnroll.VisualStudio.VsxStubs/StepDefinitions/MockableDiscoveryService.cs @@ -1,3 +1,6 @@ +using Gherkin.CucumberMessages.Types; +using Newtonsoft.Json; + namespace Reqnroll.VisualStudio.VsxStubs.StepDefinitions; public class MockableDiscoveryService : DiscoveryService @@ -22,11 +25,34 @@ public static MockableDiscoveryService SetupWithInitialStepDefinitions(IProjectS { var discoveryResultProviderMock = new Mock(MockBehavior.Strict); + var allStepDefinitions = new List(); + foreach (var stepDefinition in stepDefinitions) + { + if (stepDefinition.Type.Equals("StepDefinition")) + { + var serialized = JsonConvert.SerializeObject(stepDefinition); + var stepDefAttributes = new List() { "Given", "Then", "When" }; + foreach (string stepDefAttribute in stepDefAttributes) + { + StepDefinition? clonedStepDef = JsonConvert.DeserializeObject(serialized); + if (clonedStepDef != null) + { + clonedStepDef.Type = stepDefAttribute; + allStepDefinitions.Add(clonedStepDef); + } + } + } + else + { + allStepDefinitions.Add(stepDefinition); + } + } + var discoveryService = new MockableDiscoveryService(projectScope, discoveryResultProviderMock) { LastDiscoveryResult = new DiscoveryResult { - StepDefinitions = stepDefinitions, + StepDefinitions = allStepDefinitions.ToArray(), Hooks = Array.Empty() } };