Implement unambiguous keywords (#509)
feat(*): create keyword functions * chore(*): update messages and gherkin, relocate Keyword * chore(*): update messages and gherkin, relocate Keyword * chore(*): update messages and gherkin, relocate Keyword * feat(*): mandate keyword type when unambiguous keyword function is used * test(*): keyword type in feature files * docs(*): update step-by-step walkthrough to mention the option of using keyword functions * docs(*): update CHANGELOG.md * test(*): keyword substeps * chore(*): go mod
Этот коммит содержится в:
родитель
c035051d94
коммит
62d84eedbc
10 изменённых файлов: 289 добавлений и 26 удалений
|
@ -7,6 +7,8 @@ This project adheres to [Semantic Versioning](http://semver.org).
|
||||||
This document is formatted according to the principles of [Keep A CHANGELOG](http://keepachangelog.com).
|
This document is formatted according to the principles of [Keep A CHANGELOG](http://keepachangelog.com).
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
### Added
|
||||||
|
- Added keyword functions. ([509](https://github.com/cucumber/godog/pull/509) - [otrava7](https://github.com/otrava7))
|
||||||
|
|
||||||
## [v0.12.6]
|
## [v0.12.6]
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -164,6 +164,15 @@ func InitializeScenario(ctx *godog.ScenarioContext) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Alternatively, you can also specify the keyword (Given, When, Then...) when creating the step definitions:
|
||||||
|
``` go
|
||||||
|
func InitializeScenario(ctx *godog.ScenarioContext) {
|
||||||
|
ctx.Given(`^I eat (\d+)$`, iEat)
|
||||||
|
ctx.When(`^there are (\d+) godogs$`, thereAreGodogs)
|
||||||
|
ctx.Then(`^there should be (\d+) remaining$`, thereShouldBeRemaining)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Our module should now look like this:
|
Our module should now look like this:
|
||||||
```
|
```
|
||||||
godogs
|
godogs
|
||||||
|
|
|
@ -121,17 +121,17 @@ Feature: suite events
|
||||||
Feature: scenario hook errors
|
Feature: scenario hook errors
|
||||||
|
|
||||||
Scenario: failing before and after scenario # normal.feature:3
|
Scenario: failing before and after scenario # normal.feature:3
|
||||||
Then adding step state to context # suite_context_test.go:0 -> InitializeScenario.func12
|
Then adding step state to context # suite_context_test.go:0 -> InitializeScenario.func17
|
||||||
after scenario hook failed: failed in after scenario hook, step error: before scenario hook failed: failed in before scenario hook
|
after scenario hook failed: failed in after scenario hook, step error: before scenario hook failed: failed in before scenario hook
|
||||||
And passing step # suite_context_test.go:0 -> InitializeScenario.func2
|
And passing step # suite_context_test.go:0 -> InitializeScenario.func2
|
||||||
|
|
||||||
Scenario: failing before scenario # normal.feature:7
|
Scenario: failing before scenario # normal.feature:7
|
||||||
Then adding step state to context # suite_context_test.go:0 -> InitializeScenario.func12
|
Then adding step state to context # suite_context_test.go:0 -> InitializeScenario.func17
|
||||||
before scenario hook failed: failed in before scenario hook
|
before scenario hook failed: failed in before scenario hook
|
||||||
And passing step # suite_context_test.go:0 -> InitializeScenario.func2
|
And passing step # suite_context_test.go:0 -> InitializeScenario.func2
|
||||||
|
|
||||||
Scenario: failing after scenario # normal.feature:11
|
Scenario: failing after scenario # normal.feature:11
|
||||||
Then adding step state to context # suite_context_test.go:0 -> InitializeScenario.func12
|
Then adding step state to context # suite_context_test.go:0 -> InitializeScenario.func17
|
||||||
And passing step # suite_context_test.go:0 -> InitializeScenario.func2
|
And passing step # suite_context_test.go:0 -> InitializeScenario.func2
|
||||||
after scenario hook failed: failed in after scenario hook
|
after scenario hook failed: failed in after scenario hook
|
||||||
|
|
||||||
|
|
|
@ -332,11 +332,11 @@ Feature: pretty formatter
|
||||||
Feature: inject long value
|
Feature: inject long value
|
||||||
|
|
||||||
Scenario: test scenario # features/inject.feature:3
|
Scenario: test scenario # features/inject.feature:3
|
||||||
Given Ignore I save some value X under key Y # suite_context.go:0 -> SuiteContext.func7
|
Given Ignore I save some value X under key Y # suite_context.go:0 -> SuiteContext.func12
|
||||||
And I allow variable injection # suite_context.go:0 -> *suiteContext
|
And I allow variable injection # suite_context.go:0 -> *suiteContext
|
||||||
When Ignore I use value someverylonginjectionsoweacanbesureitsurpasstheinitiallongeststeplenghtanditwillhelptestsmethodsafety # suite_context.go:0 -> SuiteContext.func7
|
When Ignore I use value someverylonginjectionsoweacanbesureitsurpasstheinitiallongeststeplenghtanditwillhelptestsmethodsafety # suite_context.go:0 -> SuiteContext.func12
|
||||||
Then Ignore Godog rendering should not break # suite_context.go:0 -> SuiteContext.func7
|
Then Ignore Godog rendering should not break # suite_context.go:0 -> SuiteContext.func12
|
||||||
And Ignore test # suite_context.go:0 -> SuiteContext.func7
|
And Ignore test # suite_context.go:0 -> SuiteContext.func12
|
||||||
| key | val |
|
| key | val |
|
||||||
| 1 | 2 |
|
| 1 | 2 |
|
||||||
| 3 | 4 |
|
| 3 | 4 |
|
||||||
|
@ -548,3 +548,139 @@ Feature: pretty formatter
|
||||||
2 steps (1 passed, 1 failed)
|
2 steps (1 passed, 1 failed)
|
||||||
0s
|
0s
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
Scenario: Use 'given' keyword on a declared 'when' step
|
||||||
|
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 a when 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 a when step
|
||||||
|
|
||||||
|
1 scenarios (1 undefined)
|
||||||
|
1 steps (1 undefined)
|
||||||
|
0s
|
||||||
|
|
||||||
|
You can implement step definitions for undefined steps with these snippets:
|
||||||
|
|
||||||
|
func aWhenStep() error {
|
||||||
|
return godog.ErrPending
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitializeScenario(ctx *godog.ScenarioContext) {
|
||||||
|
ctx.Step(`^a when step$`, aWhenStep)
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Use 'when' keyword on a declared 'then' step
|
||||||
|
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
|
||||||
|
When a then 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
|
||||||
|
When a then step
|
||||||
|
|
||||||
|
1 scenarios (1 undefined)
|
||||||
|
1 steps (1 undefined)
|
||||||
|
0s
|
||||||
|
|
||||||
|
You can implement step definitions for undefined steps with these snippets:
|
||||||
|
|
||||||
|
func aThenStep() error {
|
||||||
|
return godog.ErrPending
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitializeScenario(ctx *godog.ScenarioContext) {
|
||||||
|
ctx.Step(`^a then step$`, aThenStep)
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Use 'then' keyword on a declared 'given' step
|
||||||
|
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
|
||||||
|
Then a given 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
|
||||||
|
Then a given step
|
||||||
|
|
||||||
|
1 scenarios (1 undefined)
|
||||||
|
1 steps (1 undefined)
|
||||||
|
0s
|
||||||
|
|
||||||
|
You can implement step definitions for undefined steps with these snippets:
|
||||||
|
|
||||||
|
func aGivenStep() error {
|
||||||
|
return godog.ErrPending
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitializeScenario(ctx *godog.ScenarioContext) {
|
||||||
|
ctx.Step(`^a given step$`, aGivenStep)
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Match keyword functions correctly
|
||||||
|
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 a given step
|
||||||
|
When a when step
|
||||||
|
Then a then step
|
||||||
|
And a then 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 a given step # suite_context_test.go:0 -> InitializeScenario.func3
|
||||||
|
When a when step # suite_context_test.go:0 -> InitializeScenario.func4
|
||||||
|
Then a then step # suite_context_test.go:0 -> InitializeScenario.func5
|
||||||
|
And a then step # suite_context_test.go:0 -> InitializeScenario.func5
|
||||||
|
|
||||||
|
1 scenarios (1 passed)
|
||||||
|
4 steps (4 passed)
|
||||||
|
0s
|
||||||
|
"""
|
|
@ -161,3 +161,40 @@ Feature: run features with nested steps
|
||||||
"""
|
"""
|
||||||
When I run feature suite
|
When I run feature suite
|
||||||
Then the suite should have passed
|
Then the suite should have passed
|
||||||
|
|
||||||
|
Scenario: should run passing multistep using keyword function successfully
|
||||||
|
Given a feature "normal.feature" file:
|
||||||
|
"""
|
||||||
|
Feature: normal feature
|
||||||
|
|
||||||
|
Scenario: run passing multistep
|
||||||
|
Given passing step
|
||||||
|
Then passing multistep using 'then' function
|
||||||
|
"""
|
||||||
|
When I run feature suite
|
||||||
|
Then the suite should have passed
|
||||||
|
And the following steps should be passed:
|
||||||
|
"""
|
||||||
|
passing step
|
||||||
|
passing multistep using 'then' function
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: should identify undefined multistep using keyword function
|
||||||
|
Given a feature "normal.feature" file:
|
||||||
|
"""
|
||||||
|
Feature: normal feature
|
||||||
|
|
||||||
|
Scenario: run passing multistep
|
||||||
|
Given passing step
|
||||||
|
Then undefined multistep using 'then' function
|
||||||
|
"""
|
||||||
|
When I run feature suite
|
||||||
|
Then the suite should have passed
|
||||||
|
And the following steps should be passed:
|
||||||
|
"""
|
||||||
|
passing step
|
||||||
|
"""
|
||||||
|
And the following step should be undefined:
|
||||||
|
"""
|
||||||
|
undefined multistep using 'then' function
|
||||||
|
"""
|
||||||
|
|
|
@ -88,4 +88,14 @@ type FormatterFunc func(string, io.Writer) Formatter
|
||||||
type StepDefinition struct {
|
type StepDefinition struct {
|
||||||
Expr *regexp.Regexp
|
Expr *regexp.Regexp
|
||||||
Handler interface{}
|
Handler interface{}
|
||||||
|
Keyword Keyword
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Keyword int64
|
||||||
|
|
||||||
|
const (
|
||||||
|
Given Keyword = iota
|
||||||
|
When
|
||||||
|
Then
|
||||||
|
None
|
||||||
|
)
|
||||||
|
|
14
run_test.go
14
run_test.go
|
@ -518,11 +518,12 @@ func Test_AllFeaturesRun(t *testing.T) {
|
||||||
...................................................................... 140
|
...................................................................... 140
|
||||||
...................................................................... 210
|
...................................................................... 210
|
||||||
...................................................................... 280
|
...................................................................... 280
|
||||||
....................................................... 335
|
...................................................................... 350
|
||||||
|
...... 356
|
||||||
|
|
||||||
|
|
||||||
88 scenarios (88 passed)
|
94 scenarios (94 passed)
|
||||||
335 steps (335 passed)
|
356 steps (356 passed)
|
||||||
0s
|
0s
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -545,11 +546,12 @@ func Test_AllFeaturesRunAsSubtests(t *testing.T) {
|
||||||
...................................................................... 140
|
...................................................................... 140
|
||||||
...................................................................... 210
|
...................................................................... 210
|
||||||
...................................................................... 280
|
...................................................................... 280
|
||||||
....................................................... 335
|
...................................................................... 350
|
||||||
|
...... 356
|
||||||
|
|
||||||
|
|
||||||
88 scenarios (88 passed)
|
94 scenarios (94 passed)
|
||||||
335 steps (335 passed)
|
356 steps (356 passed)
|
||||||
0s
|
0s
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
35
suite.go
35
suite.go
|
@ -65,7 +65,7 @@ type suite struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *suite) matchStep(step *messages.PickleStep) *models.StepDefinition {
|
func (s *suite) matchStep(step *messages.PickleStep) *models.StepDefinition {
|
||||||
def := s.matchStepText(step.Text)
|
def := s.matchStepTextAndType(step.Text, step.Type)
|
||||||
if def != nil && step.Argument != nil {
|
if def != nil && step.Argument != nil {
|
||||||
def.Args = append(def.Args, step.Argument)
|
def.Args = append(def.Args, step.Argument)
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ func (s *suite) runStep(ctx context.Context, pickle *Scenario, step *Step, prevS
|
||||||
return ctx, err
|
return ctx, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx, undef, err := s.maybeUndefined(ctx, step.Text, step.Argument); err != nil {
|
if ctx, undef, err := s.maybeUndefined(ctx, step.Text, step.Argument, step.Type); err != nil {
|
||||||
return ctx, err
|
return ctx, err
|
||||||
} else if len(undef) > 0 {
|
} else if len(undef) > 0 {
|
||||||
if match != nil {
|
if match != nil {
|
||||||
|
@ -155,6 +155,7 @@ func (s *suite) runStep(ctx context.Context, pickle *Scenario, step *Step, prevS
|
||||||
StepDefinition: formatters.StepDefinition{
|
StepDefinition: formatters.StepDefinition{
|
||||||
Expr: match.Expr,
|
Expr: match.Expr,
|
||||||
Handler: match.Handler,
|
Handler: match.Handler,
|
||||||
|
Keyword: match.Keyword,
|
||||||
},
|
},
|
||||||
Args: match.Args,
|
Args: match.Args,
|
||||||
HandlerValue: match.HandlerValue,
|
HandlerValue: match.HandlerValue,
|
||||||
|
@ -297,8 +298,8 @@ func (s *suite) runAfterScenarioHooks(ctx context.Context, pickle *messages.Pick
|
||||||
return ctx, err
|
return ctx, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *suite) maybeUndefined(ctx context.Context, text string, arg interface{}) (context.Context, []string, error) {
|
func (s *suite) maybeUndefined(ctx context.Context, text string, arg interface{}, stepType messages.PickleStepType) (context.Context, []string, error) {
|
||||||
step := s.matchStepText(text)
|
step := s.matchStepTextAndType(text, stepType)
|
||||||
if nil == step {
|
if nil == step {
|
||||||
return ctx, []string{text}, nil
|
return ctx, []string{text}, nil
|
||||||
}
|
}
|
||||||
|
@ -323,7 +324,7 @@ func (s *suite) maybeUndefined(ctx context.Context, text string, arg interface{}
|
||||||
if len(lines[0]) > 0 && lines[0][len(lines[0])-1] == ':' {
|
if len(lines[0]) > 0 && lines[0][len(lines[0])-1] == ':' {
|
||||||
return ctx, undefined, fmt.Errorf("nested steps cannot be multiline and have table or content body argument")
|
return ctx, undefined, fmt.Errorf("nested steps cannot be multiline and have table or content body argument")
|
||||||
}
|
}
|
||||||
ctx, undef, err := s.maybeUndefined(ctx, next, nil)
|
ctx, undef, err := s.maybeUndefined(ctx, next, nil, messages.PickleStepType_UNKNOWN)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx, undefined, err
|
return ctx, undefined, err
|
||||||
}
|
}
|
||||||
|
@ -349,7 +350,7 @@ func (s *suite) maybeSubSteps(ctx context.Context, result interface{}) (context.
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
for _, text := range steps {
|
for _, text := range steps {
|
||||||
if def := s.matchStepText(text); def == nil {
|
if def := s.matchStepTextAndType(text, messages.PickleStepType_UNKNOWN); def == nil {
|
||||||
return ctx, ErrUndefined
|
return ctx, ErrUndefined
|
||||||
} else if ctx, err = s.maybeSubSteps(def.Run(ctx)); err != nil {
|
} else if ctx, err = s.maybeSubSteps(def.Run(ctx)); err != nil {
|
||||||
return ctx, fmt.Errorf("%s: %+v", text, err)
|
return ctx, fmt.Errorf("%s: %+v", text, err)
|
||||||
|
@ -358,9 +359,12 @@ func (s *suite) maybeSubSteps(ctx context.Context, result interface{}) (context.
|
||||||
return ctx, nil
|
return ctx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *suite) matchStepText(text string) *models.StepDefinition {
|
func (s *suite) matchStepTextAndType(text string, stepType messages.PickleStepType) *models.StepDefinition {
|
||||||
for _, h := range s.steps {
|
for _, h := range s.steps {
|
||||||
if m := h.Expr.FindStringSubmatch(text); len(m) > 0 {
|
if m := h.Expr.FindStringSubmatch(text); len(m) > 0 {
|
||||||
|
if !keywordMatches(h.Keyword, stepType) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
var args []interface{}
|
var args []interface{}
|
||||||
for _, m := range m[1:] {
|
for _, m := range m[1:] {
|
||||||
args = append(args, m)
|
args = append(args, m)
|
||||||
|
@ -372,6 +376,7 @@ func (s *suite) matchStepText(text string) *models.StepDefinition {
|
||||||
StepDefinition: formatters.StepDefinition{
|
StepDefinition: formatters.StepDefinition{
|
||||||
Expr: h.Expr,
|
Expr: h.Expr,
|
||||||
Handler: h.Handler,
|
Handler: h.Handler,
|
||||||
|
Keyword: h.Keyword,
|
||||||
},
|
},
|
||||||
Args: args,
|
Args: args,
|
||||||
HandlerValue: h.HandlerValue,
|
HandlerValue: h.HandlerValue,
|
||||||
|
@ -382,6 +387,22 @@ func (s *suite) matchStepText(text string) *models.StepDefinition {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func keywordMatches(k formatters.Keyword, stepType messages.PickleStepType) bool {
|
||||||
|
if k == formatters.None {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
switch stepType {
|
||||||
|
case messages.PickleStepType_CONTEXT:
|
||||||
|
return k == formatters.Given
|
||||||
|
case messages.PickleStepType_ACTION:
|
||||||
|
return k == formatters.When
|
||||||
|
case messages.PickleStepType_OUTCOME:
|
||||||
|
return k == formatters.Then
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *suite) runSteps(ctx context.Context, pickle *Scenario, steps []*Step) (context.Context, error) {
|
func (s *suite) runSteps(ctx context.Context, pickle *Scenario, steps []*Step) (context.Context, error) {
|
||||||
var (
|
var (
|
||||||
stepErr, err error
|
stepErr, err error
|
||||||
|
|
|
@ -73,6 +73,15 @@ func InitializeScenario(ctx *ScenarioContext) {
|
||||||
ctx.Step(`^(?:a )?passing step$`, func() error {
|
ctx.Step(`^(?:a )?passing step$`, func() error {
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
ctx.Given(`^(?:a )?given step$`, func() error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
ctx.When(`^(?:a )?when step$`, func() error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
ctx.Then(`^(?:a )?then step$`, func() error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
// Introduced to test formatter/cucumber.feature
|
// Introduced to test formatter/cucumber.feature
|
||||||
ctx.Step(`^the rendered json will be as follows:$`, tc.theRenderJSONWillBe)
|
ctx.Step(`^the rendered json will be as follows:$`, tc.theRenderJSONWillBe)
|
||||||
|
@ -91,10 +100,18 @@ func InitializeScenario(ctx *ScenarioContext) {
|
||||||
return Steps{"passing step", "undefined step", "passing step"}
|
return Steps{"passing step", "undefined step", "passing step"}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ctx.Then(`^(?:a |an )?undefined multistep using 'then' function$`, func() Steps {
|
||||||
|
return Steps{"given step", "undefined step", "then step"}
|
||||||
|
})
|
||||||
|
|
||||||
ctx.Step(`^(?:a )?passing multistep$`, func() Steps {
|
ctx.Step(`^(?:a )?passing multistep$`, func() Steps {
|
||||||
return Steps{"passing step", "passing step", "passing step"}
|
return Steps{"passing step", "passing step", "passing step"}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ctx.Then(`^(?:a )?passing multistep using 'then' function$`, func() Steps {
|
||||||
|
return Steps{"given step", "when step", "then step"}
|
||||||
|
})
|
||||||
|
|
||||||
ctx.Step(`^(?:a )?failing nested multistep$`, func() Steps {
|
ctx.Step(`^(?:a )?failing nested multistep$`, func() Steps {
|
||||||
return Steps{"passing step", "passing multistep", "failing multistep"}
|
return Steps{"passing step", "passing multistep", "failing multistep"}
|
||||||
})
|
})
|
||||||
|
|
|
@ -26,12 +26,12 @@ type Step = messages.PickleStep
|
||||||
// instead of returning an error in step func
|
// instead of returning an error in step func
|
||||||
// it is possible to return combined steps:
|
// it is possible to return combined steps:
|
||||||
//
|
//
|
||||||
// func multistep(name string) godog.Steps {
|
// func multistep(name string) godog.Steps {
|
||||||
// return godog.Steps{
|
// return godog.Steps{
|
||||||
// fmt.Sprintf(`an user named "%s"`, name),
|
// fmt.Sprintf(`an user named "%s"`, name),
|
||||||
// fmt.Sprintf(`user "%s" is authenticated`, name),
|
// fmt.Sprintf(`user "%s" is authenticated`, name),
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// These steps will be matched and executed in
|
// These steps will be matched and executed in
|
||||||
// sequential order. The first one which fails
|
// sequential order. The first one which fails
|
||||||
|
@ -251,6 +251,34 @@ func (ctx *ScenarioContext) AfterStep(fn func(st *Step, err error)) {
|
||||||
// ErrUndefined error will be returned when
|
// ErrUndefined error will be returned when
|
||||||
// running steps.
|
// running steps.
|
||||||
func (ctx *ScenarioContext) Step(expr, stepFunc interface{}) {
|
func (ctx *ScenarioContext) Step(expr, stepFunc interface{}) {
|
||||||
|
ctx.stepWithKeyword(expr, stepFunc, formatters.None)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given functions identically to Step, but the *StepDefinition
|
||||||
|
// will only be matched if the step starts with "Given". "And"
|
||||||
|
// and "But" keywords copy the keyword of the last step for the
|
||||||
|
// purpose of matching.
|
||||||
|
func (ctx *ScenarioContext) Given(expr, stepFunc interface{}) {
|
||||||
|
ctx.stepWithKeyword(expr, stepFunc, formatters.Given)
|
||||||
|
}
|
||||||
|
|
||||||
|
// When functions identically to Step, but the *StepDefinition
|
||||||
|
// will only be matched if the step starts with "When". "And"
|
||||||
|
// and "But" keywords copy the keyword of the last step for the
|
||||||
|
// purpose of matching.
|
||||||
|
func (ctx *ScenarioContext) When(expr, stepFunc interface{}) {
|
||||||
|
ctx.stepWithKeyword(expr, stepFunc, formatters.When)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then functions identically to Step, but the *StepDefinition
|
||||||
|
// will only be matched if the step starts with "Then". "And"
|
||||||
|
// and "But" keywords copy the keyword of the last step for the
|
||||||
|
// purpose of matching.
|
||||||
|
func (ctx *ScenarioContext) Then(expr, stepFunc interface{}) {
|
||||||
|
ctx.stepWithKeyword(expr, stepFunc, formatters.Then)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *ScenarioContext) stepWithKeyword(expr interface{}, stepFunc interface{}, keyword formatters.Keyword) {
|
||||||
var regex *regexp.Regexp
|
var regex *regexp.Regexp
|
||||||
|
|
||||||
switch t := expr.(type) {
|
switch t := expr.(type) {
|
||||||
|
@ -278,6 +306,7 @@ func (ctx *ScenarioContext) Step(expr, stepFunc interface{}) {
|
||||||
StepDefinition: formatters.StepDefinition{
|
StepDefinition: formatters.StepDefinition{
|
||||||
Handler: stepFunc,
|
Handler: stepFunc,
|
||||||
Expr: regex,
|
Expr: regex,
|
||||||
|
Keyword: keyword,
|
||||||
},
|
},
|
||||||
HandlerValue: v,
|
HandlerValue: v,
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче