Skip to content
Open
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
1 change: 1 addition & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<ItemGroup>
<PackageReference Include="FSharp.Core" Version="4.2.3" Condition=" '$(ProjectExt)'=='.fsproj' AND '$(TargetFramework.StartsWith(net4))' " />
<PackageReference Include="FSharp.Core" Version="4.3.4" Condition=" '$(ProjectExt)'=='.fsproj' AND '$(TargetFramework.StartsWith(net5))' " />
<PackageReference Include="FSharp.Core" Version="6.0.7" Condition=" '$(ProjectExt)'=='.fsproj' AND '$(TargetFramework.StartsWith(net6))' " />
<PackageReference Include="FSharp.Core" Version="4.3.4" Condition=" '$(ProjectExt)'=='.fsproj' AND '$(TargetFramework.StartsWith(netstandard))' " />
</ItemGroup>
<PropertyGroup>
Expand Down
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,58 @@ While the typical recommended usage of TickSpec is to keep the step definitions

See the `CustomContainer` example project for usage examples - the example demonstrates wiring of Autofac including usage of lifetime scopes per scenario and usage of the [xUnit 2+ Shared Fixtures](https://xunit.github.io/docs/shared-context.html) to correctly manage the sharing/ifetime of the container where one runs xUnit Test Classes in parallel as part of a large test suite.

# Build integration

TickSpec.Build automatically integrates into the build process as "BeforeCompile" target and generates the "wiring" needed to execute
the BDD scenarios. Currently only NUnit is supported as test framework.

## HTML documentation

TickSpec.Build additionally supports generating HTML documents for the feature files

```bash
TickSpec.Build doc ./src ./html
```

When generating the HTML files to the output location the F# project local folders are preserved.

Using ``--toc html`` a HTML table of contents and with ``--toc json`` a Json table of contents can be generated.

### Styling

The generated HTML documents intentionally only contain HTML fragments of type "article" so that those
articles can easily be integrated in an existing HTML documentation.

These articles provide the following CSS classes for styling:

- **gherkin-keyword** applies to the keywords like GIVEN, WHEN, THEN
- **gherkin-scenario-body** applies to the body of a scenario
- **gherkin-scenario** applies to a complete scenario
- **gherkin-tags** applies to the tags attached to scenarios
- **gherkin-description** applies to a comment provided above a scenario
- **gherkin-scenario-title** applies to the title of a scenario
- **gherkin-feature-title** applies to the feature title

If you want to use the generated articles as a standalone documentation use ``--toc html`` to generate a
standalone HTML document. Put a ``style.css`` next to the ``ToC.html`` to define the CSS classes listed above

### MsBuild integration

To integrate the HTML generation into your MsBuild based build process set the property ``FeatureFileHtmlOutput``
to the location the HTML files should be generated too. By default, only the feature files local to this project
are considered. You can change this by setting the property ``FeatureFileHtmlInput``.

The format of the table of contents can be set using property ``TickSpecBuildTocFormat``.


## Story behind this project

The following articles tell the story behind this project:

- [Lean BDD and Code Generation](http://www.plainionist.net/TickSpec-with-Code-Generation/)
- [Lean BDD with even more Code Generation](http://www.plainionist.net/TickSpec-More-CodeGen/)


# Contributing

Contributions are welcome, particularly examples and documentation. If you'd like to chat about TickSpec, please use the [the gitter channel](https://gitter.im/fsprojects/TickSpec).
Expand Down
57 changes: 39 additions & 18 deletions TickSpec.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2027
# Visual Studio Version 17
VisualStudioVersion = 17.3.32901.215
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{CD7A2701-42ED-47BD-8724-1E130B5C5071}"
EndProject
Expand All @@ -17,47 +17,53 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CommandLine", "CommandLine"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSharp", "Examples\ByFramework\CommandLine\CSharp\CSharp.csproj", "{FBB69434-1AC8-46B9-8533-81F09B69B134}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp", "Examples\ByFramework\CommandLine\FSharp\FSharp.fsproj", "{9A6D191D-73B3-48D9-A0C1-51581E8894A8}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp", "Examples\ByFramework\CommandLine\FSharp\FSharp.fsproj", "{9A6D191D-73B3-48D9-A0C1-51581E8894A8}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TicTacToe", "Examples\ByFramework\CommandLine\TicTacToe\TicTacToe.fsproj", "{3D58E3C3-1A7C-426D-BC9F-555735EA622E}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TicTacToe", "Examples\ByFramework\CommandLine\TicTacToe\TicTacToe.fsproj", "{3D58E3C3-1A7C-426D-BC9F-555735EA622E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NUnit.CSharp", "Examples\ByFramework\NUnit\CSharp.NUnit\NUnit.CSharp.csproj", "{B224A186-190C-43D8-B83C-3E2F0FD7BE39}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "NUnit.FSharp", "Examples\ByFramework\NUnit\FSharp.NUnit\NUnit.FSharp.fsproj", "{5DFF73BD-8C5D-4EE2-B5DD-2D244EC06A61}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "NUnit.FSharp", "Examples\ByFramework\NUnit\FSharp.NUnit\NUnit.FSharp.fsproj", "{5DFF73BD-8C5D-4EE2-B5DD-2D244EC06A61}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Interactive", "Examples\ByStyle\Interactive\Interactive.fsproj", "{BA6F3A69-34F3-4D85-8804-DD354F8E17FA}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Interactive", "Examples\ByStyle\Interactive\Interactive.fsproj", "{BA6F3A69-34F3-4D85-8804-DD354F8E17FA}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Attributes", "Examples\ByStyle\Attributes\Attributes.fsproj", "{B3AA7D1B-E83A-4C9B-97CF-12293AF46E10}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Attributes", "Examples\ByStyle\Attributes\Attributes.fsproj", "{B3AA7D1B-E83A-4C9B-97CF-12293AF46E10}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Functional", "Examples\ByStyle\Functional\Functional.fsproj", "{1D2CA398-6F02-41B1-BAA5-E63DC15508A4}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Functional", "Examples\ByStyle\Functional\Functional.fsproj", "{1D2CA398-6F02-41B1-BAA5-E63DC15508A4}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Xunit.FSharp", "Examples\ByFramework\xUnit\FSharp.xUnit\Xunit.FSharp.fsproj", "{1207F9C8-3B84-4939-B6E2-DB96D06B73E2}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Xunit.FSharp", "Examples\ByFramework\xUnit\FSharp.xUnit\Xunit.FSharp.fsproj", "{1207F9C8-3B84-4939-B6E2-DB96D06B73E2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ByFeature", "ByFeature", "{EB1F6262-0913-4464-A034-4F4D01268E83}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TickSpec", "TickSpec\TickSpec.fsproj", "{DC4A4A1D-CCC5-42E7-8EE6-4F015E8A2E3E}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TickSpec", "TickSpec\TickSpec.fsproj", "{DC4A4A1D-CCC5-42E7-8EE6-4F015E8A2E3E}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "CustomContainer", "Examples\ByFeature\CustomContainer\CustomContainer.fsproj", "{4F45F8E2-F9FD-4C80-B4E0-A38B17A791D2}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "CustomContainer", "Examples\ByFeature\CustomContainer\CustomContainer.fsproj", "{4F45F8E2-F9FD-4C80-B4E0-A38B17A791D2}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "DependencyInjection", "Examples\ByFeature\DependencyInjection\DependencyInjection.fsproj", "{6DD7F109-6798-4CAF-BD13-7BA4689BD892}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "DependencyInjection", "Examples\ByFeature\DependencyInjection\DependencyInjection.fsproj", "{6DD7F109-6798-4CAF-BD13-7BA4689BD892}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FunctionalInjection", "Examples\ByFeature\FunctionalInjection\FunctionalInjection.fsproj", "{1CE6B475-C94F-438E-97D4-5E99FD0F04D4}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FunctionalInjection", "Examples\ByFeature\FunctionalInjection\FunctionalInjection.fsproj", "{1CE6B475-C94F-438E-97D4-5E99FD0F04D4}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TickSpec.Tests", "TickSpec.Tests\TickSpec.Tests.fsproj", "{CD2AA807-5E4F-4A2C-80F7-A7D7CA6B3C2D}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TickSpec.Tests", "TickSpec.Tests\TickSpec.Tests.fsproj", "{CD2AA807-5E4F-4A2C-80F7-A7D7CA6B3C2D}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TaggedExamples", "Examples\ByFeature\TaggedExamples\TaggedExamples.fsproj", "{39C63F8E-F3A5-48D8-851C-62BEB9C701C2}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TaggedExamples", "Examples\ByFeature\TaggedExamples\TaggedExamples.fsproj", "{39C63F8E-F3A5-48D8-851C-62BEB9C701C2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MSTest", "MSTest", "{694A8BD0-05B1-4000-BDD2-67CC4B3B8D90}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "MSTest.FSharp", "Examples\ByFramework\MSTest\MSTest.FSharp\MSTest.FSharp.fsproj", "{6EAC46DB-177A-4482-970A-D43124DB2FB9}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "MSTest.FSharp", "Examples\ByFramework\MSTest\MSTest.FSharp\MSTest.FSharp.fsproj", "{6EAC46DB-177A-4482-970A-D43124DB2FB9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Expecto", "Expecto", "{750A854A-FB45-4E51-94DF-D79B4F1E46DC}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Expecto.FSharp", "Examples\ByFramework\Expecto\FSharp.Expecto\Expecto.FSharp.fsproj", "{F9B139E4-0160-4150-B420-73DCCD57B6B8}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Expecto.FSharp", "Examples\ByFramework\Expecto\FSharp.Expecto\Expecto.FSharp.fsproj", "{F9B139E4-0160-4150-B420-73DCCD57B6B8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Wiring", "Wiring", "{373B654A-3A88-48CC-A0A3-0454514E61FF}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TickSpec.Xunit", "Wiring\TickSpec.Xunit\TickSpec.Xunit.fsproj", "{DDB39875-AA8B-494E-B923-C8143930464F}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TickSpec.Xunit", "Wiring\TickSpec.Xunit\TickSpec.Xunit.fsproj", "{DDB39875-AA8B-494E-B923-C8143930464F}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TickSepc.Build.Tests", "Wiring\TickSepc.Build.Tests\TickSepc.Build.Tests.fsproj", "{8FE8AF85-C728-4DD7-BD16-3520707F97A1}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TickSpec.Build", "Wiring\TickSpec.Build\TickSpec.Build.fsproj", "{F80CF1A0-9FFD-4276-86BA-CF96FEB7F8F6}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TickSpec.CodeGen.NUnit", "Wiring\TickSpec.CodeGen.NUnit\TickSpec.CodeGen.NUnit.fsproj", "{3DF05F3A-9100-41EC-92F9-A66AEE9AA9FC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -137,6 +143,18 @@ Global
{DDB39875-AA8B-494E-B923-C8143930464F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DDB39875-AA8B-494E-B923-C8143930464F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DDB39875-AA8B-494E-B923-C8143930464F}.Release|Any CPU.Build.0 = Release|Any CPU
{8FE8AF85-C728-4DD7-BD16-3520707F97A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8FE8AF85-C728-4DD7-BD16-3520707F97A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8FE8AF85-C728-4DD7-BD16-3520707F97A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8FE8AF85-C728-4DD7-BD16-3520707F97A1}.Release|Any CPU.Build.0 = Release|Any CPU
{F80CF1A0-9FFD-4276-86BA-CF96FEB7F8F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F80CF1A0-9FFD-4276-86BA-CF96FEB7F8F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F80CF1A0-9FFD-4276-86BA-CF96FEB7F8F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F80CF1A0-9FFD-4276-86BA-CF96FEB7F8F6}.Release|Any CPU.Build.0 = Release|Any CPU
{3DF05F3A-9100-41EC-92F9-A66AEE9AA9FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3DF05F3A-9100-41EC-92F9-A66AEE9AA9FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3DF05F3A-9100-41EC-92F9-A66AEE9AA9FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3DF05F3A-9100-41EC-92F9-A66AEE9AA9FC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -166,6 +184,9 @@ Global
{750A854A-FB45-4E51-94DF-D79B4F1E46DC} = {1D43105D-361B-4D27-8069-FBE067C8C114}
{F9B139E4-0160-4150-B420-73DCCD57B6B8} = {750A854A-FB45-4E51-94DF-D79B4F1E46DC}
{DDB39875-AA8B-494E-B923-C8143930464F} = {373B654A-3A88-48CC-A0A3-0454514E61FF}
{8FE8AF85-C728-4DD7-BD16-3520707F97A1} = {373B654A-3A88-48CC-A0A3-0454514E61FF}
{F80CF1A0-9FFD-4276-86BA-CF96FEB7F8F6} = {373B654A-3A88-48CC-A0A3-0454514E61FF}
{3DF05F3A-9100-41EC-92F9-A66AEE9AA9FC} = {373B654A-3A88-48CC-A0A3-0454514E61FF}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8B381617-F1EE-4BFC-8EAE-CAB4DBB4B9A2}
Expand Down
21 changes: 21 additions & 0 deletions Wiring/TickSepc.Build.Tests/Assertions.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[<AutoOpen>]
module TickSepc.Build.Tests.Assertions

open System.Text.RegularExpressions
open NUnit.Framework.Constraints

type SubStringConstraintIgnoreWhitespaces(expected:string) =
inherit Constraint()
let removeWhitespaces str = Regex.Replace(str, @"\s", "")
let expected' = expected |> removeWhitespaces
override this.ApplyTo(actual) =
let actual' = actual.ToString() |> removeWhitespaces
let isSuccess = actual'.Contains(expected')
ConstraintResult(this, actual, isSuccess)
override _.Description = expected

let haveSubstringIgnoringWhitespaces = SubStringConstraintIgnoreWhitespaces

let dump x =
printfn "%A" x
x
173 changes: 173 additions & 0 deletions Wiring/TickSepc.Build.Tests/HtmlGenerationTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
module TickSepc.Build.Tests.HtmlGenerationTests

open NUnit.Framework
open TickSpec.Build
open FsUnit

[<Test>]
let ``Feature title is headline``() =
"""
Feature: First feature

Scenario: One
GIVEN some environment
WHEN some event happens
THEN the system should be in this state
"""
|> TestApi.GenerateHtmlDoc
|> should haveSubstringIgnoringWhitespaces """<h2 class="gherkin-feature-title">First feature</h2>"""

[<Test>]
let ``Scenario title is headline``() =
"""
Feature: First feature

Scenario: One
GIVEN some environment
WHEN some event happens
THEN the system should be in this state
"""
|> TestApi.GenerateHtmlDoc
|> should haveSubstringIgnoringWhitespaces """<h3 class="gherkin-scenario-title">One</h3>"""

[<Test>]
let ``Scenario Outline title is headline``() =
"""
Feature: First feature

Scenario Outline: One
GIVEN some environment
WHEN some event happens
THEN the system should be in this state
"""
|> TestApi.GenerateHtmlDoc
|> should haveSubstringIgnoringWhitespaces """<h3 class="gherkin-scenario-title">One</h3>"""

[<Test>]
let ``Steps rendered as <code/>``() =
"""
Feature: First feature

Scenario: One
GIVEN some environment
AND with following setting
WHEN some event happens
THEN the system should be in this state
AND behave like this
"""
|> TestApi.GenerateHtmlDoc
|> should haveSubstringIgnoringWhitespaces """
<div class="gherkin-scenario"><h3 class="gherkin-scenario-title">One</h3>
<pre class="gherkin-scenario-body"><code><span class="gherkin-keyword">Given</span> some environment
<span class="gherkin-keyword">And</span> with following setting
<span class="gherkin-keyword">When</span> some event happens
<span class="gherkin-keyword">Then</span> the system should be in this state
<span class="gherkin-keyword">And</span> behave like this
</code></pre></div>"""

[<Test>]
let ``With Background``() =
"""
Feature: First feature

Background:
GIVEN some additional environment

Scenario: One
GIVEN some environment
AND with following setting
WHEN some event happens
THEN the system should be in this state
AND behave like this
"""
|> TestApi.GenerateHtmlDoc
|> should haveSubstringIgnoringWhitespaces """
<article>
<h2 class="gherkin-feature-title">First feature</h2>
<div class="gherkin-scenario">
<h3 class="gherkin-scenario-title">Background</h3>
<pre class="gherkin-scenario-body"><code><span class="gherkin-keyword">Given</span> some additional environment
</code></pre></div>"""

[<Test>]
let ``Step with multi line string``() =
"""
Feature: First feature

Scenario: One
GIVEN some environment
AND the following value
\"\"\"
line 1
line 2
\"\"\"
WHEN some event happens
THEN the system should be in this state
"""
|> TestApi.GenerateHtmlDoc
|> should haveSubstringIgnoringWhitespaces """
<div class="gherkin-scenario"><h3 class="gherkin-scenario-title">One</h3>
<pre class="gherkin-scenario-body"><code><span class="gherkin-keyword">Given</span> some environment
<span class="gherkin-keyword">And</span> the following value
\"\"\"
line 1
line 2
\"\"\"
<span class="gherkin-keyword">When</span> some event happens
<span class="gherkin-keyword">Then</span> the system should be in this state
</code></pre></div>"""

[<Test>]
let ``Tags``() =
"""
Feature: First feature

@some-tag @one-more-tag
Scenario: One
GIVEN some environment
WHEN some event happens
THEN the system should be in this state
"""
|> TestApi.GenerateHtmlDoc
|> should haveSubstringIgnoringWhitespaces """
<div class="gherkin-scenario">
<h3 class="gherkin-scenario-title">One</h3>
<div><span class="gherkin-tags">Tags:</span>some-tag, one-more-tag</div>
<pre class="gherkin-scenario-body">"""

[<Test>]
let ``Comments``() =
"""
Feature: First feature

Scenario: One
GIVEN some environment
WHEN some event happens
THEN the system should be in this state

# this is a comment
# over multiple lines
@some-tag @one-more-tag
Scenario: Two
GIVEN some environment
WHEN some event happens
THEN the system should be in this state
"""
|> TestApi.GenerateHtmlDoc
|> should haveSubstringIgnoringWhitespaces """
<div class="gherkin-scenario">
<h3 class="gherkin-scenario-title">One</h3>
<pre class="gherkin-scenario-body"><code><span class="gherkin-keyword">Given</span> some environment
<span class="gherkin-keyword">When</span> some event happens
<span class="gherkin-keyword">Then</span> the system should be in this state
</code></pre>
</div>
<div class="gherkin-scenario">
<h3 class="gherkin-scenario-title">Two</h3>
<div><span class="gherkin-tags">Tags:</span>some-tag, one-more-tag</div>
<div class="gherkin-description">this is a comment over multiple lines</div>
<pre class="gherkin-scenario-body"><code><span class="gherkin-keyword">Given</span> some environment
<span class="gherkin-keyword">When</span> some event happens
<span class="gherkin-keyword">Then</span> the system should be in this state
</code></pre>"""

Loading