From c50c2dc368011f4614e24735f2dd903d0ada6d15 Mon Sep 17 00:00:00 2001 From: gedi Date: Sun, 22 May 2016 17:40:42 +0300 Subject: [PATCH] initial tests for event stream formatter --- features/formatter/events.feature | 78 +++++++++++++++++++++++++++++++ features/lang.feature | 3 +- features/load.feature | 3 +- fmt_test.go | 17 ++++++- suite_test.go | 75 +++++++++++++++++++++++++---- 5 files changed, 163 insertions(+), 13 deletions(-) create mode 100644 features/formatter/events.feature diff --git a/features/formatter/events.feature b/features/formatter/events.feature new file mode 100644 index 0000000..d9c2b2a --- /dev/null +++ b/features/formatter/events.feature @@ -0,0 +1,78 @@ +Feature: event stream formatter + In order to have universal cucumber formatter + As a test suite + I need to be able to support event stream formatter + + Scenario: should fire only suite events without any scenario + Given a feature path "features/load.feature:4" + When I run feature suite with formatter "events" + Then the following events should be fired: + """ + TestRunStarted + TestSource + TestRunFinished + """ + + Scenario: should process simple scenario + Given a feature path "features/load.feature:21" + When I run feature suite with formatter "events" + Then the following events should be fired: + """ + TestRunStarted + TestSource + TestCaseStarted + StepDefinitionFound + TestStepStarted + TestStepFinished + StepDefinitionFound + TestStepStarted + TestStepFinished + StepDefinitionFound + TestStepStarted + TestStepFinished + TestCaseFinished + TestRunFinished + """ + + Scenario: should process outline scenario + Given a feature path "features/load.feature:29" + When I run feature suite with formatter "events" + Then the following events should be fired: + """ + TestRunStarted + TestSource + TestCaseStarted + StepDefinitionFound + TestStepStarted + TestStepFinished + StepDefinitionFound + TestStepStarted + TestStepFinished + StepDefinitionFound + TestStepStarted + TestStepFinished + TestCaseFinished + TestCaseStarted + StepDefinitionFound + TestStepStarted + TestStepFinished + StepDefinitionFound + TestStepStarted + TestStepFinished + StepDefinitionFound + TestStepStarted + TestStepFinished + TestCaseFinished + TestCaseStarted + StepDefinitionFound + TestStepStarted + TestStepFinished + StepDefinitionFound + TestStepStarted + TestStepFinished + StepDefinitionFound + TestStepStarted + TestStepFinished + TestCaseFinished + TestRunFinished + """ diff --git a/features/lang.feature b/features/lang.feature index 6f5b346..0cf35a0 100644 --- a/features/lang.feature +++ b/features/lang.feature @@ -8,10 +8,11 @@ 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 7 savybių failus: + Tada aš turėčiau turėti 8 savybių failus: """ features/background.feature features/events.feature + features/formatter/events.feature features/lang.feature features/load.feature features/outline.feature diff --git a/features/load.feature b/features/load.feature index ac434a1..f15cee1 100644 --- a/features/load.feature +++ b/features/load.feature @@ -6,10 +6,11 @@ Feature: load features Scenario: load features within path Given a feature path "features" When I parse features - Then I should have 7 feature files: + Then I should have 8 feature files: """ features/background.feature features/events.feature + features/formatter/events.feature features/lang.feature features/load.feature features/outline.feature diff --git a/fmt_test.go b/fmt_test.go index c8dc921..2614dcc 100644 --- a/fmt_test.go +++ b/fmt_test.go @@ -1,12 +1,27 @@ package godog -import "github.com/DATA-DOG/godog/gherkin" +import ( + "io" + "time" + + "github.com/DATA-DOG/godog/gherkin" +) type testFormatter struct { basefmt scenarios []interface{} } +func testFormatterFunc(out io.Writer) Formatter { + return &testFormatter{ + basefmt: basefmt{ + started: time.Now(), + indent: 2, + out: out, + }, + } +} + func (f *testFormatter) Node(node interface{}) { f.basefmt.Node(node) switch t := node.(type) { diff --git a/suite_test.go b/suite_test.go index 80e3543..b493e87 100644 --- a/suite_test.go +++ b/suite_test.go @@ -1,6 +1,8 @@ package godog import ( + "bytes" + "encoding/json" "fmt" "path/filepath" "strconv" @@ -18,6 +20,7 @@ func SuiteContext(s *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 formatter "([^"]*)"$`, c.iRunFeatureSuiteWithFormatter) s.Step(`^a feature "([^"]*)" file:$`, c.aFeatureFile) s.Step(`^the suite should have (passed|failed)$`, c.theSuiteShouldHave) @@ -32,6 +35,9 @@ func SuiteContext(s *Suite) { s.Step(`^the following steps? should be (passed|failed|skipped|undefined|pending):`, c.followingStepsShouldHave) s.Step(`^the undefined step snippets should be:$`, c.theUndefinedStepSnippetsShouldBe) + // event stream + s.Step(`^the following events should be fired:$`, c.thereShouldBeEventsFired) + // lt s.Step(`^savybių aplankas "([^"]*)"$`, c.featurePath) s.Step(`^aš išskaitau savybes$`, c.parseFeatures) @@ -54,20 +60,59 @@ type suiteContext struct { paths []string testedSuite *Suite events []*firedEvent - fmt *testFormatter + out bytes.Buffer } func (s *suiteContext) ResetBeforeEachScenario(interface{}) { // reset whole suite with the state - s.fmt = &testFormatter{} + s.out.Reset() s.paths = []string{} - s.testedSuite = &Suite{fmt: s.fmt} + s.testedSuite = &Suite{} // our tested suite will have the same context registered SuiteContext(s.testedSuite) // reset all fired events s.events = []*firedEvent{} } +func (s *suiteContext) iRunFeatureSuiteWithFormatter(name string) error { + f, err := findFmt(name) + if err != nil { + return err + } + s.testedSuite.fmt = f(&s.out) + if err := s.parseFeatures(); err != nil { + return err + } + s.testedSuite.run() + s.testedSuite.fmt.Summary() + return nil +} + +func (s *suiteContext) thereShouldBeEventsFired(doc *gherkin.DocString) error { + actual := strings.Split(strings.TrimSpace(s.out.String()), "\n") + expect := strings.Split(strings.TrimSpace(doc.Content), "\n") + if len(expect) != len(actual) { + return fmt.Errorf("expected %d events, but got %d", len(expect), len(actual)) + } + + type ev struct { + Event string + } + + for i, event := range actual { + exp := strings.TrimSpace(expect[i]) + var act ev + if err := json.Unmarshal([]byte(event), &act); err != nil { + return fmt.Errorf("failed to read event data: %v", err) + } + + if act.Event != exp { + return fmt.Errorf(`expected event: "%s" at position: %d, but actual was "%s"`, exp, i, act.Event) + } + } + return nil +} + func (s *suiteContext) cleanupSnippet(snip string) string { lines := strings.Split(strings.TrimSpace(snip), "\n") for i := 0; i < len(lines); i++ { @@ -77,10 +122,14 @@ func (s *suiteContext) cleanupSnippet(snip string) string { } func (s *suiteContext) theUndefinedStepSnippetsShouldBe(body *gherkin.DocString) error { - actual := s.cleanupSnippet(s.fmt.snippets()) + f, ok := s.testedSuite.fmt.(*testFormatter) + if !ok { + return fmt.Errorf("this step requires testFormatter, but there is: %T", s.testedSuite.fmt) + } + actual := s.cleanupSnippet(f.snippets()) expected := s.cleanupSnippet(body.Content) if actual != expected { - return fmt.Errorf("snippets do not match actual: %s", s.fmt.snippets()) + return fmt.Errorf("snippets do not match actual: %s", f.snippets()) } return nil } @@ -89,25 +138,29 @@ func (s *suiteContext) followingStepsShouldHave(status string, steps *gherkin.Do var expected = strings.Split(steps.Content, "\n") var actual, unmatched, matched []string + f, ok := s.testedSuite.fmt.(*testFormatter) + if !ok { + return fmt.Errorf("this step requires testFormatter, but there is: %T", s.testedSuite.fmt) + } switch status { case "passed": - for _, st := range s.fmt.passed { + for _, st := range f.passed { actual = append(actual, st.step.Text) } case "failed": - for _, st := range s.fmt.failed { + for _, st := range f.failed { actual = append(actual, st.step.Text) } case "skipped": - for _, st := range s.fmt.skipped { + for _, st := range f.skipped { actual = append(actual, st.step.Text) } case "undefined": - for _, st := range s.fmt.undefined { + for _, st := range f.undefined { actual = append(actual, st.step.Text) } case "pending": - for _, st := range s.fmt.pending { + for _, st := range f.pending { actual = append(actual, st.step.Text) } default: @@ -231,7 +284,9 @@ func (s *suiteContext) iRunFeatureSuite() error { if err := s.parseFeatures(); err != nil { return err } + s.testedSuite.fmt = testFormatterFunc(&s.out) s.testedSuite.run() + s.testedSuite.fmt.Summary() return nil }