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 all 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
99 changes: 99 additions & 0 deletions features/formatter/pretty.feature
Expand Up @@ -449,3 +449,102 @@ Feature: pretty formatter
16 steps (16 passed)
0s
"""

Scenario: Support of Feature Plus Rule
Given a feature "features/simple.feature" file:
"""
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
Given a feature "features/simple.feature" file:
"""
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
"""

Scenario: Support of Feature Plus Rule with Scenario Outline
Given a feature "features/simple.feature" file:
"""
Feature: simple feature with a rule with Scenario Outline
simple feature description
Rule: simple rule
simple rule description
Scenario Outline: simple scenario
simple scenario description

Given <status> step

Examples: simple examples
| status |
| passing |
| failing |
"""
When I run feature suite with formatter "pretty"
Then the rendered output will be as follows:
"""
Feature: simple feature with a rule with Scenario Outline
simple feature description

Scenario Outline: simple scenario # features/simple.feature:5
Given <status> step # suite_context.go:0 -> SuiteContext.func2

Examples: simple examples
| status |
| passing |
| failing |
intentional failure

--- Failed steps:

Scenario Outline: simple scenario # features/simple.feature:5
Given failing step # features/simple.feature:8
Error: intentional failure


2 scenarios (1 passed, 1 failed)
2 steps (1 passed, 1 failed)
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