From ecd2dfebbdab53cb9f08a3defa1abb447f17538c Mon Sep 17 00:00:00 2001
From: John Lonergan <836248+Johnlon@users.noreply.github.com>
Date: Wed, 16 Oct 2024 15:41:47 +0100
Subject: [PATCH] Ambiguous step detection - add support to all formatters
(#648)
* added the missing impl of json/events/junit/pretty - still need 'progress' and 'junit,pretty'
* added tests for "progress formatter"
* switched from tabs to spaces in the ambiguous steps error message
* rename some_scenarions_including_failing
to some_scenarios_including_failing
* changelog
---
CHANGELOG.md | 2 +-
internal/formatters/fmt.go | 2 +-
internal/formatters/fmt_base.go | 9 +-
internal/formatters/fmt_cucumber.go | 2 +-
internal/formatters/fmt_events.go | 12 +-
internal/formatters/fmt_junit.go | 6 +
internal/formatters/fmt_output_test.go | 110 +++++++++++++++++-
internal/formatters/fmt_pretty.go | 13 +++
internal/formatters/fmt_progress.go | 12 ++
...iling => some_scenarios_including_failing} | 39 ++++++-
.../events/some_scenarions_including_failing | 29 -----
.../events/some_scenarios_including_failing | 36 ++++++
... some_scenarios_including_failing.feature} | 4 +
...iling => some_scenarios_including_failing} | 30 +++--
...iling => some_scenarios_including_failing} | 8 +-
...iling => some_scenarios_including_failing} | 22 ++--
.../some_scenarions_including_failing | 10 +-
suite.go | 5 +-
18 files changed, 285 insertions(+), 66 deletions(-)
rename internal/formatters/formatter-tests/cucumber/{some_scenarions_including_failing => some_scenarios_including_failing} (72%)
delete mode 100644 internal/formatters/formatter-tests/events/some_scenarions_including_failing
create mode 100644 internal/formatters/formatter-tests/events/some_scenarios_including_failing
rename internal/formatters/formatter-tests/features/{some_scenarions_including_failing.feature => some_scenarios_including_failing.feature} (77%)
rename internal/formatters/formatter-tests/junit,pretty/{some_scenarions_including_failing => some_scenarios_including_failing} (63%)
rename internal/formatters/formatter-tests/junit/{some_scenarions_including_failing => some_scenarios_including_failing} (69%)
rename internal/formatters/formatter-tests/pretty/{some_scenarions_including_failing => some_scenarios_including_failing} (61%)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f1a4678..d0ca199 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,7 +9,7 @@ This document is formatted according to the principles of [Keep A CHANGELOG](htt
## Unreleased
- Improved the type checking of step return types and improved the error messages - ([647](https://github.com/cucumber/godog/pull/647) - [johnlon](https://github.com/johnlon))
-- Ambiguous step definitions will now be detected when strict mode is activated - ([636](https://github.com/cucumber/godog/pull/636) - [johnlon](https://github.com/johnlon))
+- Ambiguous step definitions will now be detected when strict mode is activated - ([636](https://github.com/cucumber/godog/pull/636)/([648](https://github.com/cucumber/godog/pull/648) - [johnlon](https://github.com/johnlon))
- Provide support for attachments / embeddings including a new example in the examples dir - ([623](https://github.com/cucumber/godog/pull/623) - [johnlon](https://github.com/johnlon))
## [v0.14.1]
diff --git a/internal/formatters/fmt.go b/internal/formatters/fmt.go
index 08e6b54..3efe1f4 100644
--- a/internal/formatters/fmt.go
+++ b/internal/formatters/fmt.go
@@ -36,7 +36,7 @@ var (
skipped = models.Skipped
undefined = models.Undefined
pending = models.Pending
- ambiguous = models.Skipped
+ ambiguous = models.Ambiguous
)
type sortFeaturesByName []*models.Feature
diff --git a/internal/formatters/fmt_base.go b/internal/formatters/fmt_base.go
index 2b3276b..607a1c0 100644
--- a/internal/formatters/fmt_base.go
+++ b/internal/formatters/fmt_base.go
@@ -92,7 +92,7 @@ func (f *Base) Ambiguous(*messages.Pickle, *messages.PickleStep, *formatters.Ste
// Summary renders summary information.
func (f *Base) Summary() {
var totalSc, passedSc, undefinedSc int
- var totalSt, passedSt, failedSt, skippedSt, pendingSt, undefinedSt int
+ var totalSt, passedSt, failedSt, skippedSt, pendingSt, undefinedSt, ambiguousSt int
pickleResults := f.Storage.MustGetPickleResults()
for _, pr := range pickleResults {
@@ -114,6 +114,9 @@ func (f *Base) Summary() {
case failed:
prStatus = failed
failedSt++
+ case ambiguous:
+ prStatus = ambiguous
+ ambiguousSt++
case skipped:
skippedSt++
case undefined:
@@ -144,6 +147,10 @@ func (f *Base) Summary() {
parts = append(parts, yellow(fmt.Sprintf("%d pending", pendingSt)))
steps = append(steps, yellow(fmt.Sprintf("%d pending", pendingSt)))
}
+ if ambiguousSt > 0 {
+ parts = append(parts, yellow(fmt.Sprintf("%d ambiguous", ambiguousSt)))
+ steps = append(steps, yellow(fmt.Sprintf("%d ambiguous", ambiguousSt)))
+ }
if undefinedSt > 0 {
parts = append(parts, yellow(fmt.Sprintf("%d undefined", undefinedSc)))
steps = append(steps, yellow(fmt.Sprintf("%d undefined", undefinedSt)))
diff --git a/internal/formatters/fmt_cucumber.go b/internal/formatters/fmt_cucumber.go
index a3de673..31380c9 100644
--- a/internal/formatters/fmt_cucumber.go
+++ b/internal/formatters/fmt_cucumber.go
@@ -299,7 +299,7 @@ func (f *Cuke) buildCukeStep(pickle *messages.Pickle, stepResult models.PickleSt
cukeStep.Result.Error = stepResult.Err.Error()
}
- if stepResult.Status == undefined || stepResult.Status == pending {
+ if stepResult.Status == undefined || stepResult.Status == pending || stepResult.Status == ambiguous {
cukeStep.Match.Location = fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line)
}
diff --git a/internal/formatters/fmt_events.go b/internal/formatters/fmt_events.go
index 4ed401c..c5ffcb5 100644
--- a/internal/formatters/fmt_events.go
+++ b/internal/formatters/fmt_events.go
@@ -198,7 +198,7 @@ func (f *Events) step(pickle *messages.Pickle, pickleStep *messages.PickleStep)
pickleStepResults := f.Storage.MustGetPickleStepResultsByPickleID(pickle.Id)
for _, stepResult := range pickleStepResults {
switch stepResult.Status {
- case passed, failed, undefined, pending:
+ case passed, failed, undefined, pending, ambiguous:
status = stepResult.Status.String()
}
}
@@ -318,6 +318,16 @@ func (f *Events) Pending(pickle *messages.Pickle, step *messages.PickleStep, mat
f.step(pickle, step)
}
+// Ambiguous captures ambiguous step.
+func (f *Events) Ambiguous(pickle *messages.Pickle, step *messages.PickleStep, match *formatters.StepDefinition, err error) {
+ f.Base.Ambiguous(pickle, step, match, err)
+
+ f.Lock.Lock()
+ defer f.Lock.Unlock()
+
+ f.step(pickle, step)
+}
+
func (f *Events) scenarioLocation(pickle *messages.Pickle) string {
feature := f.Storage.MustGetFeature(pickle.Uri)
scenario := feature.FindScenario(pickle.AstNodeIds[0])
diff --git a/internal/formatters/fmt_junit.go b/internal/formatters/fmt_junit.go
index bc6ed27..d7b2517 100644
--- a/internal/formatters/fmt_junit.go
+++ b/internal/formatters/fmt_junit.go
@@ -117,6 +117,12 @@ func (f *JUnit) buildJUNITPackageSuite() JunitPackageSuite {
tc.Failure = &junitFailure{
Message: fmt.Sprintf("Step %s: %s", pickleStep.Text, stepResult.Err),
}
+ case ambiguous:
+ tc.Status = ambiguous.String()
+ tc.Error = append(tc.Error, &junitError{
+ Type: "ambiguous",
+ Message: fmt.Sprintf("Step %s", pickleStep.Text),
+ })
case skipped:
tc.Error = append(tc.Error, &junitError{
Type: "skipped",
diff --git a/internal/formatters/fmt_output_test.go b/internal/formatters/fmt_output_test.go
index 46ac0e7..4cd9f96 100644
--- a/internal/formatters/fmt_output_test.go
+++ b/internal/formatters/fmt_output_test.go
@@ -85,7 +85,7 @@ func fmtOutputTest(fmtName, testName, featureFilePath string) func(*testing.T) {
att := godog.Attachments(ctx)
attCount := len(att)
if attCount != 4 {
- assert.FailNow(tT, "Unexpected attachements: "+sc.Name, "expected 4, found %d", attCount)
+ assert.FailNow(tT, "Unexpected attachments: "+sc.Name, "expected 4, found %d", attCount)
}
ctx = godog.Attach(ctx,
godog.Attachment{Body: []byte("AfterScenarioAttachment"), FileName: "After Scenario Attachment 2", MediaType: "text/plain"},
@@ -144,12 +144,15 @@ func fmtOutputTest(fmtName, testName, featureFilePath string) func(*testing.T) {
ctx.Step(`^(?:a )?failing step`, failingStepDef)
ctx.Step(`^(?:a )?pending step$`, pendingStepDef)
ctx.Step(`^(?:a )?passing step$`, passingStepDef)
+ ctx.Step(`^ambiguous step.*$`, ambiguousStepDef)
+ ctx.Step(`^ambiguous step$`, ambiguousStepDef)
ctx.Step(`^odd (\d+) and even (\d+) number$`, oddEvenStepDef)
ctx.Step(`^(?:a )?a step with a single attachment call for multiple attachments$`, stepWithSingleAttachmentCall)
ctx.Step(`^(?:a )?a step with multiple attachment calls$`, stepWithMultipleAttachmentCalls)
}
return func(t *testing.T) {
+ fmt.Printf("fmt_output_test for format %10s : sample file %v\n", fmtName, featureFilePath)
expectOutputPath := strings.Replace(featureFilePath, "features", fmtName, 1)
expectOutputPath = strings.TrimSuffix(expectOutputPath, path.Ext(expectOutputPath))
if _, err := os.Stat(expectOutputPath); err != nil {
@@ -167,6 +170,7 @@ func fmtOutputTest(fmtName, testName, featureFilePath string) func(*testing.T) {
Format: fmtName,
Paths: []string{featureFilePath},
Output: out,
+ Strict: true,
}
godog.TestSuite{
@@ -178,7 +182,14 @@ func fmtOutputTest(fmtName, testName, featureFilePath string) func(*testing.T) {
// normalise on unix line ending so expected vs actual works cross platform
expected := normalise(string(expectedOutput))
actual := normalise(buf.String())
+
assert.Equalf(t, expected, actual, "path: %s", expectOutputPath)
+
+ // display as a side by side listing as the output of the assert is all one line with embedded newlines and useless
+ if expected != actual {
+ fmt.Printf("Error: fmt: %s, path: %s\n", fmtName, expectOutputPath)
+ compareLists(expected, actual)
+ }
}
}
@@ -192,9 +203,17 @@ func normalise(s string) string {
return normalised
}
-func passingStepDef() error { return nil }
+func passingStepDef() error {
+ return nil
+}
-func oddEvenStepDef(odd, even int) error { return oddOrEven(odd, even) }
+func ambiguousStepDef() error {
+ return nil
+}
+
+func oddEvenStepDef(odd, even int) error {
+ return oddOrEven(odd, even)
+}
func oddOrEven(odd, even int) error {
if odd%2 == 0 {
@@ -239,3 +258,88 @@ func stepWithMultipleAttachmentCalls(ctx context.Context) (context.Context, erro
return ctx, nil
}
+
+// wrapString wraps a string into chunks of the given width.
+func wrapString(s string, width int) []string {
+ var result []string
+ for len(s) > width {
+ result = append(result, s[:width])
+ s = s[width:]
+ }
+ result = append(result, s)
+ return result
+}
+
+// compareLists compares two lists of strings and prints them with wrapped text.
+func compareLists(expected, actual string) {
+ list1 := strings.Split(expected, "\n")
+ list2 := strings.Split(actual, "\n")
+
+ // Get the length of the longer list
+ maxLength := len(list1)
+ if len(list2) > maxLength {
+ maxLength = len(list2)
+ }
+
+ colWid := 60
+ fmtTitle := fmt.Sprintf("%%4s: %%-%ds | %%-%ds\n", colWid+2, colWid+2)
+ fmtData := fmt.Sprintf("%%4d: %%-%ds | %%-%ds %%s\n", colWid+2, colWid+2)
+
+ fmt.Printf(fmtTitle, "#", "expected", "actual")
+
+ for i := 0; i < maxLength; i++ {
+ var val1, val2 string
+
+ // Get the value from list1 if it exists
+ if i < len(list1) {
+ val1 = list1[i]
+ } else {
+ val1 = "N/A"
+ }
+
+ // Get the value from list2 if it exists
+ if i < len(list2) {
+ val2 = list2[i]
+ } else {
+ val2 = "N/A"
+ }
+
+ // Wrap both strings into slices of strings with fixed width
+ wrapped1 := wrapString(val1, colWid)
+ wrapped2 := wrapString(val2, colWid)
+
+ // Find the number of wrapped lines needed for the current pair
+ maxWrappedLines := len(wrapped1)
+ if len(wrapped2) > maxWrappedLines {
+ maxWrappedLines = len(wrapped2)
+ }
+
+ // Print the wrapped lines with alignment
+ for j := 0; j < maxWrappedLines; j++ {
+ var line1, line2 string
+
+ // Get the wrapped line or use an empty string if it doesn't exist
+ if j < len(wrapped1) {
+ line1 = wrapped1[j]
+ } else {
+ line1 = ""
+ }
+
+ if j < len(wrapped2) {
+ line2 = wrapped2[j]
+ } else {
+ line2 = ""
+ }
+
+ status := "same"
+ // if val1 != val2 {
+ if line1 != line2 {
+ status = "different"
+ }
+
+ delim := "¬"
+ // Print the wrapped lines with fixed-width column
+ fmt.Printf(fmtData, i+1, delim+line1+delim, delim+line2+delim, status)
+ }
+ }
+}
diff --git a/internal/formatters/fmt_pretty.go b/internal/formatters/fmt_pretty.go
index e7b9e32..91dbc0c 100644
--- a/internal/formatters/fmt_pretty.go
+++ b/internal/formatters/fmt_pretty.go
@@ -114,6 +114,16 @@ func (f *Pretty) Failed(pickle *messages.Pickle, step *messages.PickleStep, matc
f.printStep(pickle, step)
}
+// Failed captures failed step.
+func (f *Pretty) Ambiguous(pickle *messages.Pickle, step *messages.PickleStep, match *formatters.StepDefinition, err error) {
+ f.Base.Ambiguous(pickle, step, match, err)
+
+ f.Lock.Lock()
+ defer f.Lock.Unlock()
+
+ f.printStep(pickle, step)
+}
+
// Pending captures pending step.
func (f *Pretty) Pending(pickle *messages.Pickle, step *messages.PickleStep, match *formatters.StepDefinition) {
f.Base.Pending(pickle, step, match)
@@ -269,6 +279,9 @@ func (f *Pretty) printOutlineExample(pickle *messages.Pickle, backgroundSteps in
case result.Status == failed:
errorMsg = result.Err.Error()
clr = result.Status.Color()
+ case result.Status == ambiguous:
+ errorMsg = result.Err.Error()
+ clr = result.Status.Color()
case result.Status == undefined || result.Status == pending:
clr = result.Status.Color()
case result.Status == skipped && clr == nil:
diff --git a/internal/formatters/fmt_progress.go b/internal/formatters/fmt_progress.go
index 2308696..9722ef7 100644
--- a/internal/formatters/fmt_progress.go
+++ b/internal/formatters/fmt_progress.go
@@ -98,6 +98,8 @@ func (f *Progress) step(pickleStepID string) {
fmt.Fprint(f.out, red("F"))
case undefined:
fmt.Fprint(f.out, yellow("U"))
+ case ambiguous:
+ fmt.Fprint(f.out, yellow("A"))
case pending:
fmt.Fprint(f.out, yellow("P"))
}
@@ -149,6 +151,16 @@ func (f *Progress) Failed(pickle *messages.Pickle, step *messages.PickleStep, ma
f.step(step.Id)
}
+// Ambiguous steps.
+func (f *Progress) Ambiguous(pickle *messages.Pickle, step *messages.PickleStep, match *formatters.StepDefinition, err error) {
+ f.Base.Ambiguous(pickle, step, match, err)
+
+ f.Lock.Lock()
+ defer f.Lock.Unlock()
+
+ f.step(step.Id)
+}
+
// Pending captures pending step.
func (f *Progress) Pending(pickle *messages.Pickle, step *messages.PickleStep, match *formatters.StepDefinition) {
f.Base.Pending(pickle, step, match)
diff --git a/internal/formatters/formatter-tests/cucumber/some_scenarions_including_failing b/internal/formatters/formatter-tests/cucumber/some_scenarios_including_failing
similarity index 72%
rename from internal/formatters/formatter-tests/cucumber/some_scenarions_including_failing
rename to internal/formatters/formatter-tests/cucumber/some_scenarios_including_failing
index a1864e1..fbc8562 100644
--- a/internal/formatters/formatter-tests/cucumber/some_scenarions_including_failing
+++ b/internal/formatters/formatter-tests/cucumber/some_scenarios_including_failing
@@ -1,6 +1,6 @@
[
{
- "uri": "formatter-tests/features/some_scenarions_including_failing.feature",
+ "uri": "formatter-tests/features/some_scenarios_including_failing.feature",
"id": "some-scenarios",
"keyword": "Feature",
"name": "some scenarios",
@@ -66,7 +66,7 @@
"name": "pending step",
"line": 9,
"match": {
- "location": "formatter-tests/features/some_scenarions_including_failing.feature:9"
+ "location": "formatter-tests/features/some_scenarios_including_failing.feature:9"
},
"result": {
"status": "pending"
@@ -98,7 +98,7 @@
"name": "undefined",
"line": 13,
"match": {
- "location": "formatter-tests/features/some_scenarions_including_failing.feature:13"
+ "location": "formatter-tests/features/some_scenarios_including_failing.feature:13"
},
"result": {
"status": "undefined"
@@ -116,6 +116,39 @@
}
}
]
+ },
+ {
+ "id": "some-scenarios;ambiguous",
+ "keyword": "Scenario",
+ "name": "ambiguous",
+ "description": "",
+ "line": 16,
+ "type": "scenario",
+ "steps": [
+ {
+ "keyword": "When ",
+ "name": "ambiguous step",
+ "line": 17,
+ "match": {
+ "location": "formatter-tests/features/some_scenarios_including_failing.feature:17"
+ },
+ "result": {
+ "status": "ambiguous",
+ "error_message": "ambiguous step definition, step text: ambiguous step\n matches:\n ^ambiguous step.*$\n ^ambiguous step$"
+ }
+ },
+ {
+ "keyword": "Then ",
+ "name": "passing step",
+ "line": 18,
+ "match": {
+ "location": "fmt_output_test.go:XXX"
+ },
+ "result": {
+ "status": "skipped"
+ }
+ }
+ ]
}
]
}
diff --git a/internal/formatters/formatter-tests/events/some_scenarions_including_failing b/internal/formatters/formatter-tests/events/some_scenarions_including_failing
deleted file mode 100644
index 53606be..0000000
--- a/internal/formatters/formatter-tests/events/some_scenarions_including_failing
+++ /dev/null
@@ -1,29 +0,0 @@
-{"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"}
-{"event":"TestSource","location":"formatter-tests/features/some_scenarions_including_failing.feature:1","source":"Feature: some scenarios\n\n Scenario: failing\n Given passing step\n When failing step\n Then passing step\n\n Scenario: pending\n When pending step\n Then passing step\n\n Scenario: undefined\n When undefined\n Then passing step\n"}
-{"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:3","timestamp":-6795364578871}
-{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:4","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
-{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:4","timestamp":-6795364578871}
-{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:4","timestamp":-6795364578871,"status":"passed"}
-{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:5","definition_id":"fmt_output_test.go:117 -\u003e github.com/cucumber/godog/internal/formatters_test.failingStepDef","arguments":[]}
-{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:5","timestamp":-6795364578871}
-{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:5","timestamp":-6795364578871,"status":"failed","summary":"step failed"}
-{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
-{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:6","timestamp":-6795364578871}
-{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:6","timestamp":-6795364578871,"status":"skipped"}
-{"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:3","timestamp":-6795364578871,"status":"failed"}
-{"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:8","timestamp":-6795364578871}
-{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:9","definition_id":"fmt_output_test.go:115 -\u003e github.com/cucumber/godog/internal/formatters_test.pendingStepDef","arguments":[]}
-{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:9","timestamp":-6795364578871}
-{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:9","timestamp":-6795364578871,"status":"pending"}
-{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:10","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
-{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:10","timestamp":-6795364578871}
-{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:10","timestamp":-6795364578871,"status":"skipped"}
-{"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:8","timestamp":-6795364578871,"status":"pending"}
-{"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:12","timestamp":-6795364578871}
-{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:13","timestamp":-6795364578871}
-{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:13","timestamp":-6795364578871,"status":"undefined"}
-{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:14","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
-{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:14","timestamp":-6795364578871}
-{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:14","timestamp":-6795364578871,"status":"skipped"}
-{"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:12","timestamp":-6795364578871,"status":"undefined"}
-{"event":"TestRunFinished","status":"failed","timestamp":-6795364578871,"snippets":"You can implement step definitions for undefined steps with these snippets:\n\nfunc undefined() error {\n\treturn godog.ErrPending\n}\n\nfunc InitializeScenario(ctx *godog.ScenarioContext) {\n\tctx.Step(`^undefined$`, undefined)\n}\n","memory":""}
diff --git a/internal/formatters/formatter-tests/events/some_scenarios_including_failing b/internal/formatters/formatter-tests/events/some_scenarios_including_failing
new file mode 100644
index 0000000..e56b4c5
--- /dev/null
+++ b/internal/formatters/formatter-tests/events/some_scenarios_including_failing
@@ -0,0 +1,36 @@
+{"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"}
+{"event":"TestSource","location":"formatter-tests/features/some_scenarios_including_failing.feature:1","source":"Feature: some scenarios\n\n Scenario: failing\n Given passing step\n When failing step\n Then passing step\n\n Scenario: pending\n When pending step\n Then passing step\n\n Scenario: undefined\n When undefined\n Then passing step\n\n Scenario: ambiguous\n When ambiguous step\n Then passing step\n"}
+{"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarios_including_failing.feature:3","timestamp":-6795364578871}
+{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarios_including_failing.feature:4","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
+{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarios_including_failing.feature:4","timestamp":-6795364578871}
+{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarios_including_failing.feature:4","timestamp":-6795364578871,"status":"passed"}
+{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarios_including_failing.feature:5","definition_id":"fmt_output_test.go:117 -\u003e github.com/cucumber/godog/internal/formatters_test.failingStepDef","arguments":[]}
+{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarios_including_failing.feature:5","timestamp":-6795364578871}
+{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarios_including_failing.feature:5","timestamp":-6795364578871,"status":"failed","summary":"step failed"}
+{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarios_including_failing.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
+{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarios_including_failing.feature:6","timestamp":-6795364578871}
+{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarios_including_failing.feature:6","timestamp":-6795364578871,"status":"skipped"}
+{"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarios_including_failing.feature:3","timestamp":-6795364578871,"status":"failed"}
+{"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarios_including_failing.feature:8","timestamp":-6795364578871}
+{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarios_including_failing.feature:9","definition_id":"fmt_output_test.go:115 -\u003e github.com/cucumber/godog/internal/formatters_test.pendingStepDef","arguments":[]}
+{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarios_including_failing.feature:9","timestamp":-6795364578871}
+{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarios_including_failing.feature:9","timestamp":-6795364578871,"status":"pending"}
+{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarios_including_failing.feature:10","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
+{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarios_including_failing.feature:10","timestamp":-6795364578871}
+{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarios_including_failing.feature:10","timestamp":-6795364578871,"status":"skipped"}
+{"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarios_including_failing.feature:8","timestamp":-6795364578871,"status":"pending"}
+{"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarios_including_failing.feature:12","timestamp":-6795364578871}
+{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarios_including_failing.feature:13","timestamp":-6795364578871}
+{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarios_including_failing.feature:13","timestamp":-6795364578871,"status":"undefined"}
+{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarios_including_failing.feature:14","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
+{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarios_including_failing.feature:14","timestamp":-6795364578871}
+{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarios_including_failing.feature:14","timestamp":-6795364578871,"status":"skipped"}
+{"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarios_including_failing.feature:12","timestamp":-6795364578871,"status":"undefined"}
+{"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarios_including_failing.feature:16","timestamp":-6795364578871}
+{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarios_including_failing.feature:17","timestamp":-6795364578871}
+{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarios_including_failing.feature:17","timestamp":-6795364578871,"status":"ambiguous","summary":"ambiguous step definition, step text: ambiguous step\n matches:\n ^ambiguous step.*$\n ^ambiguous step$"}
+{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarios_including_failing.feature:18","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
+{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarios_including_failing.feature:18","timestamp":-6795364578871}
+{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarios_including_failing.feature:18","timestamp":-6795364578871,"status":"skipped"}
+{"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarios_including_failing.feature:16","timestamp":-6795364578871,"status":"ambiguous"}
+{"event":"TestRunFinished","status":"failed","timestamp":-6795364578871,"snippets":"You can implement step definitions for undefined steps with these snippets:\n\nfunc undefined() error {\n\treturn godog.ErrPending\n}\n\nfunc InitializeScenario(ctx *godog.ScenarioContext) {\n\tctx.Step(`^undefined$`, undefined)\n}\n","memory":""}
diff --git a/internal/formatters/formatter-tests/features/some_scenarions_including_failing.feature b/internal/formatters/formatter-tests/features/some_scenarios_including_failing.feature
similarity index 77%
rename from internal/formatters/formatter-tests/features/some_scenarions_including_failing.feature
rename to internal/formatters/formatter-tests/features/some_scenarios_including_failing.feature
index a41f7ef..c62aa94 100644
--- a/internal/formatters/formatter-tests/features/some_scenarions_including_failing.feature
+++ b/internal/formatters/formatter-tests/features/some_scenarios_including_failing.feature
@@ -12,3 +12,7 @@ Feature: some scenarios
Scenario: undefined
When undefined
Then passing step
+
+ Scenario: ambiguous
+ When ambiguous step
+ Then passing step
diff --git a/internal/formatters/formatter-tests/junit,pretty/some_scenarions_including_failing b/internal/formatters/formatter-tests/junit,pretty/some_scenarios_including_failing
similarity index 63%
rename from internal/formatters/formatter-tests/junit,pretty/some_scenarions_including_failing
rename to internal/formatters/formatter-tests/junit,pretty/some_scenarios_including_failing
index 4567095..e44596f 100644
--- a/internal/formatters/formatter-tests/junit,pretty/some_scenarions_including_failing
+++ b/internal/formatters/formatter-tests/junit,pretty/some_scenarios_including_failing
@@ -1,22 +1,30 @@
Feature: some scenarios
- Scenario: failing # formatter-tests/features/some_scenarions_including_failing.feature:3
+ Scenario: failing # formatter-tests/features/some_scenarios_including_failing.feature:3
Given passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef
When failing step # fmt_output_test.go:117 -> github.com/cucumber/godog/internal/formatters_test.failingStepDef
step failed
Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef
- Scenario: pending # formatter-tests/features/some_scenarions_including_failing.feature:8
+ Scenario: pending # formatter-tests/features/some_scenarios_including_failing.feature:8
When pending step # fmt_output_test.go:115 -> github.com/cucumber/godog/internal/formatters_test.pendingStepDef
TODO: write pending definition
Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef
- Scenario: undefined # formatter-tests/features/some_scenarions_including_failing.feature:12
+ Scenario: undefined # formatter-tests/features/some_scenarios_including_failing.feature:12
When undefined
Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef
+
+ Scenario: ambiguous # formatter-tests/features/some_scenarios_including_failing.feature:16
+ When ambiguous step
+ ambiguous step definition, step text: ambiguous step
+ matches:
+ ^ambiguous step.*$
+ ^ambiguous step$
+ Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef
-
-
+
+
@@ -29,17 +37,21 @@
+
+
+
+
--- Failed steps:
- Scenario: failing # formatter-tests/features/some_scenarions_including_failing.feature:3
- When failing step # formatter-tests/features/some_scenarions_including_failing.feature:5
+ Scenario: failing # formatter-tests/features/some_scenarios_including_failing.feature:3
+ When failing step # formatter-tests/features/some_scenarios_including_failing.feature:5
Error: step failed
-3 scenarios (1 failed, 1 pending, 1 undefined)
-7 steps (1 passed, 1 failed, 1 pending, 1 undefined, 3 skipped)
+4 scenarios (1 failed, 1 pending, 1 ambiguous, 1 undefined)
+9 steps (1 passed, 1 failed, 1 pending, 1 ambiguous, 1 undefined, 4 skipped)
0s
You can implement step definitions for undefined steps with these snippets:
diff --git a/internal/formatters/formatter-tests/junit/some_scenarions_including_failing b/internal/formatters/formatter-tests/junit/some_scenarios_including_failing
similarity index 69%
rename from internal/formatters/formatter-tests/junit/some_scenarions_including_failing
rename to internal/formatters/formatter-tests/junit/some_scenarios_including_failing
index 427c7b2..e03af02 100644
--- a/internal/formatters/formatter-tests/junit/some_scenarions_including_failing
+++ b/internal/formatters/formatter-tests/junit/some_scenarios_including_failing
@@ -1,6 +1,6 @@
-
-
+
+
@@ -13,5 +13,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/internal/formatters/formatter-tests/pretty/some_scenarions_including_failing b/internal/formatters/formatter-tests/pretty/some_scenarios_including_failing
similarity index 61%
rename from internal/formatters/formatter-tests/pretty/some_scenarions_including_failing
rename to internal/formatters/formatter-tests/pretty/some_scenarios_including_failing
index 016f09a..6c612a7 100644
--- a/internal/formatters/formatter-tests/pretty/some_scenarions_including_failing
+++ b/internal/formatters/formatter-tests/pretty/some_scenarios_including_failing
@@ -1,29 +1,37 @@
Feature: some scenarios
- Scenario: failing # formatter-tests/features/some_scenarions_including_failing.feature:3
+ Scenario: failing # formatter-tests/features/some_scenarios_including_failing.feature:3
Given passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef
When failing step # fmt_output_test.go:117 -> github.com/cucumber/godog/internal/formatters_test.failingStepDef
step failed
Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef
- Scenario: pending # formatter-tests/features/some_scenarions_including_failing.feature:8
+ Scenario: pending # formatter-tests/features/some_scenarios_including_failing.feature:8
When pending step # fmt_output_test.go:115 -> github.com/cucumber/godog/internal/formatters_test.pendingStepDef
TODO: write pending definition
Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef
- Scenario: undefined # formatter-tests/features/some_scenarions_including_failing.feature:12
+ Scenario: undefined # formatter-tests/features/some_scenarios_including_failing.feature:12
When undefined
Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef
+ Scenario: ambiguous # formatter-tests/features/some_scenarios_including_failing.feature:16
+ When ambiguous step
+ ambiguous step definition, step text: ambiguous step
+ matches:
+ ^ambiguous step.*$
+ ^ambiguous step$
+ Then passing step # fmt_output_test.go:XXX -> github.com/cucumber/godog/internal/formatters_test.passingStepDef
+
--- Failed steps:
- Scenario: failing # formatter-tests/features/some_scenarions_including_failing.feature:3
- When failing step # formatter-tests/features/some_scenarions_including_failing.feature:5
+ Scenario: failing # formatter-tests/features/some_scenarios_including_failing.feature:3
+ When failing step # formatter-tests/features/some_scenarios_including_failing.feature:5
Error: step failed
-3 scenarios (1 failed, 1 pending, 1 undefined)
-7 steps (1 passed, 1 failed, 1 pending, 1 undefined, 3 skipped)
+4 scenarios (1 failed, 1 pending, 1 ambiguous, 1 undefined)
+9 steps (1 passed, 1 failed, 1 pending, 1 ambiguous, 1 undefined, 4 skipped)
0s
You can implement step definitions for undefined steps with these snippets:
diff --git a/internal/formatters/formatter-tests/progress/some_scenarions_including_failing b/internal/formatters/formatter-tests/progress/some_scenarions_including_failing
index 43146df..55dca49 100644
--- a/internal/formatters/formatter-tests/progress/some_scenarions_including_failing
+++ b/internal/formatters/formatter-tests/progress/some_scenarions_including_failing
@@ -1,15 +1,15 @@
-.F-P-U- 7
+.F-P-U-A- 9
--- Failed steps:
- Scenario: failing # formatter-tests/features/some_scenarions_including_failing.feature:3
- When failing step # formatter-tests/features/some_scenarions_including_failing.feature:5
+ Scenario: failing # formatter-tests/features/some_scenarios_including_failing.feature:3
+ When failing step # formatter-tests/features/some_scenarios_including_failing.feature:5
Error: step failed
-3 scenarios (1 failed, 1 pending, 1 undefined)
-7 steps (1 passed, 1 failed, 1 pending, 1 undefined, 3 skipped)
+4 scenarios (1 failed, 1 pending, 1 ambiguous, 1 undefined)
+9 steps (1 passed, 1 failed, 1 pending, 1 ambiguous, 1 undefined, 4 skipped)
0s
You can implement step definitions for undefined steps with these snippets:
diff --git a/suite.go b/suite.go
index 44f0e20..9a38729 100644
--- a/suite.go
+++ b/suite.go
@@ -541,9 +541,8 @@ func (s *suite) matchStepTextAndType(text string, stepType messages.PickleStepTy
if s.strict {
if len(matchingExpressions) > 1 {
- fmt.Printf("IS STRICT=%v\n", len(matchingExpressions))
- errs := "\n\t\t" + strings.Join(matchingExpressions, "\n\t\t")
- return nil, fmt.Errorf("%w, step text: %s\n\tmatches:%s", ErrAmbiguous, text, errs)
+ errs := "\n " + strings.Join(matchingExpressions, "\n ")
+ return nil, fmt.Errorf("%w, step text: %s\n matches:%s", ErrAmbiguous, text, errs)
}
}