* Pretty Print when using rules (#440) * Pretty Print when using rules (#440) * fix a few formatting mistakes (#440) * added test with rule and scenario outline (#440)
Этот коммит содержится в:
родитель
c5a86a4e56
коммит
5d705e5b8e
8 изменённых файлов: 368 добавлений и 19 удалений
|
@ -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
|
||||
"""
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
|
||||
"github.com/cucumber/godog/colors"
|
||||
"github.com/cucumber/godog/formatters"
|
||||
"github.com/cucumber/godog/internal/models"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
|
@ -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")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,3 +58,53 @@ Scenario Outline: Eat <dec> out of <beginning>
|
|||
Examples:
|
||||
| begin | dec | remain |
|
||||
| 12 | 5 | 7 |`
|
||||
|
||||
// BuildTestFeature creates a feature with rules for testing purpose.
|
||||
//
|
||||
// The created feature includes:
|
||||
// - a background
|
||||
// - one normal scenario with three steps
|
||||
// - one outline scenario with one example and three steps
|
||||
func BuildTestFeatureWithRules(t *testing.T) models.Feature {
|
||||
newIDFunc := (&messages.Incrementing{}).NewId
|
||||
|
||||
gherkinDocument, err := gherkin.ParseGherkinDocument(strings.NewReader(featureWithRuleContent), newIDFunc)
|
||||
require.NoError(t, err)
|
||||
|
||||
path := t.Name()
|
||||
gherkinDocument.Uri = path
|
||||
pickles := gherkin.Pickles(*gherkinDocument, path, newIDFunc)
|
||||
|
||||
ft := models.Feature{GherkinDocument: gherkinDocument, Pickles: pickles, Content: []byte(featureWithRuleContent)}
|
||||
require.Len(t, ft.Pickles, 2)
|
||||
|
||||
require.Len(t, ft.Pickles[0].AstNodeIds, 1)
|
||||
require.Len(t, ft.Pickles[0].Steps, 3)
|
||||
|
||||
require.Len(t, ft.Pickles[1].AstNodeIds, 2)
|
||||
require.Len(t, ft.Pickles[1].Steps, 3)
|
||||
|
||||
return ft
|
||||
}
|
||||
|
||||
const featureWithRuleContent = `Feature: eat godogs
|
||||
In order to be happy
|
||||
As a hungry gopher
|
||||
I need to be able to eat godogs
|
||||
|
||||
Rule: eating godogs
|
||||
|
||||
Background:
|
||||
Given there are <begin> godogs
|
||||
|
||||
Scenario: Eat 5 out of 12
|
||||
When I eat 5
|
||||
Then there should be 7 remaining
|
||||
|
||||
Scenario Outline: Eat <dec> out of <beginning>
|
||||
When I eat <dec>
|
||||
Then there should be <remain> remaining
|
||||
|
||||
Examples:
|
||||
| begin | dec | remain |
|
||||
| 12 | 5 | 7 |`
|
||||
|
|
12
run_test.go
12
run_test.go
|
@ -432,11 +432,11 @@ func Test_AllFeaturesRun(t *testing.T) {
|
|||
...................................................................... 140
|
||||
...................................................................... 210
|
||||
...................................................................... 280
|
||||
........................................ 320
|
||||
................................................. 329
|
||||
|
||||
|
||||
83 scenarios (83 passed)
|
||||
320 steps (320 passed)
|
||||
86 scenarios (86 passed)
|
||||
329 steps (329 passed)
|
||||
0s
|
||||
`
|
||||
|
||||
|
@ -459,11 +459,11 @@ func Test_AllFeaturesRunAsSubtests(t *testing.T) {
|
|||
...................................................................... 140
|
||||
...................................................................... 210
|
||||
...................................................................... 280
|
||||
........................................ 320
|
||||
................................................. 329
|
||||
|
||||
|
||||
83 scenarios (83 passed)
|
||||
320 steps (320 passed)
|
||||
86 scenarios (86 passed)
|
||||
329 steps (329 passed)
|
||||
0s
|
||||
`
|
||||
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче