Merge pull request #79 from DATA-DOG/multistep
implements convenient multistep definition
Этот коммит содержится в:
коммит
38e3d1fb6d
20 изменённых файлов: 617 добавлений и 115 удалений
|
@ -1,5 +1,11 @@
|
||||||
# Change LOG
|
# Change LOG
|
||||||
|
|
||||||
|
**2017-04-29**
|
||||||
|
- added support for nested steps. From now on, it is possible to return
|
||||||
|
**godog.Steps** instead of an **error** in the step definition func.
|
||||||
|
This change introduced few minor changes in **Formatter** interface. Be
|
||||||
|
sure to adapt the changes if you have custom formatters.
|
||||||
|
|
||||||
**2017-04-27**
|
**2017-04-27**
|
||||||
- added an option to randomize scenario execution order, so we could
|
- added an option to randomize scenario execution order, so we could
|
||||||
ensure that scenarios do not depend on global state.
|
ensure that scenarios do not depend on global state.
|
||||||
|
|
|
@ -248,8 +248,11 @@ See implementation examples:
|
||||||
|
|
||||||
### FAQ
|
### FAQ
|
||||||
|
|
||||||
**Q:** Where can I configure common options globally?
|
#### Configure common options for godog CLI
|
||||||
**A:** You can't. Alias your common or project based commands: `alias godog-wip="godog --format=progress --tags=@wip"`
|
|
||||||
|
There are no global options or configuration files. Alias your common or
|
||||||
|
project based commands: `alias godog-wip="godog --format=progress
|
||||||
|
--tags=@wip"`
|
||||||
|
|
||||||
### Contributions
|
### Contributions
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,6 @@ Feature: get version
|
||||||
And the response should match json:
|
And the response should match json:
|
||||||
"""
|
"""
|
||||||
{
|
{
|
||||||
"version": "v0.6.3"
|
"version": "v0.7.0"
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -14,7 +14,7 @@ Feature: event stream formatter
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Scenario: should process simple scenario
|
Scenario: should process simple scenario
|
||||||
Given a feature path "features/load.feature:22"
|
Given a feature path "features/load.feature:23"
|
||||||
When I run feature suite with formatter "events"
|
When I run feature suite with formatter "events"
|
||||||
Then the following events should be fired:
|
Then the following events should be fired:
|
||||||
"""
|
"""
|
||||||
|
@ -35,7 +35,7 @@ Feature: event stream formatter
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Scenario: should process outline scenario
|
Scenario: should process outline scenario
|
||||||
Given a feature path "features/load.feature:30"
|
Given a feature path "features/load.feature:31"
|
||||||
When I run feature suite with formatter "events"
|
When I run feature suite with formatter "events"
|
||||||
Then the following events should be fired:
|
Then the following events should be fired:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -8,7 +8,7 @@ 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 9 savybių failus:
|
Tada aš turėčiau turėti 10 savybių failus:
|
||||||
"""
|
"""
|
||||||
features/background.feature
|
features/background.feature
|
||||||
features/events.feature
|
features/events.feature
|
||||||
|
@ -16,6 +16,7 @@ Savybė: užkrauti savybes
|
||||||
features/formatter/events.feature
|
features/formatter/events.feature
|
||||||
features/lang.feature
|
features/lang.feature
|
||||||
features/load.feature
|
features/load.feature
|
||||||
|
features/multistep.feature
|
||||||
features/outline.feature
|
features/outline.feature
|
||||||
features/run.feature
|
features/run.feature
|
||||||
features/snippets.feature
|
features/snippets.feature
|
||||||
|
|
|
@ -6,7 +6,7 @@ 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 9 feature files:
|
Then I should have 10 feature files:
|
||||||
"""
|
"""
|
||||||
features/background.feature
|
features/background.feature
|
||||||
features/events.feature
|
features/events.feature
|
||||||
|
@ -14,6 +14,7 @@ Feature: load features
|
||||||
features/formatter/events.feature
|
features/formatter/events.feature
|
||||||
features/lang.feature
|
features/lang.feature
|
||||||
features/load.feature
|
features/load.feature
|
||||||
|
features/multistep.feature
|
||||||
features/outline.feature
|
features/outline.feature
|
||||||
features/run.feature
|
features/run.feature
|
||||||
features/snippets.feature
|
features/snippets.feature
|
||||||
|
|
140
features/multistep.feature
Обычный файл
140
features/multistep.feature
Обычный файл
|
@ -0,0 +1,140 @@
|
||||||
|
Feature: run features with nested steps
|
||||||
|
In order to test multisteps
|
||||||
|
As a test suite
|
||||||
|
I need to be able to execute multisteps
|
||||||
|
|
||||||
|
Scenario: should run passing multistep successfully
|
||||||
|
Given a feature "normal.feature" file:
|
||||||
|
"""
|
||||||
|
Feature: normal feature
|
||||||
|
|
||||||
|
Scenario: run passing multistep
|
||||||
|
Given passing step
|
||||||
|
Then passing multistep
|
||||||
|
"""
|
||||||
|
When I run feature suite
|
||||||
|
Then the suite should have passed
|
||||||
|
And the following steps should be passed:
|
||||||
|
"""
|
||||||
|
passing step
|
||||||
|
passing multistep
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: should fail multistep
|
||||||
|
Given a feature "failed.feature" file:
|
||||||
|
"""
|
||||||
|
Feature: failed feature
|
||||||
|
|
||||||
|
Scenario: run failing multistep
|
||||||
|
Given passing step
|
||||||
|
When failing multistep
|
||||||
|
Then I should have 1 scenario registered
|
||||||
|
"""
|
||||||
|
When I run feature suite
|
||||||
|
Then the suite should have failed
|
||||||
|
And the following step should be failed:
|
||||||
|
"""
|
||||||
|
failing multistep
|
||||||
|
"""
|
||||||
|
And the following steps should be skipped:
|
||||||
|
"""
|
||||||
|
I should have 1 scenario registered
|
||||||
|
"""
|
||||||
|
And the following steps should be passed:
|
||||||
|
"""
|
||||||
|
passing step
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: should fail nested multistep
|
||||||
|
Given a feature "failed.feature" file:
|
||||||
|
"""
|
||||||
|
Feature: failed feature
|
||||||
|
|
||||||
|
Scenario: run failing nested multistep
|
||||||
|
Given failing nested multistep
|
||||||
|
When passing step
|
||||||
|
"""
|
||||||
|
When I run feature suite
|
||||||
|
Then the suite should have failed
|
||||||
|
And the following step should be failed:
|
||||||
|
"""
|
||||||
|
failing nested multistep
|
||||||
|
"""
|
||||||
|
And the following steps should be skipped:
|
||||||
|
"""
|
||||||
|
passing step
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: should skip steps after undefined multistep
|
||||||
|
Given a feature "undefined.feature" file:
|
||||||
|
"""
|
||||||
|
Feature: run undefined multistep
|
||||||
|
|
||||||
|
Scenario: run undefined multistep
|
||||||
|
Given passing step
|
||||||
|
When undefined multistep
|
||||||
|
Then passing multistep
|
||||||
|
"""
|
||||||
|
When I run feature suite
|
||||||
|
Then the suite should have passed
|
||||||
|
And the following step should be passed:
|
||||||
|
"""
|
||||||
|
passing step
|
||||||
|
"""
|
||||||
|
And the following step should be undefined:
|
||||||
|
"""
|
||||||
|
undefined multistep
|
||||||
|
"""
|
||||||
|
And the following step should be skipped:
|
||||||
|
"""
|
||||||
|
passing multistep
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: should match undefined steps in a row
|
||||||
|
Given a feature "undefined.feature" file:
|
||||||
|
"""
|
||||||
|
Feature: undefined feature
|
||||||
|
|
||||||
|
Scenario: parse a scenario
|
||||||
|
Given undefined step
|
||||||
|
When undefined multistep
|
||||||
|
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:
|
||||||
|
"""
|
||||||
|
undefined step
|
||||||
|
undefined multistep
|
||||||
|
"""
|
||||||
|
And the following step should be skipped:
|
||||||
|
"""
|
||||||
|
I should have 1 scenario registered
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: should mark undefined steps after pending
|
||||||
|
Given a feature "pending.feature" file:
|
||||||
|
"""
|
||||||
|
Feature: pending feature
|
||||||
|
|
||||||
|
Scenario: parse a scenario
|
||||||
|
Given pending step
|
||||||
|
When undefined step
|
||||||
|
Then undefined multistep
|
||||||
|
And I should have 1 scenario registered
|
||||||
|
"""
|
||||||
|
When I run feature suite
|
||||||
|
Then the suite should have passed
|
||||||
|
And the following steps should be undefined:
|
||||||
|
"""
|
||||||
|
undefined step
|
||||||
|
undefined multistep
|
||||||
|
"""
|
||||||
|
And the following step should be pending:
|
||||||
|
"""
|
||||||
|
pending step
|
||||||
|
"""
|
||||||
|
And the following step should be skipped:
|
||||||
|
"""
|
||||||
|
I should have 1 scenario registered
|
||||||
|
"""
|
24
fmt.go
24
fmt.go
|
@ -105,8 +105,8 @@ type Formatter interface {
|
||||||
Defined(*gherkin.Step, *StepDef)
|
Defined(*gherkin.Step, *StepDef)
|
||||||
Failed(*gherkin.Step, *StepDef, error)
|
Failed(*gherkin.Step, *StepDef, error)
|
||||||
Passed(*gherkin.Step, *StepDef)
|
Passed(*gherkin.Step, *StepDef)
|
||||||
Skipped(*gherkin.Step)
|
Skipped(*gherkin.Step, *StepDef)
|
||||||
Undefined(*gherkin.Step)
|
Undefined(*gherkin.Step, *StepDef)
|
||||||
Pending(*gherkin.Step, *StepDef)
|
Pending(*gherkin.Step, *StepDef)
|
||||||
Summary()
|
Summary()
|
||||||
}
|
}
|
||||||
|
@ -210,21 +210,23 @@ func (f *basefmt) Passed(step *gherkin.Step, match *StepDef) {
|
||||||
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, match *StepDef) {
|
||||||
s := &stepResult{
|
s := &stepResult{
|
||||||
owner: f.owner,
|
owner: f.owner,
|
||||||
feature: f.features[len(f.features)-1],
|
feature: f.features[len(f.features)-1],
|
||||||
step: step,
|
step: step,
|
||||||
|
def: match,
|
||||||
typ: skipped,
|
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, match *StepDef) {
|
||||||
s := &stepResult{
|
s := &stepResult{
|
||||||
owner: f.owner,
|
owner: f.owner,
|
||||||
feature: f.features[len(f.features)-1],
|
feature: f.features[len(f.features)-1],
|
||||||
step: step,
|
step: step,
|
||||||
|
def: match,
|
||||||
typ: undefined,
|
typ: undefined,
|
||||||
}
|
}
|
||||||
f.undefined = append(f.undefined, s)
|
f.undefined = append(f.undefined, s)
|
||||||
|
@ -394,12 +396,19 @@ func (f *basefmt) snippets() string {
|
||||||
var snips []*undefinedSnippet
|
var snips []*undefinedSnippet
|
||||||
// build snippets
|
// build snippets
|
||||||
for _, u := range f.undefined {
|
for _, u := range f.undefined {
|
||||||
expr := snippetExprCleanup.ReplaceAllString(u.step.Text, "\\$1")
|
steps := []string{u.step.Text}
|
||||||
|
arg := u.step.Argument
|
||||||
|
if u.def != nil {
|
||||||
|
steps = u.def.undefined
|
||||||
|
arg = nil
|
||||||
|
}
|
||||||
|
for _, step := range steps {
|
||||||
|
expr := snippetExprCleanup.ReplaceAllString(step, "\\$1")
|
||||||
expr = snippetNumbers.ReplaceAllString(expr, "(\\d+)")
|
expr = snippetNumbers.ReplaceAllString(expr, "(\\d+)")
|
||||||
expr = snippetExprQuoted.ReplaceAllString(expr, "$1\"([^\"]*)\"$2")
|
expr = snippetExprQuoted.ReplaceAllString(expr, "$1\"([^\"]*)\"$2")
|
||||||
expr = "^" + strings.TrimSpace(expr) + "$"
|
expr = "^" + strings.TrimSpace(expr) + "$"
|
||||||
|
|
||||||
name := snippetNumbers.ReplaceAllString(u.step.Text, " ")
|
name := snippetNumbers.ReplaceAllString(step, " ")
|
||||||
name = snippetExprQuoted.ReplaceAllString(name, " ")
|
name = snippetExprQuoted.ReplaceAllString(name, " ")
|
||||||
name = snippetMethodName.ReplaceAllString(name, "")
|
name = snippetMethodName.ReplaceAllString(name, "")
|
||||||
var words []string
|
var words []string
|
||||||
|
@ -425,7 +434,8 @@ func (f *basefmt) snippets() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
snips = append(snips, &undefinedSnippet{Method: name, Expr: expr, argument: u.step.Argument})
|
snips = append(snips, &undefinedSnippet{Method: name, Expr: expr, argument: arg})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -297,16 +297,16 @@ func (f *cukefmt) Passed(step *gherkin.Step, match *StepDef) {
|
||||||
f.step(f.passed[len(f.passed)-1])
|
f.step(f.passed[len(f.passed)-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *cukefmt) Skipped(step *gherkin.Step) {
|
func (f *cukefmt) Skipped(step *gherkin.Step, match *StepDef) {
|
||||||
f.basefmt.Skipped(step)
|
f.basefmt.Skipped(step, match)
|
||||||
f.step(f.skipped[len(f.skipped)-1])
|
f.step(f.skipped[len(f.skipped)-1])
|
||||||
|
|
||||||
// no duration reported for skipped.
|
// no duration reported for skipped.
|
||||||
f.curStep.Result.Duration = nil
|
f.curStep.Result.Duration = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *cukefmt) Undefined(step *gherkin.Step) {
|
func (f *cukefmt) Undefined(step *gherkin.Step, match *StepDef) {
|
||||||
f.basefmt.Undefined(step)
|
f.basefmt.Undefined(step, match)
|
||||||
f.stat = undefined
|
f.stat = undefined
|
||||||
f.step(f.undefined[len(f.undefined)-1])
|
f.step(f.undefined[len(f.undefined)-1])
|
||||||
|
|
||||||
|
|
|
@ -245,13 +245,13 @@ func (f *events) Passed(step *gherkin.Step, match *StepDef) {
|
||||||
f.step(f.passed[len(f.passed)-1])
|
f.step(f.passed[len(f.passed)-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Skipped(step *gherkin.Step) {
|
func (f *events) Skipped(step *gherkin.Step, match *StepDef) {
|
||||||
f.basefmt.Skipped(step)
|
f.basefmt.Skipped(step, match)
|
||||||
f.step(f.skipped[len(f.skipped)-1])
|
f.step(f.skipped[len(f.skipped)-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Undefined(step *gherkin.Step) {
|
func (f *events) Undefined(step *gherkin.Step, match *StepDef) {
|
||||||
f.basefmt.Undefined(step)
|
f.basefmt.Undefined(step, match)
|
||||||
f.stat = undefined
|
f.stat = undefined
|
||||||
f.step(f.undefined[len(f.undefined)-1])
|
f.step(f.undefined[len(f.undefined)-1])
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,7 +101,7 @@ func (j *junitFormatter) Passed(step *gherkin.Step, match *StepDef) {
|
||||||
tcase.Status = "passed"
|
tcase.Status = "passed"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *junitFormatter) Skipped(step *gherkin.Step) {
|
func (j *junitFormatter) Skipped(step *gherkin.Step, match *StepDef) {
|
||||||
suite := j.current()
|
suite := j.current()
|
||||||
|
|
||||||
tcase := suite.current()
|
tcase := suite.current()
|
||||||
|
@ -112,7 +112,7 @@ func (j *junitFormatter) Skipped(step *gherkin.Step) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *junitFormatter) Undefined(step *gherkin.Step) {
|
func (j *junitFormatter) Undefined(step *gherkin.Step, match *StepDef) {
|
||||||
suite := j.current()
|
suite := j.current()
|
||||||
tcase := suite.current()
|
tcase := suite.current()
|
||||||
if tcase.Status != "undefined" {
|
if tcase.Status != "undefined" {
|
||||||
|
|
|
@ -334,13 +334,13 @@ func (f *pretty) Passed(step *gherkin.Step, match *StepDef) {
|
||||||
f.printStepKind(f.passed[len(f.passed)-1])
|
f.printStepKind(f.passed[len(f.passed)-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) Skipped(step *gherkin.Step) {
|
func (f *pretty) Skipped(step *gherkin.Step, match *StepDef) {
|
||||||
f.basefmt.Skipped(step)
|
f.basefmt.Skipped(step, match)
|
||||||
f.printStepKind(f.skipped[len(f.skipped)-1])
|
f.printStepKind(f.skipped[len(f.skipped)-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) Undefined(step *gherkin.Step) {
|
func (f *pretty) Undefined(step *gherkin.Step, match *StepDef) {
|
||||||
f.basefmt.Undefined(step)
|
f.basefmt.Undefined(step, match)
|
||||||
f.printStepKind(f.undefined[len(f.undefined)-1])
|
f.printStepKind(f.undefined[len(f.undefined)-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,17 +91,17 @@ func (f *progress) Passed(step *gherkin.Step, match *StepDef) {
|
||||||
f.step(f.passed[len(f.passed)-1])
|
f.step(f.passed[len(f.passed)-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *progress) Skipped(step *gherkin.Step) {
|
func (f *progress) Skipped(step *gherkin.Step, match *StepDef) {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
defer f.Unlock()
|
defer f.Unlock()
|
||||||
f.basefmt.Skipped(step)
|
f.basefmt.Skipped(step, match)
|
||||||
f.step(f.skipped[len(f.skipped)-1])
|
f.step(f.skipped[len(f.skipped)-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *progress) Undefined(step *gherkin.Step) {
|
func (f *progress) Undefined(step *gherkin.Step, match *StepDef) {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
defer f.Unlock()
|
defer f.Unlock()
|
||||||
f.basefmt.Undefined(step)
|
f.basefmt.Undefined(step, match)
|
||||||
f.step(f.undefined[len(f.undefined)-1])
|
f.step(f.undefined[len(f.undefined)-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,6 @@ func TestProgressFormatterOutput(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// var zeroDuration time.Duration
|
|
||||||
expected := `
|
expected := `
|
||||||
...F-.P-.UU.....F..P..U 23
|
...F-.P-.UU.....F..P..U 23
|
||||||
|
|
||||||
|
@ -88,3 +87,177 @@ func trimAllLines(s string) string {
|
||||||
}
|
}
|
||||||
return strings.Join(lines, "\n")
|
return strings.Join(lines, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var basicGherkinFeature = `
|
||||||
|
Feature: basic
|
||||||
|
|
||||||
|
Scenario: passing scenario
|
||||||
|
When one
|
||||||
|
Then two
|
||||||
|
`
|
||||||
|
|
||||||
|
func TestProgressFormatterWhenStepPanics(t *testing.T) {
|
||||||
|
feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
w := colors.Uncolored(&buf)
|
||||||
|
r := runner{
|
||||||
|
fmt: progressFunc("progress", w),
|
||||||
|
features: []*feature{&feature{Feature: feat}},
|
||||||
|
initializer: func(s *Suite) {
|
||||||
|
s.Step(`^one$`, func() error { return nil })
|
||||||
|
s.Step(`^two$`, func() error { panic("omg") })
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if !r.run() {
|
||||||
|
t.Fatal("the suite should have failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
out := buf.String()
|
||||||
|
if idx := strings.Index(out, "github.com/DATA-DOG/godog/fmt_progress_test.go:116"); idx == -1 {
|
||||||
|
t.Fatal("expected to find panic stacktrace")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProgressFormatterWithPassingMultisteps(t *testing.T) {
|
||||||
|
feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
w := colors.Uncolored(&buf)
|
||||||
|
r := runner{
|
||||||
|
fmt: progressFunc("progress", w),
|
||||||
|
features: []*feature{&feature{Feature: feat}},
|
||||||
|
initializer: func(s *Suite) {
|
||||||
|
s.Step(`^sub1$`, func() error { return nil })
|
||||||
|
s.Step(`^sub-sub$`, func() error { return nil })
|
||||||
|
s.Step(`^sub2$`, func() Steps { return Steps{"sub-sub", "sub1", "one"} })
|
||||||
|
s.Step(`^one$`, func() error { return nil })
|
||||||
|
s.Step(`^two$`, func() Steps { return Steps{"sub1", "sub2"} })
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.run() {
|
||||||
|
t.Fatal("the suite should have passed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProgressFormatterWithFailingMultisteps(t *testing.T) {
|
||||||
|
feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
w := colors.Uncolored(&buf)
|
||||||
|
r := runner{
|
||||||
|
fmt: progressFunc("progress", w),
|
||||||
|
features: []*feature{&feature{Feature: feat}},
|
||||||
|
initializer: func(s *Suite) {
|
||||||
|
s.Step(`^sub1$`, func() error { return nil })
|
||||||
|
s.Step(`^sub-sub$`, func() error { return fmt.Errorf("errored") })
|
||||||
|
s.Step(`^sub2$`, func() Steps { return Steps{"sub-sub", "sub1", "one"} })
|
||||||
|
s.Step(`^one$`, func() error { return nil })
|
||||||
|
s.Step(`^two$`, func() Steps { return Steps{"sub1", "sub2"} })
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if !r.run() {
|
||||||
|
t.Fatal("the suite should have failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProgressFormatterWithPanicInMultistep(t *testing.T) {
|
||||||
|
feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
w := colors.Uncolored(&buf)
|
||||||
|
r := runner{
|
||||||
|
fmt: progressFunc("progress", w),
|
||||||
|
features: []*feature{&feature{Feature: feat}},
|
||||||
|
initializer: func(s *Suite) {
|
||||||
|
s.Step(`^sub1$`, func() error { return nil })
|
||||||
|
s.Step(`^sub-sub$`, func() error { return nil })
|
||||||
|
s.Step(`^sub2$`, func() []string { return []string{"sub-sub", "sub1", "one"} })
|
||||||
|
s.Step(`^one$`, func() error { return nil })
|
||||||
|
s.Step(`^two$`, func() []string { return []string{"sub1", "sub2"} })
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if !r.run() {
|
||||||
|
t.Fatal("the suite should have failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProgressFormatterMultistepTemplates(t *testing.T) {
|
||||||
|
feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
w := colors.Uncolored(&buf)
|
||||||
|
r := runner{
|
||||||
|
fmt: progressFunc("progress", w),
|
||||||
|
features: []*feature{&feature{Feature: feat}},
|
||||||
|
initializer: func(s *Suite) {
|
||||||
|
s.Step(`^sub-sub$`, func() error { return nil })
|
||||||
|
s.Step(`^substep$`, func() Steps { return Steps{"sub-sub", `unavailable "John" cost 5`, "one", "three"} })
|
||||||
|
s.Step(`^one$`, func() error { return nil })
|
||||||
|
s.Step(`^(t)wo$`, func(s string) Steps { return Steps{"undef", "substep"} })
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.run() {
|
||||||
|
t.Fatal("the suite should have passed")
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := `
|
||||||
|
.U 2
|
||||||
|
|
||||||
|
|
||||||
|
1 scenarios (1 undefined)
|
||||||
|
2 steps (1 passed, 1 undefined)
|
||||||
|
%s
|
||||||
|
|
||||||
|
Randomized with seed: %s
|
||||||
|
|
||||||
|
You can implement step definitions for undefined steps with these snippets:
|
||||||
|
|
||||||
|
func undef() error {
|
||||||
|
return godog.ErrPending
|
||||||
|
}
|
||||||
|
|
||||||
|
func unavailableCost(arg1 string, arg2 int) error {
|
||||||
|
return godog.ErrPending
|
||||||
|
}
|
||||||
|
|
||||||
|
func three() error {
|
||||||
|
return godog.ErrPending
|
||||||
|
}
|
||||||
|
|
||||||
|
func FeatureContext(s *godog.Suite) {
|
||||||
|
s.Step(` + "`^undef$`" + `, undef)
|
||||||
|
s.Step(` + "`^unavailable \"([^\"]*)\" cost (\\d+)$`" + `, unavailableCost)
|
||||||
|
s.Step(` + "`^three$`" + `, three)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
var zeroDuration time.Duration
|
||||||
|
expected = fmt.Sprintf(expected, zeroDuration.String(), os.Getenv("GODOG_SEED"))
|
||||||
|
expected = trimAllLines(expected)
|
||||||
|
|
||||||
|
actual := trimAllLines(buf.String())
|
||||||
|
if actual != expected {
|
||||||
|
t.Fatalf("expected output does not match: %s", actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
2
godog.go
2
godog.go
|
@ -42,4 +42,4 @@ Godog was inspired by Behat and Cucumber the above description is taken from it'
|
||||||
package godog
|
package godog
|
||||||
|
|
||||||
// Version of package - based on Semantic Versioning 2.0.0 http://semver.org/
|
// Version of package - based on Semantic Versioning 2.0.0 http://semver.org/
|
||||||
const Version = "v0.6.3"
|
const Version = "v0.7.0"
|
||||||
|
|
8
run.go
8
run.go
|
@ -54,7 +54,7 @@ func (r *runner) concurrent(rate int) (failed bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) run() (failed bool) {
|
func (r *runner) run() bool {
|
||||||
suite := &Suite{
|
suite := &Suite{
|
||||||
fmt: r.fmt,
|
fmt: r.fmt,
|
||||||
randomSeed: r.randomSeed,
|
randomSeed: r.randomSeed,
|
||||||
|
@ -160,13 +160,11 @@ func Run(suite string, contextInitializer func(suite *Suite)) int {
|
||||||
func supportsConcurrency(format string) bool {
|
func supportsConcurrency(format string) bool {
|
||||||
switch format {
|
switch format {
|
||||||
case "events":
|
case "events":
|
||||||
return false
|
|
||||||
case "junit":
|
case "junit":
|
||||||
return false
|
|
||||||
case "pretty":
|
case "pretty":
|
||||||
return false
|
|
||||||
case "cucumber":
|
case "cucumber":
|
||||||
return false
|
default:
|
||||||
|
return true // supports concurrency
|
||||||
}
|
}
|
||||||
|
|
||||||
return true // all custom formatters are treated as supporting concurrency
|
return true // all custom formatters are treated as supporting concurrency
|
||||||
|
|
43
run_test.go
43
run_test.go
|
@ -2,10 +2,13 @@ package godog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/DATA-DOG/godog/colors"
|
"github.com/DATA-DOG/godog/colors"
|
||||||
|
"github.com/DATA-DOG/godog/gherkin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func okStep() error {
|
func okStep() error {
|
||||||
|
@ -50,3 +53,43 @@ func TestPrintsNoStepDefinitionsIfNoneFound(t *testing.T) {
|
||||||
t.Fatalf("expected output does not match to: %s", out)
|
t.Fatalf("expected output does not match to: %s", out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestShouldNotFailWhenHasPendingSteps(t *testing.T) {
|
||||||
|
feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := runner{
|
||||||
|
fmt: progressFunc("progress", ioutil.Discard),
|
||||||
|
features: []*feature{&feature{Feature: feat}},
|
||||||
|
initializer: func(s *Suite) {
|
||||||
|
s.Step(`^one$`, func() error { return nil })
|
||||||
|
s.Step(`^two$`, func() error { return ErrPending })
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.run() {
|
||||||
|
t.Fatal("the suite should have passed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShouldFailOnError(t *testing.T) {
|
||||||
|
feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := runner{
|
||||||
|
fmt: progressFunc("progress", ioutil.Discard),
|
||||||
|
features: []*feature{&feature{Feature: feat}},
|
||||||
|
initializer: func(s *Suite) {
|
||||||
|
s.Step(`^one$`, func() error { return nil })
|
||||||
|
s.Step(`^two$`, func() error { return fmt.Errorf("error") })
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if !r.run() {
|
||||||
|
t.Fatal("the suite should have failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
29
stepdef.go
29
stepdef.go
|
@ -14,6 +14,22 @@ import (
|
||||||
|
|
||||||
var matchFuncDefRef = regexp.MustCompile(`\(([^\)]+)\)`)
|
var matchFuncDefRef = regexp.MustCompile(`\(([^\)]+)\)`)
|
||||||
|
|
||||||
|
// Steps allows to nest steps
|
||||||
|
// instead of returning an error in step func
|
||||||
|
// it is possible to return combined steps:
|
||||||
|
//
|
||||||
|
// func multistep(name string) godog.Steps {
|
||||||
|
// return godog.Steps{
|
||||||
|
// fmt.Sprintf(`an user named "%s"`, name),
|
||||||
|
// fmt.Sprintf(`user "%s" is authenticated`, name),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// These steps will be matched and executed in
|
||||||
|
// sequential order. The first one which fails
|
||||||
|
// will result in main step failure.
|
||||||
|
type Steps []string
|
||||||
|
|
||||||
// StepDef is a registered step definition
|
// StepDef is a registered step definition
|
||||||
// contains a StepHandler and regexp which
|
// contains a StepHandler and regexp which
|
||||||
// is used to match a step. Args which
|
// is used to match a step. Args which
|
||||||
|
@ -27,6 +43,10 @@ type StepDef struct {
|
||||||
hv reflect.Value
|
hv reflect.Value
|
||||||
Expr *regexp.Regexp
|
Expr *regexp.Regexp
|
||||||
Handler interface{}
|
Handler interface{}
|
||||||
|
|
||||||
|
// multistep related
|
||||||
|
nested bool
|
||||||
|
undefined []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sd *StepDef) definitionID() string {
|
func (sd *StepDef) definitionID() string {
|
||||||
|
@ -53,7 +73,7 @@ func (sd *StepDef) definitionID() string {
|
||||||
|
|
||||||
// run a step with the matched arguments using
|
// run a step with the matched arguments using
|
||||||
// reflect
|
// reflect
|
||||||
func (sd *StepDef) run() error {
|
func (sd *StepDef) run() interface{} {
|
||||||
typ := sd.hv.Type()
|
typ := sd.hv.Type()
|
||||||
if len(sd.args) < typ.NumIn() {
|
if len(sd.args) < typ.NumIn() {
|
||||||
return fmt.Errorf("func expects %d arguments, which is more than %d matched from step", typ.NumIn(), len(sd.args))
|
return fmt.Errorf("func expects %d arguments, which is more than %d matched from step", typ.NumIn(), len(sd.args))
|
||||||
|
@ -171,12 +191,7 @@ func (sd *StepDef) run() error {
|
||||||
return fmt.Errorf("the argument %d type %s is not supported", i, param.Kind())
|
return fmt.Errorf("the argument %d type %s is not supported", i, param.Kind())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret := sd.hv.Call(values)[0].Interface()
|
return sd.hv.Call(values)[0].Interface()
|
||||||
if nil == ret {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret.(error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sd *StepDef) shouldBeString(idx int) (string, error) {
|
func (sd *StepDef) shouldBeString(idx int) (string, error) {
|
||||||
|
|
162
suite.go
162
suite.go
|
@ -95,17 +95,33 @@ func (s *Suite) Step(expr interface{}, stepFunc interface{}) {
|
||||||
if typ.Kind() != reflect.Func {
|
if typ.Kind() != reflect.Func {
|
||||||
panic(fmt.Sprintf("expected handler to be func, but got: %T", stepFunc))
|
panic(fmt.Sprintf("expected handler to be func, but got: %T", stepFunc))
|
||||||
}
|
}
|
||||||
|
|
||||||
if typ.NumOut() != 1 {
|
if typ.NumOut() != 1 {
|
||||||
panic(fmt.Sprintf("expected handler to return an error, but it has more values in return: %d", typ.NumOut()))
|
panic(fmt.Sprintf("expected handler to return only one value, but it has: %d", typ.NumOut()))
|
||||||
}
|
}
|
||||||
if typ.Out(0).Kind() != reflect.Interface || !typ.Out(0).Implements(errorInterface) {
|
|
||||||
panic(fmt.Sprintf("expected handler to return an error interface, but we have: %s", typ.Out(0).Kind()))
|
def := &StepDef{
|
||||||
}
|
|
||||||
s.steps = append(s.steps, &StepDef{
|
|
||||||
Handler: stepFunc,
|
Handler: stepFunc,
|
||||||
Expr: regex,
|
Expr: regex,
|
||||||
hv: v,
|
hv: v,
|
||||||
})
|
}
|
||||||
|
|
||||||
|
typ = typ.Out(0)
|
||||||
|
switch typ.Kind() {
|
||||||
|
case reflect.Interface:
|
||||||
|
if !typ.Implements(errorInterface) {
|
||||||
|
panic(fmt.Sprintf("expected handler to return an error, but got: %s", typ.Kind()))
|
||||||
|
}
|
||||||
|
case reflect.Slice:
|
||||||
|
if typ.Elem().Kind() != reflect.String {
|
||||||
|
panic(fmt.Sprintf("expected handler to return []string for multistep, but got: []%s", typ.Kind()))
|
||||||
|
}
|
||||||
|
def.nested = true
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("expected handler to return an error or []string, but got: %s", typ.Kind()))
|
||||||
|
}
|
||||||
|
|
||||||
|
s.steps = append(s.steps, def)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeforeSuite registers a function or method
|
// BeforeSuite registers a function or method
|
||||||
|
@ -184,41 +200,18 @@ func (s *Suite) run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Suite) matchStep(step *gherkin.Step) *StepDef {
|
func (s *Suite) matchStep(step *gherkin.Step) *StepDef {
|
||||||
for _, h := range s.steps {
|
def := s.matchStepText(step.Text)
|
||||||
if m := h.Expr.FindStringSubmatch(step.Text); len(m) > 0 {
|
if def != nil && step.Argument != nil {
|
||||||
var args []interface{}
|
def.args = append(def.args, step.Argument)
|
||||||
for _, m := range m[1:] {
|
|
||||||
args = append(args, m)
|
|
||||||
}
|
}
|
||||||
if step.Argument != nil {
|
return def
|
||||||
args = append(args, step.Argument)
|
|
||||||
}
|
|
||||||
h.args = args
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// @TODO can handle ambiguous
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Suite) runStep(step *gherkin.Step, prevStepErr error) (err error) {
|
func (s *Suite) runStep(step *gherkin.Step, prevStepErr error) (err error) {
|
||||||
match := s.matchStep(step)
|
match := s.matchStep(step)
|
||||||
s.fmt.Defined(step, match)
|
s.fmt.Defined(step, match)
|
||||||
if match == nil {
|
|
||||||
s.fmt.Undefined(step)
|
|
||||||
return ErrUndefined
|
|
||||||
}
|
|
||||||
|
|
||||||
if prevStepErr != nil {
|
|
||||||
s.fmt.Skipped(step)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// run before step handlers
|
|
||||||
for _, f := range s.beforeStepHandlers {
|
|
||||||
f(step)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// user multistep definitions may panic
|
||||||
defer func() {
|
defer func() {
|
||||||
if e := recover(); e != nil {
|
if e := recover(); e != nil {
|
||||||
err = &traceError{
|
err = &traceError{
|
||||||
|
@ -226,6 +219,15 @@ func (s *Suite) runStep(step *gherkin.Step, prevStepErr error) (err error) {
|
||||||
stack: callStack(),
|
stack: callStack(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if prevStepErr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == ErrUndefined {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
switch err {
|
switch err {
|
||||||
case nil:
|
case nil:
|
||||||
s.fmt.Passed(step, match)
|
s.fmt.Passed(step, match)
|
||||||
|
@ -241,10 +243,98 @@ func (s *Suite) runStep(step *gherkin.Step, prevStepErr error) (err error) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err = match.run()
|
if undef := s.maybeUndefined(step.Text); len(undef) > 0 {
|
||||||
|
if match != nil {
|
||||||
|
match = &StepDef{
|
||||||
|
args: match.args,
|
||||||
|
hv: match.hv,
|
||||||
|
Expr: match.Expr,
|
||||||
|
Handler: match.Handler,
|
||||||
|
nested: match.nested,
|
||||||
|
undefined: undef,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.fmt.Undefined(step, match)
|
||||||
|
return ErrUndefined
|
||||||
|
}
|
||||||
|
|
||||||
|
if prevStepErr != nil {
|
||||||
|
s.fmt.Skipped(step, match)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// run before step handlers
|
||||||
|
for _, f := range s.beforeStepHandlers {
|
||||||
|
f(step)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.maybeSubSteps(match.run())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Suite) maybeUndefined(text string) (undefined []string) {
|
||||||
|
step := s.matchStepText(text)
|
||||||
|
if nil == step {
|
||||||
|
undefined = append(undefined, text)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !step.nested {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, next := range step.run().(Steps) {
|
||||||
|
undefined = append(undefined, s.maybeUndefined(next)...)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Suite) maybeSubSteps(result interface{}) error {
|
||||||
|
if nil == result {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err, ok := result.(error); ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
steps, ok := result.(Steps)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected error, should have been []string: %T - %+v", result, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, text := range steps {
|
||||||
|
if def := s.matchStepText(text); def == nil {
|
||||||
|
return ErrUndefined
|
||||||
|
} else if err := s.maybeSubSteps(def.run()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Suite) matchStepText(text string) *StepDef {
|
||||||
|
for _, h := range s.steps {
|
||||||
|
if m := h.Expr.FindStringSubmatch(text); len(m) > 0 {
|
||||||
|
var args []interface{}
|
||||||
|
for _, m := range m[1:] {
|
||||||
|
args = append(args, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// since we need to assign arguments
|
||||||
|
// better to copy the step definition
|
||||||
|
return &StepDef{
|
||||||
|
args: args,
|
||||||
|
hv: h.hv,
|
||||||
|
Expr: h.Expr,
|
||||||
|
Handler: h.Handler,
|
||||||
|
nested: h.nested,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Suite) runSteps(steps []*gherkin.Step, prevErr error) (err error) {
|
func (s *Suite) runSteps(steps []*gherkin.Step, prevErr error) (err error) {
|
||||||
err = prevErr
|
err = prevErr
|
||||||
for _, step := range steps {
|
for _, step := range steps {
|
||||||
|
@ -264,7 +354,7 @@ func (s *Suite) runSteps(steps []*gherkin.Step, prevErr error) (err error) {
|
||||||
|
|
||||||
func (s *Suite) skipSteps(steps []*gherkin.Step) {
|
func (s *Suite) skipSteps(steps []*gherkin.Step) {
|
||||||
for _, step := range steps {
|
for _, step := range steps {
|
||||||
s.fmt.Skipped(step)
|
s.fmt.Skipped(step, s.matchStep(step))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,14 +20,20 @@ func TestMain(m *testing.M) {
|
||||||
format := "progress" // non verbose mode
|
format := "progress" // non verbose mode
|
||||||
concurrency := 4
|
concurrency := 4
|
||||||
|
|
||||||
|
var specific bool
|
||||||
for _, arg := range os.Args[1:] {
|
for _, arg := range os.Args[1:] {
|
||||||
if arg == "-test.v=true" { // go test transforms -v option - verbose mode
|
if arg == "-test.v=true" { // go test transforms -v option - verbose mode
|
||||||
format = "pretty"
|
format = "pretty"
|
||||||
concurrency = 1
|
concurrency = 1
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if strings.Index(arg, "-test.run") == 0 {
|
||||||
|
specific = true
|
||||||
}
|
}
|
||||||
status := RunWithOptions("godog", func(s *Suite) {
|
}
|
||||||
|
var status int
|
||||||
|
if !specific {
|
||||||
|
status = RunWithOptions("godog", func(s *Suite) {
|
||||||
SuiteContext(s)
|
SuiteContext(s)
|
||||||
}, Options{
|
}, Options{
|
||||||
Format: format, // pretty format for verbose mode, otherwise - progress
|
Format: format, // pretty format for verbose mode, otherwise - progress
|
||||||
|
@ -35,6 +41,7 @@ func TestMain(m *testing.M) {
|
||||||
Concurrency: concurrency, // concurrency for verbose mode is 1
|
Concurrency: concurrency, // concurrency for verbose mode is 1
|
||||||
Randomize: time.Now().UnixNano(), // randomize scenario execution order
|
Randomize: time.Now().UnixNano(), // randomize scenario execution order
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if st := m.Run(); st > status {
|
if st := m.Run(); st > status {
|
||||||
status = st
|
status = st
|
||||||
|
@ -89,6 +96,21 @@ func SuiteContext(s *Suite) {
|
||||||
// Introduced to test formatter/cucumber.feature
|
// Introduced to test formatter/cucumber.feature
|
||||||
s.Step(`^the rendered json will be as follows:$`, c.theRenderJSONWillBe)
|
s.Step(`^the rendered json will be as follows:$`, c.theRenderJSONWillBe)
|
||||||
|
|
||||||
|
s.Step(`^failing multistep$`, func() Steps {
|
||||||
|
return Steps{"passing step", "failing step"}
|
||||||
|
})
|
||||||
|
|
||||||
|
s.Step(`^undefined multistep$`, func() Steps {
|
||||||
|
return Steps{"passing step", "undefined step", "passing step"}
|
||||||
|
})
|
||||||
|
|
||||||
|
s.Step(`^passing multistep$`, func() Steps {
|
||||||
|
return Steps{"passing step", "passing step", "passing step"}
|
||||||
|
})
|
||||||
|
|
||||||
|
s.Step(`^failing nested multistep$`, func() Steps {
|
||||||
|
return Steps{"passing step", "passing multistep", "failing multistep"}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type firedEvent struct {
|
type firedEvent struct {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче