Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pretty Print when using rules (#440) #480

Merged
merged 4 commits into from Jun 17, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
55 changes: 55 additions & 0 deletions features/formatter/pretty.feature
Expand Up @@ -449,3 +449,58 @@ Feature: pretty formatter
16 steps (16 passed)
0s
"""

Scenario: Support of Feature Plus Rule
Given a feature "features/simple.feature" file:
dumpsterfireproject marked this conversation as resolved.
Show resolved Hide resolved
"""
Feature: simple feature with a rule
simple feature description
Rule: simple rule
simple rule description
Example: simple scenario
simple scenario description
Given passing step
"""
When I run feature suite with formatter "pretty"
Then the rendered output will be as follows:
"""
Feature: simple feature with a rule
simple feature description

Example: simple scenario # features/simple.feature:5
Given passing step # suite_context.go:0 -> SuiteContext.func2

1 scenarios (1 passed)
1 steps (1 passed)
0s
"""

Scenario: Support of Feature Plus Rule with Background
dumpsterfireproject marked this conversation as resolved.
Show resolved Hide resolved
Given a feature "features/simple.feature" file:
dumpsterfireproject marked this conversation as resolved.
Show resolved Hide resolved
"""
Feature: simple feature with a rule with Background
simple feature description
Rule: simple rule
simple rule description
Background:
Given passing step
Example: simple scenario
simple scenario description
Given passing step
"""
When I run feature suite with formatter "pretty"
Then the rendered output will be as follows:
"""
Feature: simple feature with a rule with Background
simple feature description

Background:
Given passing step # suite_context.go:0 -> SuiteContext.func2

Example: simple scenario # features/simple.feature:7
Given passing step # suite_context.go:0 -> SuiteContext.func2

1 scenarios (1 passed)
2 steps (2 passed)
0s
"""
26 changes: 25 additions & 1 deletion internal/formatters/fmt_pretty.go
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/cucumber/godog/colors"
"github.com/cucumber/godog/formatters"
"github.com/cucumber/godog/internal/models"
)

func init() {
Expand Down Expand Up @@ -350,15 +351,38 @@ func (f *Pretty) printTableHeader(row *messages.TableRow, max []int) {
f.printTableRow(row, max, cyan)
}

func isFirstScenarioInRule(rule *messages.Rule, scenario *messages.Scenario) bool {
if rule == nil || scenario == nil {
return false
}
var firstScenario *messages.Scenario
for _, c := range rule.Children {
if c.Scenario != nil {
firstScenario = c.Scenario
break
}
}
return firstScenario != nil && firstScenario.Id == scenario.Id
}

func isFirstPickleAndNoRule(feature *models.Feature, pickle *messages.Pickle, rule *messages.Rule) bool {
if rule != nil {
return false
}
return feature.Pickles[0].Id == pickle.Id
}

func (f *Pretty) printStep(pickle *messages.Pickle, pickleStep *messages.PickleStep) {
feature := f.Storage.MustGetFeature(pickle.Uri)
astBackground := feature.FindBackground(pickle.AstNodeIds[0])
astScenario := feature.FindScenario(pickle.AstNodeIds[0])
astRule := feature.FindRule(pickle.AstNodeIds[0])
astStep := feature.FindStep(pickleStep.AstNodeIds[0])

var astBackgroundStep bool
var firstExecutedBackgroundStep bool
var backgroundSteps int

if astBackground != nil {
backgroundSteps = len(astBackground.Steps)

Expand All @@ -371,7 +395,7 @@ func (f *Pretty) printStep(pickle *messages.Pickle, pickleStep *messages.PickleS
}
}

firstPickle := feature.Pickles[0].Id == pickle.Id
firstPickle := isFirstPickleAndNoRule(feature, pickle, astRule) || isFirstScenarioInRule(astRule, astScenario)

if astBackgroundStep && !firstPickle {
return
Expand Down
@@ -0,0 +1,30 @@
Feature: rules with examples with backgrounds

Rule: first rule

Background: for first rule
Given passing step
And passing step

Example: rule 1 example 1
When passing step
Then passing step

Example: rule 1 example 2
When passing step
Then passing step


Rule: second rule

Background: for second rule
Given passing step
And passing step

Example: rule 1 example 1
When passing step
Then passing step

Example: rule 2 example 2
When passing step
Then passing step
@@ -0,0 +1,29 @@
<bold-white>Feature:</bold-white> rules with examples with backgrounds

<bold-white>Background:</bold-white> for first rule
<green>Given</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
<green>And</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>

<bold-white>Example:</bold-white> rule 1 example 1 <bold-black># formatter-tests/features/rules_with_examples_with_backgrounds.feature:9</bold-black>
<green>When</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
<green>Then</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>

<bold-white>Example:</bold-white> rule 1 example 2 <bold-black># formatter-tests/features/rules_with_examples_with_backgrounds.feature:13</bold-black>
<green>When</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
<green>Then</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>

<bold-white>Background:</bold-white> for second rule
<green>Given</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
<green>And</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>

<bold-white>Example:</bold-white> rule 1 example 1 <bold-black># formatter-tests/features/rules_with_examples_with_backgrounds.feature:24</bold-black>
<green>When</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
<green>Then</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>

<bold-white>Example:</bold-white> rule 2 example 2 <bold-black># formatter-tests/features/rules_with_examples_with_backgrounds.feature:28</bold-black>
<green>When</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
<green>Then</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>

4 scenarios (<green>4 passed</green>)
16 steps (<green>16 passed</green>)
0s
71 changes: 70 additions & 1 deletion internal/models/feature.go
Expand Up @@ -13,12 +13,35 @@ type Feature struct {
Content []byte
}

// FindScenario ...
// FindRule returns the rule to which the given scenario belongs
func (f Feature) FindRule(astScenarioID string) *messages.Rule {
for _, child := range f.GherkinDocument.Feature.Children {
if ru := child.Rule; ru != nil {
if rc := child.Rule; rc != nil {
for _, rcc := range rc.Children {
if sc := rcc.Scenario; sc != nil && sc.Id == astScenarioID {
return ru
}
}
}
}
}
return nil
}

// FindScenario returns the scenario in the feature or in a rule in the feature
func (f Feature) FindScenario(astScenarioID string) *messages.Scenario {
for _, child := range f.GherkinDocument.Feature.Children {
if sc := child.Scenario; sc != nil && sc.Id == astScenarioID {
return sc
}
if rc := child.Rule; rc != nil {
for _, rcc := range rc.Children {
if sc := rcc.Scenario; sc != nil && sc.Id == astScenarioID {
return sc
}
}
}
}

return nil
Expand All @@ -36,6 +59,18 @@ func (f Feature) FindBackground(astScenarioID string) *messages.Background {
if sc := child.Scenario; sc != nil && sc.Id == astScenarioID {
return bg
}

if ru := child.Rule; ru != nil {
for _, rc := range ru.Children {
if tmp := rc.Background; tmp != nil {
bg = tmp
}

if sc := rc.Scenario; sc != nil && sc.Id == astScenarioID {
return bg
}
}
}
}

return nil
Expand All @@ -53,6 +88,19 @@ func (f Feature) FindExample(exampleAstID string) (*messages.Examples, *messages
}
}
}
if ru := child.Rule; ru != nil {
for _, rc := range ru.Children {
if sc := rc.Scenario; sc != nil {
for _, example := range sc.Examples {
for _, row := range example.TableBody {
if row.Id == exampleAstID {
return example, row
}
}
}
}
}
}
}

return nil, nil
Expand All @@ -61,6 +109,27 @@ func (f Feature) FindExample(exampleAstID string) (*messages.Examples, *messages
// FindStep ...
func (f Feature) FindStep(astStepID string) *messages.Step {
for _, child := range f.GherkinDocument.Feature.Children {

if ru := child.Rule; ru != nil {
for _, ch := range ru.Children {
if sc := ch.Scenario; sc != nil {
for _, step := range sc.Steps {
if step.Id == astStepID {
return step
}
}
}

if bg := ch.Background; bg != nil {
for _, step := range bg.Steps {
if step.Id == astStepID {
return step
}
}
}
}
}

if sc := child.Scenario; sc != nil {
for _, step := range sc.Steps {
if step.Id == astStepID {
Expand Down
70 changes: 59 additions & 11 deletions internal/models/feature_test.go
Expand Up @@ -3,6 +3,7 @@ package models_test
import (
"testing"

"github.com/cucumber/godog/internal/models"
"github.com/cucumber/godog/internal/testutils"
"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -32,29 +33,76 @@ func Test_Find(t *testing.T) {
assert.NotNilf(t, step, "expected step to not be nil")
}
})

t.Run("rule", func(t *testing.T) {
sc := ft.FindRule(ft.Pickles[0].AstNodeIds[0])
assert.Nilf(t, sc, "expected rule to be nil")
})
}

func Test_NotFind(t *testing.T) {
ft := testutils.BuildTestFeature(t)
func Test_FindInRule(t *testing.T) {

ft := testutils.BuildTestFeatureWithRules(t)

t.Run("rule", func(t *testing.T) {
sc := ft.FindRule(ft.Pickles[0].AstNodeIds[0])
assert.NotNilf(t, sc, "expected rule to not be nil")
})

t.Run("scenario", func(t *testing.T) {
sc := ft.FindScenario("-")
assert.Nilf(t, sc, "expected scenario to be nil")
sc := ft.FindScenario(ft.Pickles[0].AstNodeIds[0])
assert.NotNilf(t, sc, "expected scenario to not be nil")
})

t.Run("background", func(t *testing.T) {
bg := ft.FindBackground("-")
assert.Nilf(t, bg, "expected background to be nil")
bg := ft.FindBackground(ft.Pickles[0].AstNodeIds[0])
assert.NotNilf(t, bg, "expected background to not be nil")
})

t.Run("example", func(t *testing.T) {
example, row := ft.FindExample("-")
assert.Nilf(t, example, "expected example to be nil")
assert.Nilf(t, row, "expected table row to be nil")
example, row := ft.FindExample(ft.Pickles[1].AstNodeIds[1])
assert.NotNilf(t, example, "expected example to not be nil")
assert.NotNilf(t, row, "expected table row to not be nil")
})

t.Run("step", func(t *testing.T) {
step := ft.FindStep("-")
assert.Nilf(t, step, "expected step to be nil")
for _, ps := range ft.Pickles[0].Steps {
step := ft.FindStep(ps.AstNodeIds[0])
assert.NotNilf(t, step, "expected step to not be nil")
}
})
}

func Test_NotFind(t *testing.T) {
testCases := []struct {
Feature models.Feature
}{
{testutils.BuildTestFeature(t)},
{testutils.BuildTestFeatureWithRules(t)},
}

for _, tc := range testCases {

ft := tc.Feature
t.Run("scenario", func(t *testing.T) {
sc := ft.FindScenario("-")
assert.Nilf(t, sc, "expected scenario to be nil")
})

t.Run("background", func(t *testing.T) {
bg := ft.FindBackground("-")
assert.Nilf(t, bg, "expected background to be nil")
})

t.Run("example", func(t *testing.T) {
example, row := ft.FindExample("-")
assert.Nilf(t, example, "expected example to be nil")
assert.Nilf(t, row, "expected table row to be nil")
})

t.Run("step", func(t *testing.T) {
step := ft.FindStep("-")
assert.Nilf(t, step, "expected step to be nil")
})
}
}