improve scenario outline tests and behavior
Этот коммит содержится в:
родитель
996d3d2725
коммит
5829b59e80
10 изменённых файлов: 312 добавлений и 161 удалений
4
Makefile
4
Makefile
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
# runs all necessary tests
|
# runs all necessary tests
|
||||||
test:
|
test:
|
||||||
@sh -c 'if [ ! -z "$(go fmt ./...)" ]; then exit 1; fi'
|
@sh -c 'if [ ! -z "$(go fmt ./...)" ]; then exit 1; else echo "go fmt OK"; fi'
|
||||||
golint ./...
|
@sh -c 'if [ ! -z "$(golint ./...)" ]; then exit 1; else echo "golint OK"; fi'
|
||||||
go vet ./...
|
go vet ./...
|
||||||
go test ./...
|
go test ./...
|
||||||
go run cmd/godog/main.go -f progress
|
go run cmd/godog/main.go -f progress
|
||||||
|
|
75
features/background.feature
Обычный файл
75
features/background.feature
Обычный файл
|
@ -0,0 +1,75 @@
|
||||||
|
Feature: run background
|
||||||
|
In order to test application behavior
|
||||||
|
As a test suite
|
||||||
|
I need to be able to run background correctly
|
||||||
|
|
||||||
|
Scenario: should run background steps
|
||||||
|
Given a feature "normal.feature" file:
|
||||||
|
"""
|
||||||
|
Feature: with background
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given a feature path "features/load.feature:6"
|
||||||
|
|
||||||
|
Scenario: parse a scenario
|
||||||
|
When I parse features
|
||||||
|
Then I should have 1 scenario registered
|
||||||
|
"""
|
||||||
|
When I run feature suite
|
||||||
|
Then the suite should have passed
|
||||||
|
And the following steps should be passed:
|
||||||
|
"""
|
||||||
|
a feature path "features/load.feature:6"
|
||||||
|
I parse features
|
||||||
|
I should have 1 scenario registered
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: should skip all consequent steps on failure
|
||||||
|
Given a feature "normal.feature" file:
|
||||||
|
"""
|
||||||
|
Feature: with background
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given a failing step
|
||||||
|
And a feature path "features/load.feature:6"
|
||||||
|
|
||||||
|
Scenario: parse a scenario
|
||||||
|
When I parse features
|
||||||
|
Then I should have 1 scenario registered
|
||||||
|
"""
|
||||||
|
When I run feature suite
|
||||||
|
Then the suite should have failed
|
||||||
|
And the following steps should be failed:
|
||||||
|
"""
|
||||||
|
a failing step
|
||||||
|
"""
|
||||||
|
And the following steps should be skipped:
|
||||||
|
"""
|
||||||
|
a feature path "features/load.feature:6"
|
||||||
|
I parse features
|
||||||
|
I should have 1 scenario registered
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: should continue undefined steps
|
||||||
|
Given a feature "normal.feature" file:
|
||||||
|
"""
|
||||||
|
Feature: with background
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given an undefined step
|
||||||
|
|
||||||
|
Scenario: parse a scenario
|
||||||
|
When I do undefined action
|
||||||
|
Then I should have 1 scenario registered
|
||||||
|
"""
|
||||||
|
When I run feature suite
|
||||||
|
Then the suite should have passed
|
||||||
|
And the following steps should be undefined:
|
||||||
|
"""
|
||||||
|
an undefined step
|
||||||
|
I do undefined action
|
||||||
|
"""
|
||||||
|
And the following steps should be skipped:
|
||||||
|
"""
|
||||||
|
I should have 1 scenario registered
|
||||||
|
"""
|
|
@ -8,10 +8,12 @@ Savybė: užkrauti savybes
|
||||||
Scenarijus: savybių užkrovimas iš aplanko
|
Scenarijus: savybių užkrovimas iš aplanko
|
||||||
Duota savybių aplankas "features"
|
Duota savybių aplankas "features"
|
||||||
Kai aš išskaitau savybes
|
Kai aš išskaitau savybes
|
||||||
Tada aš turėčiau turėti 4 savybių failus:
|
Tada aš turėčiau turėti 6 savybių failus:
|
||||||
"""
|
"""
|
||||||
|
features/background.feature
|
||||||
features/events.feature
|
features/events.feature
|
||||||
features/lang.feature
|
features/lang.feature
|
||||||
features/load.feature
|
features/load.feature
|
||||||
|
features/outline.feature
|
||||||
features/run.feature
|
features/run.feature
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -6,11 +6,13 @@ Feature: load features
|
||||||
Scenario: load features within path
|
Scenario: load features within path
|
||||||
Given a feature path "features"
|
Given a feature path "features"
|
||||||
When I parse features
|
When I parse features
|
||||||
Then I should have 4 feature files:
|
Then I should have 6 feature files:
|
||||||
"""
|
"""
|
||||||
|
features/background.feature
|
||||||
features/events.feature
|
features/events.feature
|
||||||
features/lang.feature
|
features/lang.feature
|
||||||
features/load.feature
|
features/load.feature
|
||||||
|
features/outline.feature
|
||||||
features/run.feature
|
features/run.feature
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
100
features/outline.feature
Обычный файл
100
features/outline.feature
Обычный файл
|
@ -0,0 +1,100 @@
|
||||||
|
Feature: run outline
|
||||||
|
In order to test application behavior
|
||||||
|
As a test suite
|
||||||
|
I need to be able to run outline scenarios
|
||||||
|
|
||||||
|
Scenario: should run a normal outline
|
||||||
|
Given a feature "normal.feature" file:
|
||||||
|
"""
|
||||||
|
Feature: outline
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given passing step
|
||||||
|
|
||||||
|
Scenario Outline: parse a scenario
|
||||||
|
Given a feature path "<path>"
|
||||||
|
When I parse features
|
||||||
|
Then I should have <num> scenario registered
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
| path | num |
|
||||||
|
| features/load.feature:6 | 1 |
|
||||||
|
| features/load.feature:3 | 0 |
|
||||||
|
"""
|
||||||
|
When I run feature suite
|
||||||
|
Then the suite should have passed
|
||||||
|
And the following steps should be passed:
|
||||||
|
"""
|
||||||
|
a passing step
|
||||||
|
I parse features
|
||||||
|
a feature path "features/load.feature:6"
|
||||||
|
a feature path "features/load.feature:3"
|
||||||
|
I should have 1 scenario registered
|
||||||
|
I should have 0 scenario registered
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: should continue through examples on failure
|
||||||
|
Given a feature "normal.feature" file:
|
||||||
|
"""
|
||||||
|
Feature: outline
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given passing step
|
||||||
|
|
||||||
|
Scenario Outline: parse a scenario
|
||||||
|
Given a feature path "<path>"
|
||||||
|
When I parse features
|
||||||
|
Then I should have <num> scenario registered
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
| path | num |
|
||||||
|
| features/load.feature:6 | 5 |
|
||||||
|
| features/load.feature:3 | 0 |
|
||||||
|
"""
|
||||||
|
When I run feature suite
|
||||||
|
Then the suite should have failed
|
||||||
|
And the following steps should be passed:
|
||||||
|
"""
|
||||||
|
a passing step
|
||||||
|
I parse features
|
||||||
|
a feature path "features/load.feature:6"
|
||||||
|
a feature path "features/load.feature:3"
|
||||||
|
I should have 0 scenario registered
|
||||||
|
"""
|
||||||
|
And the following steps should be failed:
|
||||||
|
"""
|
||||||
|
I should have 5 scenario registered
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: should skip examples on background failure
|
||||||
|
Given a feature "normal.feature" file:
|
||||||
|
"""
|
||||||
|
Feature: outline
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given a failing step
|
||||||
|
|
||||||
|
Scenario Outline: parse a scenario
|
||||||
|
Given a feature path "<path>"
|
||||||
|
When I parse features
|
||||||
|
Then I should have <num> scenario registered
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
| path | num |
|
||||||
|
| features/load.feature:6 | 1 |
|
||||||
|
| features/load.feature:3 | 0 |
|
||||||
|
"""
|
||||||
|
When I run feature suite
|
||||||
|
Then the suite should have failed
|
||||||
|
And the following steps should be skipped:
|
||||||
|
"""
|
||||||
|
I parse features
|
||||||
|
a feature path "features/load.feature:6"
|
||||||
|
a feature path "features/load.feature:3"
|
||||||
|
I should have 0 scenario registered
|
||||||
|
I should have 1 scenario registered
|
||||||
|
"""
|
||||||
|
And the following steps should be failed:
|
||||||
|
"""
|
||||||
|
a failing step
|
||||||
|
"""
|
113
fmt.go
113
fmt.go
|
@ -77,9 +77,31 @@ type Formatter interface {
|
||||||
Summary()
|
Summary()
|
||||||
}
|
}
|
||||||
|
|
||||||
// failed represents a failed step data structure
|
type stepType int
|
||||||
// with all necessary references
|
|
||||||
type failed struct {
|
const (
|
||||||
|
passed stepType = iota
|
||||||
|
failed
|
||||||
|
skipped
|
||||||
|
undefined
|
||||||
|
pending
|
||||||
|
)
|
||||||
|
|
||||||
|
func (st stepType) clr() color {
|
||||||
|
switch st {
|
||||||
|
case passed:
|
||||||
|
return green
|
||||||
|
case failed:
|
||||||
|
return red
|
||||||
|
case skipped:
|
||||||
|
return cyan
|
||||||
|
default:
|
||||||
|
return yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type stepResult struct {
|
||||||
|
typ stepType
|
||||||
feature *feature
|
feature *feature
|
||||||
owner interface{}
|
owner interface{}
|
||||||
step *gherkin.Step
|
step *gherkin.Step
|
||||||
|
@ -87,55 +109,21 @@ type failed struct {
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f failed) line() string {
|
func (f stepResult) line() string {
|
||||||
return fmt.Sprintf("%s:%d", f.feature.Path, f.step.Location.Line)
|
return fmt.Sprintf("%s:%d", f.feature.Path, f.step.Location.Line)
|
||||||
}
|
}
|
||||||
|
|
||||||
// passed represents a successful step data structure
|
|
||||||
// with all necessary references
|
|
||||||
type passed struct {
|
|
||||||
feature *feature
|
|
||||||
owner interface{}
|
|
||||||
step *gherkin.Step
|
|
||||||
def *StepDef
|
|
||||||
}
|
|
||||||
|
|
||||||
// skipped represents a skipped step data structure
|
|
||||||
// with all necessary references
|
|
||||||
type skipped struct {
|
|
||||||
feature *feature
|
|
||||||
owner interface{}
|
|
||||||
step *gherkin.Step
|
|
||||||
}
|
|
||||||
|
|
||||||
// undefined represents an undefined step data structure
|
|
||||||
// with all necessary references
|
|
||||||
type undefined struct {
|
|
||||||
feature *feature
|
|
||||||
owner interface{}
|
|
||||||
step *gherkin.Step
|
|
||||||
}
|
|
||||||
|
|
||||||
// pending represents a pending step data structure
|
|
||||||
// with all necessary references
|
|
||||||
type pending struct {
|
|
||||||
feature *feature
|
|
||||||
owner interface{}
|
|
||||||
step *gherkin.Step
|
|
||||||
def *StepDef
|
|
||||||
}
|
|
||||||
|
|
||||||
type basefmt struct {
|
type basefmt struct {
|
||||||
owner interface{}
|
owner interface{}
|
||||||
indent int
|
indent int
|
||||||
|
|
||||||
started time.Time
|
started time.Time
|
||||||
features []*feature
|
features []*feature
|
||||||
failed []*failed
|
failed []*stepResult
|
||||||
passed []*passed
|
passed []*stepResult
|
||||||
skipped []*skipped
|
skipped []*stepResult
|
||||||
undefined []*undefined
|
undefined []*stepResult
|
||||||
pending []*pending
|
pending []*stepResult
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) Node(n interface{}) {
|
func (f *basefmt) Node(n interface{}) {
|
||||||
|
@ -154,27 +142,56 @@ func (f *basefmt) Feature(ft *gherkin.Feature, p string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) Passed(step *gherkin.Step, match *StepDef) {
|
func (f *basefmt) Passed(step *gherkin.Step, match *StepDef) {
|
||||||
s := &passed{owner: f.owner, feature: f.features[len(f.features)-1], step: step, def: match}
|
s := &stepResult{
|
||||||
|
owner: f.owner,
|
||||||
|
feature: f.features[len(f.features)-1],
|
||||||
|
step: step,
|
||||||
|
def: match,
|
||||||
|
typ: passed,
|
||||||
|
}
|
||||||
f.passed = append(f.passed, s)
|
f.passed = append(f.passed, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) Skipped(step *gherkin.Step) {
|
func (f *basefmt) Skipped(step *gherkin.Step) {
|
||||||
s := &skipped{owner: f.owner, feature: f.features[len(f.features)-1], step: step}
|
s := &stepResult{
|
||||||
|
owner: f.owner,
|
||||||
|
feature: f.features[len(f.features)-1],
|
||||||
|
step: step,
|
||||||
|
typ: skipped,
|
||||||
|
}
|
||||||
f.skipped = append(f.skipped, s)
|
f.skipped = append(f.skipped, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) Undefined(step *gherkin.Step) {
|
func (f *basefmt) Undefined(step *gherkin.Step) {
|
||||||
s := &undefined{owner: f.owner, feature: f.features[len(f.features)-1], step: step}
|
s := &stepResult{
|
||||||
|
owner: f.owner,
|
||||||
|
feature: f.features[len(f.features)-1],
|
||||||
|
step: step,
|
||||||
|
typ: undefined,
|
||||||
|
}
|
||||||
f.undefined = append(f.undefined, s)
|
f.undefined = append(f.undefined, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) Failed(step *gherkin.Step, match *StepDef, err error) {
|
func (f *basefmt) Failed(step *gherkin.Step, match *StepDef, err error) {
|
||||||
s := &failed{owner: f.owner, feature: f.features[len(f.features)-1], step: step, def: match, err: err}
|
s := &stepResult{
|
||||||
|
owner: f.owner,
|
||||||
|
feature: f.features[len(f.features)-1],
|
||||||
|
step: step,
|
||||||
|
def: match,
|
||||||
|
err: err,
|
||||||
|
typ: failed,
|
||||||
|
}
|
||||||
f.failed = append(f.failed, s)
|
f.failed = append(f.failed, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) Pending(step *gherkin.Step, match *StepDef) {
|
func (f *basefmt) Pending(step *gherkin.Step, match *StepDef) {
|
||||||
s := &pending{owner: f.owner, feature: f.features[len(f.features)-1], step: step, def: match}
|
s := &stepResult{
|
||||||
|
owner: f.owner,
|
||||||
|
feature: f.features[len(f.features)-1],
|
||||||
|
step: step,
|
||||||
|
def: match,
|
||||||
|
typ: pending,
|
||||||
|
}
|
||||||
f.pending = append(f.pending, s)
|
f.pending = append(f.pending, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ type pretty struct {
|
||||||
backgroundSteps int
|
backgroundSteps int
|
||||||
|
|
||||||
// outline
|
// outline
|
||||||
outlineSteps []interface{}
|
outlineSteps []*stepResult
|
||||||
outlineNumExample int
|
outlineNumExample int
|
||||||
outlineNumExamples int
|
outlineNumExamples int
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ func (f *pretty) Node(node interface{}) {
|
||||||
// Summary sumarize the feature formatter output
|
// Summary sumarize the feature formatter output
|
||||||
func (f *pretty) Summary() {
|
func (f *pretty) Summary() {
|
||||||
// failed steps on background are not scenarios
|
// failed steps on background are not scenarios
|
||||||
var failedScenarios []*failed
|
var failedScenarios []*stepResult
|
||||||
for _, fail := range f.failed {
|
for _, fail := range f.failed {
|
||||||
switch fail.owner.(type) {
|
switch fail.owner.(type) {
|
||||||
case *gherkin.Scenario:
|
case *gherkin.Scenario:
|
||||||
|
@ -129,31 +129,29 @@ func (f *pretty) Summary() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) printOutlineExample(outline *gherkin.ScenarioOutline) {
|
func (f *pretty) printOutlineExample(outline *gherkin.ScenarioOutline) {
|
||||||
var failed error
|
var msg string
|
||||||
clr := green
|
clr := green
|
||||||
|
|
||||||
example := outline.Examples[f.outlineNumExample]
|
example := outline.Examples[f.outlineNumExample]
|
||||||
firstExample := f.outlineNumExamples == len(example.TableBody)
|
firstExample := f.outlineNumExamples == len(example.TableBody)
|
||||||
printSteps := firstExample && f.outlineNumExample == 0
|
printSteps := firstExample && f.outlineNumExample == 0
|
||||||
|
|
||||||
// var replace make(map[])
|
for i, res := range f.outlineSteps {
|
||||||
for i, act := range f.outlineSteps {
|
|
||||||
_, _, def, c, err := f.stepDetails(act)
|
|
||||||
// determine example row status
|
// determine example row status
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case res.typ == failed:
|
||||||
failed = err
|
msg = res.err.Error()
|
||||||
clr = red
|
clr = res.typ.clr()
|
||||||
case c == yellow:
|
case res.typ == undefined || res.typ == pending:
|
||||||
clr = yellow
|
clr = res.typ.clr()
|
||||||
case c == cyan && clr == green:
|
case res.typ == skipped && clr == green:
|
||||||
clr = cyan
|
clr = cyan
|
||||||
}
|
}
|
||||||
if printSteps {
|
if printSteps {
|
||||||
// in first example, we need to print steps
|
// in first example, we need to print steps
|
||||||
var text string
|
var text string
|
||||||
ostep := outline.Steps[i]
|
ostep := outline.Steps[i]
|
||||||
if def != nil {
|
if res.def != nil {
|
||||||
if m := outlinePlaceholderRegexp.FindAllStringIndex(ostep.Text, -1); len(m) > 0 {
|
if m := outlinePlaceholderRegexp.FindAllStringIndex(ostep.Text, -1); len(m) > 0 {
|
||||||
var pos int
|
var pos int
|
||||||
for i := 0; i < len(m); i++ {
|
for i := 0; i < len(m); i++ {
|
||||||
|
@ -166,7 +164,7 @@ func (f *pretty) printOutlineExample(outline *gherkin.ScenarioOutline) {
|
||||||
} else {
|
} else {
|
||||||
text = cl(ostep.Text, cyan)
|
text = cl(ostep.Text, cyan)
|
||||||
}
|
}
|
||||||
text += s(f.commentPos-f.length(ostep)+1) + cl(fmt.Sprintf("# %s", def.funcName()), black)
|
text += s(f.commentPos-f.length(ostep)+1) + cl(fmt.Sprintf("# %s", res.def.funcName()), black)
|
||||||
} else {
|
} else {
|
||||||
text = cl(ostep.Text, cyan)
|
text = cl(ostep.Text, cyan)
|
||||||
}
|
}
|
||||||
|
@ -196,8 +194,8 @@ func (f *pretty) printOutlineExample(outline *gherkin.ScenarioOutline) {
|
||||||
fmt.Println(s(f.indent*3) + "| " + strings.Join(cells, " | ") + " |")
|
fmt.Println(s(f.indent*3) + "| " + strings.Join(cells, " | ") + " |")
|
||||||
|
|
||||||
// if there is an error
|
// if there is an error
|
||||||
if failed != nil {
|
if msg != "" {
|
||||||
fmt.Println(s(f.indent*3) + bcl(failed, red))
|
fmt.Println(s(f.indent*4) + bcl(msg, red))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,43 +239,9 @@ func (f *pretty) printStep(step *gherkin.Step, def *StepDef, c color) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) stepDetails(stepAction interface{}) (owner interface{}, step *gherkin.Step, def *StepDef, c color, err error) {
|
func (f *pretty) printStepKind(res *stepResult) {
|
||||||
switch typ := stepAction.(type) {
|
|
||||||
case *passed:
|
|
||||||
step = typ.step
|
|
||||||
def = typ.def
|
|
||||||
owner = typ.owner
|
|
||||||
c = green
|
|
||||||
case *failed:
|
|
||||||
step = typ.step
|
|
||||||
def = typ.def
|
|
||||||
owner = typ.owner
|
|
||||||
err = typ.err
|
|
||||||
c = red
|
|
||||||
case *skipped:
|
|
||||||
step = typ.step
|
|
||||||
owner = typ.owner
|
|
||||||
c = cyan
|
|
||||||
case *undefined:
|
|
||||||
step = typ.step
|
|
||||||
owner = typ.owner
|
|
||||||
c = yellow
|
|
||||||
case *pending:
|
|
||||||
step = typ.step
|
|
||||||
def = typ.def
|
|
||||||
owner = typ.owner
|
|
||||||
c = yellow
|
|
||||||
default:
|
|
||||||
fatal(fmt.Errorf("unexpected step type received: %T", typ))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *pretty) printStepKind(stepAction interface{}) {
|
|
||||||
owner, step, def, c, err := f.stepDetails(stepAction)
|
|
||||||
|
|
||||||
// do not print background more than once
|
// do not print background more than once
|
||||||
if _, ok := owner.(*gherkin.Background); ok {
|
if _, ok := res.owner.(*gherkin.Background); ok {
|
||||||
switch {
|
switch {
|
||||||
case f.backgroundSteps == 0:
|
case f.backgroundSteps == 0:
|
||||||
return
|
return
|
||||||
|
@ -286,22 +250,22 @@ func (f *pretty) printStepKind(stepAction interface{}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if outline, ok := owner.(*gherkin.ScenarioOutline); ok {
|
if outline, ok := res.owner.(*gherkin.ScenarioOutline); ok {
|
||||||
f.outlineSteps = append(f.outlineSteps, stepAction)
|
f.outlineSteps = append(f.outlineSteps, res)
|
||||||
if len(f.outlineSteps) == len(outline.Steps) {
|
if len(f.outlineSteps) == len(outline.Steps) {
|
||||||
// an outline example steps has went through
|
// an outline example steps has went through
|
||||||
f.printOutlineExample(outline)
|
f.printOutlineExample(outline)
|
||||||
f.outlineSteps = []interface{}{}
|
f.outlineSteps = []*stepResult{}
|
||||||
f.outlineNumExamples--
|
f.outlineNumExamples--
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
f.printStep(step, def, c)
|
f.printStep(res.step, res.def, res.typ.clr())
|
||||||
if err != nil {
|
if res.err != nil {
|
||||||
fmt.Println(s(f.indent*2) + bcl(err, red))
|
fmt.Println(s(f.indent*2) + bcl(res.err, red))
|
||||||
}
|
}
|
||||||
if _, ok := stepAction.(*pending); ok {
|
if res.typ == pending {
|
||||||
fmt.Println(s(f.indent*3) + cl("TODO: write pending definition", yellow))
|
fmt.Println(s(f.indent*3) + cl("TODO: write pending definition", yellow))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,17 +45,17 @@ func (f *progress) Summary() {
|
||||||
f.basefmt.Summary()
|
f.basefmt.Summary()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *progress) step(step interface{}) {
|
func (f *progress) step(res *stepResult) {
|
||||||
switch step.(type) {
|
switch res.typ {
|
||||||
case *passed:
|
case passed:
|
||||||
fmt.Print(cl(".", green))
|
fmt.Print(cl(".", green))
|
||||||
case *skipped:
|
case skipped:
|
||||||
fmt.Print(cl("-", cyan))
|
fmt.Print(cl("-", cyan))
|
||||||
case *failed:
|
case failed:
|
||||||
fmt.Print(cl("F", red))
|
fmt.Print(cl("F", red))
|
||||||
case *undefined:
|
case undefined:
|
||||||
fmt.Print(cl("U", yellow))
|
fmt.Print(cl("U", yellow))
|
||||||
case *pending:
|
case pending:
|
||||||
fmt.Print(cl("P", yellow))
|
fmt.Print(cl("P", yellow))
|
||||||
}
|
}
|
||||||
f.steps++
|
f.steps++
|
||||||
|
|
57
suite.go
57
suite.go
|
@ -298,6 +298,11 @@ func (s *suite) runStep(step *gherkin.Step, prevStepErr error) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// run before step handlers
|
||||||
|
for _, f := range s.beforeStepHandlers {
|
||||||
|
f(step)
|
||||||
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if e := recover(); e != nil {
|
if e := recover(); e != nil {
|
||||||
err, ok := e.(error)
|
err, ok := e.(error)
|
||||||
|
@ -317,16 +322,17 @@ func (s *suite) runStep(step *gherkin.Step, prevStepErr error) (err error) {
|
||||||
default:
|
default:
|
||||||
s.fmt.Failed(step, match, err)
|
s.fmt.Failed(step, match, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// run after step handlers
|
||||||
|
for _, f := range s.afterStepHandlers {
|
||||||
|
f(step, err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *suite) runSteps(steps []*gherkin.Step) (err error) {
|
func (s *suite) runSteps(steps []*gherkin.Step, prevErr error) (err error) {
|
||||||
|
err = prevErr
|
||||||
for _, step := range steps {
|
for _, step := range steps {
|
||||||
// run before step handlers
|
|
||||||
for _, f := range s.beforeStepHandlers {
|
|
||||||
f(step)
|
|
||||||
}
|
|
||||||
|
|
||||||
stepErr := s.runStep(step, err)
|
stepErr := s.runStep(step, err)
|
||||||
switch stepErr {
|
switch stepErr {
|
||||||
case ErrUndefined:
|
case ErrUndefined:
|
||||||
|
@ -337,11 +343,6 @@ func (s *suite) runSteps(steps []*gherkin.Step) (err error) {
|
||||||
default:
|
default:
|
||||||
err = stepErr
|
err = stepErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// run after step handlers
|
|
||||||
for _, f := range s.afterStepHandlers {
|
|
||||||
f(step, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -352,7 +353,7 @@ func (s *suite) skipSteps(steps []*gherkin.Step) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *suite) runOutline(outline *gherkin.ScenarioOutline, b *gherkin.Background) (err error) {
|
func (s *suite) runOutline(outline *gherkin.ScenarioOutline, b *gherkin.Background) (failErr error) {
|
||||||
s.fmt.Node(outline)
|
s.fmt.Node(outline)
|
||||||
|
|
||||||
for _, example := range outline.Examples {
|
for _, example := range outline.Examples {
|
||||||
|
@ -381,24 +382,21 @@ func (s *suite) runOutline(outline *gherkin.ScenarioOutline, b *gherkin.Backgrou
|
||||||
steps = append(steps, step)
|
steps = append(steps, step)
|
||||||
}
|
}
|
||||||
// run background
|
// run background
|
||||||
|
var err error
|
||||||
if b != nil {
|
if b != nil {
|
||||||
err = s.runSteps(b.Steps)
|
err = s.runSteps(b.Steps, err)
|
||||||
}
|
|
||||||
switch err {
|
|
||||||
case ErrUndefined:
|
|
||||||
s.skipSteps(steps)
|
|
||||||
case nil:
|
|
||||||
err = s.runSteps(steps)
|
|
||||||
default:
|
|
||||||
s.skipSteps(steps)
|
|
||||||
}
|
}
|
||||||
|
err = s.runSteps(steps, err)
|
||||||
|
|
||||||
for _, f := range s.afterScenarioHandlers {
|
for _, f := range s.afterScenarioHandlers {
|
||||||
f(outline, err)
|
f(outline, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.stopOnFailure && err != ErrUndefined {
|
if err != nil && err != ErrUndefined && err != ErrPending {
|
||||||
return
|
failErr = err
|
||||||
|
if s.stopOnFailure {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -435,21 +433,12 @@ func (s *suite) runScenario(scenario *gherkin.Scenario, b *gherkin.Background) (
|
||||||
|
|
||||||
// background
|
// background
|
||||||
if b != nil {
|
if b != nil {
|
||||||
err = s.runSteps(b.Steps)
|
err = s.runSteps(b.Steps, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// scenario
|
// scenario
|
||||||
s.fmt.Node(scenario)
|
s.fmt.Node(scenario)
|
||||||
switch err {
|
err = s.runSteps(scenario.Steps, err)
|
||||||
case ErrPending:
|
|
||||||
s.skipSteps(scenario.Steps)
|
|
||||||
case ErrUndefined:
|
|
||||||
s.skipSteps(scenario.Steps)
|
|
||||||
case nil:
|
|
||||||
err = s.runSteps(scenario.Steps)
|
|
||||||
default:
|
|
||||||
s.skipSteps(scenario.Steps)
|
|
||||||
}
|
|
||||||
|
|
||||||
// run after scenario handlers
|
// run after scenario handlers
|
||||||
for _, f := range s.afterScenarioHandlers {
|
for _, f := range s.afterScenarioHandlers {
|
||||||
|
|
|
@ -38,6 +38,9 @@ func SuiteContext(s Suite) {
|
||||||
s.Step(`^pending step$`, func() error {
|
s.Step(`^pending step$`, func() error {
|
||||||
return ErrPending
|
return ErrPending
|
||||||
})
|
})
|
||||||
|
s.Step(`^passing step$`, func() error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type firedEvent struct {
|
type firedEvent struct {
|
||||||
|
@ -63,8 +66,7 @@ func (s *suiteContext) ResetBeforeEachScenario(interface{}) {
|
||||||
|
|
||||||
func (s *suiteContext) followingStepsShouldHave(status string, steps *gherkin.DocString) error {
|
func (s *suiteContext) followingStepsShouldHave(status string, steps *gherkin.DocString) error {
|
||||||
var expected = strings.Split(steps.Content, "\n")
|
var expected = strings.Split(steps.Content, "\n")
|
||||||
var actual, unmatched []string
|
var actual, unmatched, matched []string
|
||||||
var matched []int
|
|
||||||
|
|
||||||
switch status {
|
switch status {
|
||||||
case "passed":
|
case "passed":
|
||||||
|
@ -96,23 +98,23 @@ func (s *suiteContext) followingStepsShouldHave(status string, steps *gherkin.Do
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, a := range actual {
|
for _, a := range actual {
|
||||||
for i, e := range expected {
|
for _, e := range expected {
|
||||||
if a == e {
|
if a == e {
|
||||||
matched = append(matched, i)
|
matched = append(matched, e)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(matched) == len(expected) {
|
if len(matched) >= len(expected) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
for _, s := range expected {
|
||||||
for i, s := range expected {
|
|
||||||
var found bool
|
var found bool
|
||||||
for _, m := range matched {
|
for _, m := range matched {
|
||||||
if i == m {
|
if s == m {
|
||||||
found = true
|
found = true
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
|
@ -120,7 +122,7 @@ func (s *suiteContext) followingStepsShouldHave(status string, steps *gherkin.Do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("the steps: %s - is not %s", strings.Join(unmatched, ", "), status)
|
return fmt.Errorf("the steps: %s - are not %s", strings.Join(unmatched, ", "), status)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *suiteContext) iAmListeningToSuiteEvents() error {
|
func (s *suiteContext) iAmListeningToSuiteEvents() error {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче