Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
dbd3e04
bump cck to 20 and refresh resources
davidjgoss Aug 12, 2025
8ce7f7e
remove .feature part from ndjson paths
davidjgoss Aug 12, 2025
7067a27
assume multiple features
davidjgoss Aug 12, 2025
fcf1527
convert path to uri before using
davidjgoss Aug 12, 2025
f7a9857
Simplify
mpkorstanje Aug 13, 2025
df2ace3
Reduce diff
mpkorstanje Aug 13, 2025
582a3bd
Reduce diff
mpkorstanje Aug 13, 2025
d2d92b9
Throw on unexpected errors in the compatibility test
mpkorstanje Aug 13, 2025
045d3e0
Merge remote-tracking branch 'origin/main' into cck-20
mpkorstanje Sep 11, 2025
2a8a86d
Update
mpkorstanje Sep 11, 2025
d486c73
Spotless
mpkorstanje Sep 11, 2025
9c3b0eb
Use the java artifact
mpkorstanje Oct 1, 2025
6108bb1
Merge remote-tracking branch 'origin/main' into cck-20
mpkorstanje Oct 1, 2025
ea44b2d
Update
mpkorstanje Oct 1, 2025
ccc0ea5
Cleanup
mpkorstanje Oct 1, 2025
e03ed36
Add OS version to Meta message
mpkorstanje Nov 13, 2025
2b02a5c
Update CHANGELOG
mpkorstanje Nov 19, 2025
e915a69
Refactor exceptions to compatibility test
mpkorstanje Nov 20, 2025
e52c9f0
Merge branch 'add-os-version-to-meta' into cck-20
mpkorstanje Nov 20, 2025
d810e14
Update CCK samples
mpkorstanje Nov 21, 2025
77aab3d
Update CCK samples
mpkorstanje Nov 21, 2025
f1820da
Merge remote-tracking branch 'origin/main' into cck-20
mpkorstanje Nov 21, 2025
dc76d1d
Upgrade cck
mpkorstanje Nov 21, 2025
c9b7b00
Allow all hooks to signal skipping
mpkorstanje Nov 21, 2025
a698426
Polishing
mpkorstanje Nov 21, 2025
d35a3fd
Revert changes to runner
mpkorstanje Nov 21, 2025
634b7eb
Revert changes to runner
mpkorstanje Nov 21, 2025
916b465
Remove unused
mpkorstanje Nov 21, 2025
3be380e
Restructure
mpkorstanje Nov 21, 2025
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
6 changes: 6 additions & 0 deletions compatibility/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.cucumber.core.options.RuntimeOptionsBuilder;
import io.cucumber.core.order.PickleOrder;
import io.cucumber.core.order.StandardPickleOrders;
import io.cucumber.core.plugin.MessageFormatter;
import io.cucumber.core.runtime.Runtime;
import org.hamcrest.Matcher;
Expand Down Expand Up @@ -35,14 +37,18 @@ public class CompatibilityTest {
@ParameterizedTest
@MethodSource("io.cucumber.compatibility.TestCase#testCases")
void produces_expected_output_for(TestCase testCase) throws IOException {
Path parentDir = Files.createDirectories(Paths.get("target", "messages",
testCase.getId()));
Path parentDir = Files.createDirectories(Paths.get("target", "messages", testCase.getId()));
Path outputNdjson = parentDir.resolve("out.ndjson");

try {
PickleOrder pickleOrder = StandardPickleOrders.lexicalUriOrder();
if ("multiple-features-reversed".equals(testCase.getId())) {
pickleOrder = StandardPickleOrders.reverseLexicalUriOrder();
}
Runtime.builder()
.withRuntimeOptions(new RuntimeOptionsBuilder()
.addGlue(testCase.getGlue())
.setPickleOrder(pickleOrder)
.addFeature(testCase.getFeatures()).build())
.withAdditionalPlugins(
new MessageFormatter(newOutputStream(outputNdjson)))
Expand Down Expand Up @@ -71,6 +77,16 @@ void produces_expected_output_for(TestCase testCase) throws IOException {
return;
}

// exception: Cucumber JVM does not support messages for global hooks
if ("global-hooks".equals(testCase.getId())
|| "global-hooks-afterall-error".equals(testCase.getId())
|| "global-hooks-attachments".equals(testCase.getId())
|| "global-hooks-beforeall-error".equals(testCase.getId())

) {
return;
}

List<JsonNode> expected = readAllMessages(testCase.getExpectedFile());
List<JsonNode> actual = readAllMessages(outputNdjson);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.cucumber.compatibility.ambiguous;

import io.cucumber.java.en.Given;

public class Ambiguous {
@Given("^is a (.*?) with (.*?)$")
public void first_ambiguous_step(String a, String b) {

}

@Given("^is a step with (.*?)$")
public void second_ambiguous_step(String a) {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.cucumber.compatibility.backgrounds;

import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;

public class Backgrounds {

@Given("an order for {string}")
public void context(String item) {

}

@When("an action")
public void action() {

}

@Then("an outcome")
public void outcome() {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.cucumber.compatibility.docstrings;

import io.cucumber.java.en.Given;

public class DocStrings {

@Given("a doc string:")
public void docString(String docString) {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.cucumber.compatibility.multiplefeatures;

import io.cucumber.java.en.Given;

public class MultipleFeatures {

@Given("an order for {string}")
public void an_order_for_item(String item) {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.cucumber.compatibility.multiplefeaturesreversed;

import io.cucumber.java.en.Given;

public class MultipleFeatures {

@Given("an order for {string}")
public void an_order_for_item(String item) {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.cucumber.compatibility.regularexpression;

import io.cucumber.java.en.Given;

public class RegularExpression {
@Given("^a (.*?)(?: and a (.*?))?(?: and a (.*?))?$")
public void some_vegetables(String a, String b, String c) {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.cucumber.compatibility.rulesbackgrounds;

import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;

public class RulesBackgrounds {

@Given("an order for {string}")
public void context(String item) {

}

@When("an action")
public void action() {

}

@Then("an outcome")
public void outcome() {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.cucumber.compatibility.unusedsteps;

import io.cucumber.java.en.Given;

public class UnusedSteps {

@Given("a step that is used")
public void a_step_that_is_used() {

}

@Given("a step that is not used")
public void a_step_that_is_not_used() {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Feature: Ambiguous steps
Multiple step definitions that match a pickle step result in an AMBIGUOUS status, since Cucumnber cannot determine
which one to execute.

Scenario: Multiple step definitions for a step
Given a step with multiple definitions
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{"meta":{"protocolVersion":"28.0.0","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}}
{"source":{"data":"Feature: Ambiguous steps\n Multiple step definitions that match a pickle step result in an AMBIGUOUS status, since Cucumnber cannot determine\n which one to execute.\n\n Scenario: Multiple step definitions for a step\n Given a step with multiple definitions\n","uri":"samples/ambiguous/ambiguous.feature","mediaType":"text/x.cucumber.gherkin+plain"}}
{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Ambiguous steps","description":" Multiple step definitions that match a pickle step result in an AMBIGUOUS status, since Cucumnber cannot determine\n which one to execute.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":5,"column":3},"keyword":"Scenario","name":"Multiple step definitions for a step","description":"","steps":[{"id":"0","location":{"line":6,"column":5},"keyword":"Given ","keywordType":"Context","text":"a step with multiple definitions"}],"examples":[]}}]},"comments":[],"uri":"samples/ambiguous/ambiguous.feature"}}
{"pickle":{"id":"3","uri":"samples/ambiguous/ambiguous.feature","astNodeIds":["1"],"tags":[],"name":"Multiple step definitions for a step","language":"en","steps":[{"id":"2","text":"a step with multiple definitions","type":"Context","astNodeIds":["0"]}]}}
{"stepDefinition":{"id":"4","pattern":{"type":"REGULAR_EXPRESSION","source":"a (.*?) with (.*?)"},"sourceReference":{"uri":"samples/ambiguous/ambiguous.ts","location":{"line":3}}}}
{"stepDefinition":{"id":"5","pattern":{"type":"REGULAR_EXPRESSION","source":"a step with (.*)"},"sourceReference":{"uri":"samples/ambiguous/ambiguous.ts","location":{"line":7}}}}
{"testRunStarted":{"id":"6","timestamp":{"seconds":0,"nanos":0}}}
{"testCase":{"id":"7","pickleId":"3","testSteps":[{"id":"8","pickleStepId":"2","stepDefinitionIds":["4","5"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":2,"value":"step","children":[]}},{"group":{"start":12,"value":"","children":[]}}]},{"stepMatchArguments":[{"group":{"start":12,"value":"multiple definitions","children":[]},"parameterTypeName":""}]}]}],"testRunStartedId":"6"}}
{"testCaseStarted":{"id":"9","testCaseId":"7","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}}
{"testStepStarted":{"testCaseStartedId":"9","testStepId":"8","timestamp":{"seconds":0,"nanos":2000000}}}
{"testStepFinished":{"testCaseStartedId":"9","testStepId":"8","testStepResult":{"status":"AMBIGUOUS","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":3000000}}}
{"testCaseFinished":{"testCaseStartedId":"9","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}}
{"testRunFinished":{"testRunStartedId":"6","timestamp":{"seconds":0,"nanos":5000000},"success":false}}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Feature: Backgrounds
Though not recommended, Backgrounds can be used to share context steps between Scenarios. The Background steps
are prepended to the steps in each Scenario when they are compiled to Pickles. Only one Background at the Feature
level is supported.

Background:
Given an order for "eggs"
And an order for "milk"
And an order for "bread"

Scenario: one scenario
When an action
Then an outcome

Scenario: another scenario
When an action
Then an outcome
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{"meta":{"protocolVersion":"28.0.0","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}}
{"source":{"data":"Feature: Backgrounds\n Though not recommended, Backgrounds can be used to share context steps between Scenarios. The Background steps\n are prepended to the steps in each Scenario when they are compiled to Pickles. Only one Background at the Feature\n level is supported.\n\n Background:\n Given an order for \"eggs\"\n And an order for \"milk\"\n And an order for \"bread\"\n\n Scenario: one scenario\n When an action\n Then an outcome\n\n Scenario: another scenario\n When an action\n Then an outcome","uri":"samples/backgrounds/backgrounds.feature","mediaType":"text/x.cucumber.gherkin+plain"}}
{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Backgrounds","description":" Though not recommended, Backgrounds can be used to share context steps between Scenarios. The Background steps\n are prepended to the steps in each Scenario when they are compiled to Pickles. Only one Background at the Feature\n level is supported.","children":[{"background":{"id":"3","location":{"line":6,"column":3},"keyword":"Background","name":"","description":"","steps":[{"id":"0","location":{"line":7,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"eggs\""},{"id":"1","location":{"line":8,"column":5},"keyword":"And ","keywordType":"Conjunction","text":"an order for \"milk\""},{"id":"2","location":{"line":9,"column":5},"keyword":"And ","keywordType":"Conjunction","text":"an order for \"bread\""}]}},{"scenario":{"id":"6","tags":[],"location":{"line":11,"column":3},"keyword":"Scenario","name":"one scenario","description":"","steps":[{"id":"4","location":{"line":12,"column":5},"keyword":"When ","keywordType":"Action","text":"an action"},{"id":"5","location":{"line":13,"column":5},"keyword":"Then ","keywordType":"Outcome","text":"an outcome"}],"examples":[]}},{"scenario":{"id":"9","tags":[],"location":{"line":15,"column":3},"keyword":"Scenario","name":"another scenario","description":"","steps":[{"id":"7","location":{"line":16,"column":5},"keyword":"When ","keywordType":"Action","text":"an action"},{"id":"8","location":{"line":17,"column":5},"keyword":"Then ","keywordType":"Outcome","text":"an outcome"}],"examples":[]}}]},"comments":[],"uri":"samples/backgrounds/backgrounds.feature"}}
{"pickle":{"id":"15","uri":"samples/backgrounds/backgrounds.feature","astNodeIds":["6"],"tags":[],"name":"one scenario","language":"en","steps":[{"id":"10","text":"an order for \"eggs\"","type":"Context","astNodeIds":["0"]},{"id":"11","text":"an order for \"milk\"","type":"Context","astNodeIds":["1"]},{"id":"12","text":"an order for \"bread\"","type":"Context","astNodeIds":["2"]},{"id":"13","text":"an action","type":"Action","astNodeIds":["4"]},{"id":"14","text":"an outcome","type":"Outcome","astNodeIds":["5"]}]}}
{"pickle":{"id":"21","uri":"samples/backgrounds/backgrounds.feature","astNodeIds":["9"],"tags":[],"name":"another scenario","language":"en","steps":[{"id":"16","text":"an order for \"eggs\"","type":"Context","astNodeIds":["0"]},{"id":"17","text":"an order for \"milk\"","type":"Context","astNodeIds":["1"]},{"id":"18","text":"an order for \"bread\"","type":"Context","astNodeIds":["2"]},{"id":"19","text":"an action","type":"Action","astNodeIds":["7"]},{"id":"20","text":"an outcome","type":"Outcome","astNodeIds":["8"]}]}}
{"stepDefinition":{"id":"22","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an order for {string}"},"sourceReference":{"uri":"samples/backgrounds/backgrounds.ts","location":{"line":3}}}}
{"stepDefinition":{"id":"23","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an action"},"sourceReference":{"uri":"samples/backgrounds/backgrounds.ts","location":{"line":7}}}}
{"stepDefinition":{"id":"24","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an outcome"},"sourceReference":{"uri":"samples/backgrounds/backgrounds.ts","location":{"line":11}}}}
{"testRunStarted":{"id":"25","timestamp":{"seconds":0,"nanos":0}}}
{"testCase":{"id":"26","pickleId":"15","testSteps":[{"id":"27","pickleStepId":"10","stepDefinitionIds":["22"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"eggs\"","children":[{"start":14,"value":"eggs","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"28","pickleStepId":"11","stepDefinitionIds":["22"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"milk\"","children":[{"start":14,"value":"milk","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"29","pickleStepId":"12","stepDefinitionIds":["22"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"bread\"","children":[{"start":14,"value":"bread","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"30","pickleStepId":"13","stepDefinitionIds":["23"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"31","pickleStepId":"14","stepDefinitionIds":["24"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"25"}}
{"testCase":{"id":"32","pickleId":"21","testSteps":[{"id":"33","pickleStepId":"16","stepDefinitionIds":["22"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"eggs\"","children":[{"start":14,"value":"eggs","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"34","pickleStepId":"17","stepDefinitionIds":["22"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"milk\"","children":[{"start":14,"value":"milk","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"35","pickleStepId":"18","stepDefinitionIds":["22"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"bread\"","children":[{"start":14,"value":"bread","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"36","pickleStepId":"19","stepDefinitionIds":["23"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"37","pickleStepId":"20","stepDefinitionIds":["24"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"25"}}
{"testCaseStarted":{"id":"38","testCaseId":"26","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}}
{"testStepStarted":{"testCaseStartedId":"38","testStepId":"27","timestamp":{"seconds":0,"nanos":2000000}}}
{"testStepFinished":{"testCaseStartedId":"38","testStepId":"27","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}}
{"testStepStarted":{"testCaseStartedId":"38","testStepId":"28","timestamp":{"seconds":0,"nanos":4000000}}}
{"testStepFinished":{"testCaseStartedId":"38","testStepId":"28","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":5000000}}}
{"testStepStarted":{"testCaseStartedId":"38","testStepId":"29","timestamp":{"seconds":0,"nanos":6000000}}}
{"testStepFinished":{"testCaseStartedId":"38","testStepId":"29","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}}
{"testStepStarted":{"testCaseStartedId":"38","testStepId":"30","timestamp":{"seconds":0,"nanos":8000000}}}
{"testStepFinished":{"testCaseStartedId":"38","testStepId":"30","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":9000000}}}
{"testStepStarted":{"testCaseStartedId":"38","testStepId":"31","timestamp":{"seconds":0,"nanos":10000000}}}
{"testStepFinished":{"testCaseStartedId":"38","testStepId":"31","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":11000000}}}
{"testCaseFinished":{"testCaseStartedId":"38","timestamp":{"seconds":0,"nanos":12000000},"willBeRetried":false}}
{"testCaseStarted":{"id":"39","testCaseId":"32","timestamp":{"seconds":0,"nanos":13000000},"attempt":0}}
{"testStepStarted":{"testCaseStartedId":"39","testStepId":"33","timestamp":{"seconds":0,"nanos":14000000}}}
{"testStepFinished":{"testCaseStartedId":"39","testStepId":"33","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":15000000}}}
{"testStepStarted":{"testCaseStartedId":"39","testStepId":"34","timestamp":{"seconds":0,"nanos":16000000}}}
{"testStepFinished":{"testCaseStartedId":"39","testStepId":"34","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":17000000}}}
{"testStepStarted":{"testCaseStartedId":"39","testStepId":"35","timestamp":{"seconds":0,"nanos":18000000}}}
{"testStepFinished":{"testCaseStartedId":"39","testStepId":"35","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":19000000}}}
{"testStepStarted":{"testCaseStartedId":"39","testStepId":"36","timestamp":{"seconds":0,"nanos":20000000}}}
{"testStepFinished":{"testCaseStartedId":"39","testStepId":"36","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":21000000}}}
{"testStepStarted":{"testCaseStartedId":"39","testStepId":"37","timestamp":{"seconds":0,"nanos":22000000}}}
{"testStepFinished":{"testCaseStartedId":"39","testStepId":"37","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":23000000}}}
{"testCaseFinished":{"testCaseStartedId":"39","timestamp":{"seconds":0,"nanos":24000000},"willBeRetried":false}}
{"testRunFinished":{"testRunStartedId":"25","timestamp":{"seconds":0,"nanos":25000000},"success":true}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Feature: Doc strings
Doc strings are a way to supply long, sometimes multi-line, text to a step. They are passed as the last argument
to the step definition.

Scenario: a doc string with standard delimiter
Three double quotes above and below are the standard delimiter for doc strings.

Given a doc string:
"""
Here is some content
And some more on another line
"""

Scenario: a doc string with backticks delimiter
Backticks can also be used, like Markdown, but are less widely supported by editors.

Given a doc string:
```
Here is some content
And some more on another line
```

Scenario: a doc string with media type
The media type can be optionally specified too, following the opening delimiter.

Given a doc string:
"""application/json
{
"foo": "bar"
}
"""
Loading
Loading