Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
46 changes: 46 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,52 @@ Customize how step titles are generated from expressions:
Configurator.StepTitleFactory = new MyStepTitleFactory();
```

### IncludeInputsInStepTitle

Controls whether step arguments are appended to step titles (default: `true`):

```csharp
Configurator.StepTitleFactory.IncludeInputsInStepTitle = false;
```

### AddGherkinPrefixToSecondarySteps

When a step has an explicit title (via `[Given("...")]`, `[When("...")]`, `[Then("...")]`, or `[StepTitle("...")]`), BDDfy prepends the Gherkin keyword to the title by default. For consecutive steps in the same group, this means they get an "And" prefix. Set this to `false` to disable the "And" prefix on consecutive custom-titled steps:

```csharp
Configurator.StepTitleFactory.AddGherkinPrefixToSecondarySteps = true; // default
```

**With prefix enabled (default):**

```
Scenario: With prefix enabled
Given the user is logged in
And the cart has items
And the payment gateway is available
When the user checks out
Then the order is confirmed
And a confirmation email is sent
```

```csharp
Configurator.StepTitleFactory.AddGherkinPrefixToSecondarySteps = false;
```

**With prefix disabled:**

```
Scenario: With prefix disabled
Given the user is logged in
the cart has items
the payment gateway is available
When the user checks out
Then the order is confirmed
a confirmation email is sent
```

> **Note:** Primary step keywords (Given/When/Then) are always applied regardless of this setting. Only the consecutive "And" prefix on custom-titled steps is affected.

## Culture

Set the culture used for formatting values in reports:
Expand Down
36 changes: 35 additions & 1 deletion docs/reflective-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,47 @@ For more control over step text and ordering, use the executable attributes inst
Pass a string to the attribute to override the humanized method name:

```csharp
[Given("Given the account balance is $10")]
[Given("the account balance is $10")]
void GivenAccountHasEnoughBalance()
{
_card = new Card(true, 10);
}
```

By default, the Gherkin keyword (Given/When/Then/And/But) is automatically prepended to the custom title:

```csharp
[When("the user checks out")]
void WhenTheUserClicksCheckout() { }
// Reports as: "When the user checks out"
```

This behavior can be disabled for consecutive steps via configuration:

```csharp
Configurator.StepTitleFactory.AddGherkinPrefixToSecondarySteps = false;
// Consecutive custom-titled steps no longer get "And" prepended
// Primary steps (Given/When/Then) always keep their keyword
```

When both `[StepTitle]` and an executable attribute (e.g. `[When]`) are present, the executable attribute's text takes priority:

```csharp
[StepTitle("the user completes checkout")]
[When("the user checks out")]
void WhenTheUserClicksCheckout() { }
// Reports as: "When the user checks out" (When attribute wins)
```

If the executable attribute has no explicit text, `[StepTitle]` is used as fallback:

```csharp
[StepTitle("the payment gateway is available")]
[Given]
void CheckPaymentGateway() { }
// Reports as: "Given the payment gateway is available"
```

### Controlling Order

Use the `Order` property when you need explicit ordering:
Expand Down
2 changes: 1 addition & 1 deletion src/TestStack.BDDfy.Tests/GlobalSuppressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
using System.Diagnostics.CodeAnalysis;

[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Test step methods cannot be static", Scope = "namespaceanddescendants", Target = "~N:TestStack.BDDfy.Tests")]
[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "parameters serve as placeholders for step arguments", Scope = "namespaceanddescendants", Target = "~N:TestStack.BDDfy.Tests")]
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace TestStack.BDDfy.Tests.Scanner.FluentScanner
[Story]
class ScenarioToBeScannedUsingFluentScanner
{
internal const string InputDateStepTitleTemplate = "The provided date is {0:MMM d yyyy}";
internal const string InputDateStepTitleTemplate = "And the provided date is {0:MMM d yyyy}";
public static readonly DateTime InputDate = DateTime.Parse("2011-10-20", new CultureInfo("en-AU"));

private string[] _input1 = null!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public void UseConfiguration_IncludeInputsInStepTitle()
.Given(_=>something.Sub.GivenWithStepTitleAndArgument(1))
.When(_ => something.Sub.ActionWithArgument("foo"))
.And(_ => something.Sub.ActionWithArgumentsDisabledInTitle("foo"))
.And(_ => something.Sub.ActionWithTemplateTitleAndArguments("foo"))
.And(_ => something.Sub.ActionWithTemplateTitleAndArgumentsDisabled("foo"))
.And(_ => something.Sub.ActionWithArgumentsEnabledInTitle("foo"))
.BDDfy();

Expand Down Expand Up @@ -59,7 +59,10 @@ public void MethodCallInStepTitle()
.Then(_ => ThenTitleHas(AMethodCall()))
.And(_ => something.Sub.ActionWithArgument("foo"))
.And(_ => something.Sub.ActionWithArgumentsDisabledInTitle("foo"))
.And(_ => something.Sub.ActionWithTemplateTitleAndArguments("foo"))
.And(_ => something.Sub.ActionWithArgumentsEnabledInTitle("foo"))
.And(_ => something.Sub.ActionWithTemplateTitleAndArgumentsDisabled("foo"))
.And(_ => something.Sub.ActionWithTemplateTitleAndArgumentsEnabled("foo"))
.And(_ => something.Sub.ActionWithStepTitleWithArgument("foo"))
.BDDfy();

var actualTitles = story.Scenarios.Single().Steps.Select(s => s.Title).ToArray();
Expand All @@ -71,6 +74,9 @@ public void MethodCallInStepTitle()
"Then title has Mutated state",
"And with arg foo",
"And with arg",
"And with arg foo",
"And with foo arg",
"And with foo arg foo",
"And with foo arg"
};

Expand Down Expand Up @@ -115,7 +121,18 @@ public void ActionWithArgumentsEnabledInTitle(string arg)
}

[StepTitle("With {0} arg", false)]
public void ActionWithTemplateTitleAndArguments(string arg)
public void ActionWithTemplateTitleAndArgumentsDisabled(string arg)
{

}

[StepTitle("With {0} arg", true)]
public void ActionWithTemplateTitleAndArgumentsEnabled(string arg)
{
}

[StepTitle("With {0} arg")]
public void ActionWithStepTitleWithArgument(string value)
{
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

### Step name will be built from step title
i have a red car with a crazy horn
Given i have a red car with a crazy horn
When i honk the horn at volume high
Then i verify diagnostics a red car honked crazy horn at high volume

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class UsingCustomStepTitleFactory
private class CustomStepTitleFactory : IStepTitleFactory
{
public bool IncludeInputsInStepTitle { get; set; } = true;
public bool AddGherkinPrefixToSecondarySteps { get; set; } = true;

public StepTitle Create(
string? stepTextTemplate,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

Scenario: Does not double prefix when title already starts with keyword
Given the account is active
And the balance is 100
When the user withdraws 50
Then the balance is 50
And a receipt is printed

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

Scenario: With prefix disabled
Given the user is logged in
the cart has items
the payment gateway is available
When the user checks out
Then the order is confirmed
a confirmation email is sent

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

Scenario: With prefix enabled
Given the user is logged in
And the cart has items
And the payment gateway is available
When the user checks out
Then the order is confirmed
And a confirmation email is sent

Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using Shouldly;
using TestStack.BDDfy.Configuration;
using TestStack.BDDfy.Reporters;
using TestStack.BDDfy.Tests.Concurrency;
using Xunit;

namespace TestStack.BDDfy.Tests.Scanner.ReflectiveScanner
{
[Collection(TestCollectionName.ModifiesConfigurator)]
public class AddGherkinPrefixToCustomStepTitleTests
{
private class ScenarioWithCustomTitles
{
public void GivenTheUserIsLoggedIn() { }

[Given("the cart has items")]
public void PopulateCart() { }

[StepTitle("the payment gateway is available")]
[Given]
public void CheckGateway() { }

[StepTitle("the user completes checkout")]
[When("the user checks out")]
public void WhenTheUserClicksCheckout() { }

public void ThenTheOrderIsConfirmed() { }

[Then("a confirmation email is sent")]
public void SendEmail() { }
}

private class ScenarioWithPrefixAlreadyInTitle
{
[Given("Given the account is active")]
public void SetupAccount() { }

[Given("Given the balance is 100")]
public void SetupBalance() { }

[When("When the user withdraws 50")]
public void PerformWithdrawal() { }

[Then("Then the balance is 50")]
public void CheckBalance() { }

[Then("Then a receipt is printed")]
public void CheckReceipt() { }
}

[Fact]
public void WithPrefixEnabled()
{
try
{
Configurator.StepTitleFactory.AddGherkinPrefixToSecondarySteps = true;

var scenario = new ScenarioWithCustomTitles();
var story = scenario.BDDfy();

var reporter = new TextReporter();
reporter.Process(story);
reporter.ToString().ShouldMatchApproved();
}
finally
{
Configurator.StepTitleFactory.AddGherkinPrefixToSecondarySteps = true;
}
}

[Fact]
public void WithPrefixDisabled()
{
try
{
Configurator.StepTitleFactory.AddGherkinPrefixToSecondarySteps = false;

var scenario = new ScenarioWithCustomTitles();
var story = scenario.BDDfy();

var reporter = new TextReporter();
reporter.Process(story);
reporter.ToString().ShouldMatchApproved();
}
finally
{
Configurator.StepTitleFactory.AddGherkinPrefixToSecondarySteps = true;
}
}

[Fact]
public void DoesNotDoublePrefixWhenTitleAlreadyStartsWithKeyword()
{
var scenario = new ScenarioWithPrefixAlreadyInTitle();
var story = scenario.BDDfy();

var reporter = new TextReporter();
reporter.Process(story);
reporter.ToString().ShouldMatchApproved();
}
}
}
Loading
Loading