diff --git a/features/formatter/events.feature b/features/formatter/events.feature index 5cfa8cf..2947fa9 100644 --- a/features/formatter/events.feature +++ b/features/formatter/events.feature @@ -14,7 +14,7 @@ Feature: event stream formatter """ Scenario: should process simple scenario - Given a feature path "features/load.feature:23" + Given a feature path "features/load.feature:24" When I run feature suite with formatter "events" Then the following events should be fired: """ @@ -35,7 +35,7 @@ Feature: event stream formatter """ Scenario: should process outline scenario - Given a feature path "features/load.feature:31" + Given a feature path "features/load.feature:32" When I run feature suite with formatter "events" Then the following events should be fired: """ diff --git a/features/lang.feature b/features/lang.feature index 594786e..08b1083 100644 --- a/features/lang.feature +++ b/features/lang.feature @@ -8,7 +8,7 @@ Savybė: užkrauti savybes Scenarijus: savybių užkrovimas iš aplanko Duota savybių aplankas "features" Kai aš išskaitau savybes - Tada aš turėčiau turėti 10 savybių failus: + Tada aš turėčiau turėti 11 savybių failus: """ features/background.feature features/events.feature @@ -20,4 +20,5 @@ Savybė: užkrauti savybes features/outline.feature features/run.feature features/snippets.feature + features/tags.feature """ diff --git a/features/load.feature b/features/load.feature index 7b64dec..16afd50 100644 --- a/features/load.feature +++ b/features/load.feature @@ -6,7 +6,7 @@ Feature: load features Scenario: load features within path Given a feature path "features" When I parse features - Then I should have 10 feature files: + Then I should have 11 feature files: """ features/background.feature features/events.feature @@ -18,6 +18,7 @@ Feature: load features features/outline.feature features/run.feature features/snippets.feature + features/tags.feature """ Scenario: load a specific feature file diff --git a/features/outline.feature b/features/outline.feature index 7c4f92e..dd24966 100644 --- a/features/outline.feature +++ b/features/outline.feature @@ -150,3 +150,4 @@ Feature: run outline | path | scen | | features/load.feature:6 | 1 | | features/load.feature | 6 | + diff --git a/features/tags.feature b/features/tags.feature new file mode 100644 index 0000000..06e3f20 --- /dev/null +++ b/features/tags.feature @@ -0,0 +1,126 @@ +Feature: tag filters + In order to test application behavior + As a test suite + I need to be able to filter features and scenarios by tags + + Scenario: should filter outline examples by tags + Given a feature "normal.feature" file: + """ + Feature: outline + + Background: + Given passing step + + Scenario Outline: parse a scenario + Given a feature path "" + When I parse features + Then I should have scenario registered + + Examples: + | path | num | + | features/load.feature:3 | 0 | + + @used + Examples: + | path | num | + | features/load.feature:6 | 1 | + """ + When I run feature suite with tags "@used" + Then the suite should have passed + And the following steps should be passed: + """ + I parse features + a feature path "features/load.feature:6" + I should have 1 scenario registered + """ + And I should have 1 scenario registered + + Scenario: should filter scenarios by X tag + Given a feature "normal.feature" file: + """ + Feature: tagged + + @x + Scenario: one + Given a feature path "one" + + @x + Scenario: two + Given a feature path "two" + + @x @y + Scenario: three + Given a feature path "three" + + @y + Scenario: four + Given a feature path "four" + """ + When I run feature suite with tags "@x" + Then the suite should have passed + And I should have 3 scenario registered + And the following steps should be passed: + """ + a feature path "one" + a feature path "two" + a feature path "three" + """ + + Scenario: should filter scenarios by X tag not having Y + Given a feature "normal.feature" file: + """ + Feature: tagged + + @x + Scenario: one + Given a feature path "one" + + @x + Scenario: two + Given a feature path "two" + + @x @y + Scenario: three + Given a feature path "three" + + @y @z + Scenario: four + Given a feature path "four" + """ + When I run feature suite with tags "@x && ~@y" + Then the suite should have passed + And I should have 2 scenario registered + And the following steps should be passed: + """ + a feature path "one" + a feature path "two" + """ + + Scenario: should filter scenarios having Y and Z tags + Given a feature "normal.feature" file: + """ + Feature: tagged + + @x + Scenario: one + Given a feature path "one" + + @x + Scenario: two + Given a feature path "two" + + @x @y + Scenario: three + Given a feature path "three" + + @y @z + Scenario: four + Given a feature path "four" + """ + When I run feature suite with tags "@y && @z" + Then the suite should have passed + And I should have 1 scenario registered + And the following steps should be passed: + """ + a feature path "four" + """ diff --git a/suite.go b/suite.go index a3c75de..643e172 100644 --- a/suite.go +++ b/suite.go @@ -716,7 +716,6 @@ func filterFeatures(tags string, collected map[string]*feature) (features []*fea } ft.ScenarioDefinitions = scenarios applyTagFilter(tags, ft.Feature) - features = append(features, ft) } @@ -732,8 +731,22 @@ func applyTagFilter(tags string, ft *gherkin.Feature) { var scenarios []interface{} for _, scenario := range ft.ScenarioDefinitions { - if matchesTags(tags, allTags(ft, scenario)) { - scenarios = append(scenarios, scenario) + switch t := scenario.(type) { + case *gherkin.ScenarioOutline: + var allExamples []*gherkin.Examples + for _, examples := range t.Examples { + if matchesTags(tags, allTags(ft, t, examples)) { + allExamples = append(allExamples, examples) + } + } + t.Examples = allExamples + if len(t.Examples) > 0 { + scenarios = append(scenarios, scenario) + } + case *gherkin.Scenario: + if matchesTags(tags, allTags(ft, t)) { + scenarios = append(scenarios, scenario) + } } } ft.ScenarioDefinitions = scenarios diff --git a/suite_context.go b/suite_context.go index d07bc99..35470f4 100644 --- a/suite_context.go +++ b/suite_context.go @@ -39,6 +39,7 @@ func SuiteContext(s *Suite, additionalContextInitializers ...func(suite *Suite)) s.Step(`^I parse features$`, c.parseFeatures) s.Step(`^I'm listening to suite events$`, c.iAmListeningToSuiteEvents) s.Step(`^I run feature suite$`, c.iRunFeatureSuite) + s.Step(`^I run feature suite with tags "([^"]*)"$`, c.iRunFeatureSuiteWithTags) s.Step(`^I run feature suite with formatter "([^"]*)"$`, c.iRunFeatureSuiteWithFormatter) s.Step(`^(?:a )?feature "([^"]*)"(?: file)?:$`, c.aFeatureFile) s.Step(`^the suite should have (passed|failed)$`, c.theSuiteShouldHave) @@ -114,6 +115,19 @@ func (s *suiteContext) ResetBeforeEachScenario(interface{}) { s.events = []*firedEvent{} } +func (s *suiteContext) iRunFeatureSuiteWithTags(tags string) error { + if err := s.parseFeatures(); err != nil { + return err + } + for _, feat := range s.testedSuite.features { + applyTagFilter(tags, feat.Feature) + } + s.testedSuite.fmt = testFormatterFunc("godog", &s.out) + s.testedSuite.run() + s.testedSuite.fmt.Summary() + return nil +} + func (s *suiteContext) iRunFeatureSuiteWithFormatter(name string) error { f := FindFmt(name) if f == nil {