diff --git a/fmt.go b/fmt.go index 476708c..5a92fbf 100644 --- a/fmt.go +++ b/fmt.go @@ -306,16 +306,21 @@ func (f *basefmt) Summary() { switch t := def.(type) { case *gherkin.Scenario: total++ + if len(t.Steps) == 0 { + undefined++ + } case *gherkin.ScenarioOutline: for _, ex := range t.Examples { if examples, hasExamples := examples(ex); hasExamples { total += len(examples.TableBody) + if len(t.Steps) == 0 { + undefined += len(examples.TableBody) + } } } } } } - passed = total var owner interface{} for _, undef := range f.undefined { if owner != undef.owner { @@ -323,6 +328,7 @@ func (f *basefmt) Summary() { owner = undef.owner } } + passed = total - undefined var steps, parts, scenarios []string nsteps := len(f.passed) + len(f.failed) + len(f.skipped) + len(f.undefined) + len(f.pending) @@ -343,6 +349,9 @@ func (f *basefmt) Summary() { passed -= undefined parts = append(parts, yellow(fmt.Sprintf("%d undefined", undefined))) steps = append(steps, yellow(fmt.Sprintf("%d undefined", len(f.undefined)))) + } else if undefined > 0 { + // there may be some scenarios without steps + parts = append(parts, yellow(fmt.Sprintf("%d undefined", undefined))) } if len(f.skipped) > 0 { steps = append(steps, cyan(fmt.Sprintf("%d skipped", len(f.skipped)))) diff --git a/fmt_pretty.go b/fmt_pretty.go index c4a888e..b13956d 100644 --- a/fmt_pretty.go +++ b/fmt_pretty.go @@ -58,7 +58,7 @@ func (f *pretty) Feature(ft *gherkin.Feature, p string, c []byte) { fmt.Fprintln(f.out, "") } f.features = append(f.features, &feature{Path: p, Feature: ft}) - fmt.Fprintln(f.out, whiteb(ft.Keyword+": ")+ft.Name) + fmt.Fprintln(f.out, whiteb(ft.Keyword+":")+" "+ft.Name) if strings.TrimSpace(ft.Description) != "" { for _, line := range strings.Split(ft.Description, "\n") { fmt.Fprintln(f.out, s(f.indent)+strings.TrimSpace(line)) @@ -115,7 +115,7 @@ func (f *pretty) printUndefinedScenario(sc *gherkin.Scenario) { } f.commentPos = f.longestStep(sc.Steps, f.length(sc)) - text := s(f.indent) + whiteb(f.scenario.Keyword+": ") + sc.Name + text := s(f.indent) + whiteb(f.scenario.Keyword+":") + " " + sc.Name text += s(f.commentPos-f.length(f.scenario)+1) + f.line(sc.Location) fmt.Fprintln(f.out, "\n"+text) } @@ -209,7 +209,7 @@ func (f *pretty) printOutlineExample(outline *gherkin.ScenarioOutline) { // an example table header if firstExample { fmt.Fprintln(f.out, "") - fmt.Fprintln(f.out, s(f.indent*2)+whiteb(example.Keyword+": ")+example.Name) + fmt.Fprintln(f.out, s(f.indent*2)+whiteb(example.Keyword+":")+" "+example.Name) for i, cell := range example.TableHeader.Cells { val := cyan(cell.Value) @@ -306,7 +306,7 @@ func (f *pretty) printStepKind(res *stepResult) { f.commentPos = bgLen } } - text := s(f.indent) + whiteb(f.scenario.Keyword+": ") + f.scenario.Name + text := s(f.indent) + whiteb(f.scenario.Keyword+":") + " " + f.scenario.Name text += s(f.commentPos-f.length(f.scenario)+1) + f.line(f.scenario.Location) fmt.Fprintln(f.out, "\n"+text) f.scenarioKeyword = true diff --git a/formatter-tests/pretty/empty b/formatter-tests/pretty/empty index 97faafc..3850b84 100644 --- a/formatter-tests/pretty/empty +++ b/formatter-tests/pretty/empty @@ -1 +1,5 @@ -Feature: empty feature +Feature: empty feature + +No scenarios +No steps +0s diff --git a/formatter-tests/pretty/empty_with_description b/formatter-tests/pretty/empty_with_description new file mode 100644 index 0000000..6ae0404 --- /dev/null +++ b/formatter-tests/pretty/empty_with_description @@ -0,0 +1,8 @@ +Feature: empty feature + describes + an empty + feature + +No scenarios +No steps +0s diff --git a/formatter-tests/pretty/empty_with_single_scenario_without_steps b/formatter-tests/pretty/empty_with_single_scenario_without_steps new file mode 100644 index 0000000..bcff7b1 --- /dev/null +++ b/formatter-tests/pretty/empty_with_single_scenario_without_steps @@ -0,0 +1,7 @@ +Feature: empty feature + + Scenario: without steps # formatter-tests/features/empty_with_single_scenario_without_steps.feature:3 + +1 scenarios (1 undefined) +No steps +0s diff --git a/formatter-tests/pretty/empty_with_single_scenario_without_steps_and_description b/formatter-tests/pretty/empty_with_single_scenario_without_steps_and_description new file mode 100644 index 0000000..9ac0800 --- /dev/null +++ b/formatter-tests/pretty/empty_with_single_scenario_without_steps_and_description @@ -0,0 +1,10 @@ +Feature: empty feature + describes + an empty + feature + + Scenario: without steps # formatter-tests/features/empty_with_single_scenario_without_steps_and_description.feature:6 + +1 scenarios (1 undefined) +No steps +0s diff --git a/formatter-tests/pretty/single_scenario_with_passing_step b/formatter-tests/pretty/single_scenario_with_passing_step new file mode 100644 index 0000000..e0dcf32 --- /dev/null +++ b/formatter-tests/pretty/single_scenario_with_passing_step @@ -0,0 +1,11 @@ +Feature: single passing scenario + describes + a single scenario + feature + + Scenario: one step passing # formatter-tests/features/single_scenario_with_passing_step.feature:6 + Given a passing step # formatters_print_test.go:35 -> github.com/DATA-DOG/godog.TestPrintingFormatters.func4 + +1 scenarios (1 passed) +1 steps (1 passed) +0s diff --git a/formatters_print_test.go b/formatters_print_test.go index 5d7c8c5..8b4bd51 100644 --- a/formatters_print_test.go +++ b/formatters_print_test.go @@ -1 +1,66 @@ package godog + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "strings" + "testing" +) + +func TestPrintingFormatters(t *testing.T) { + features, err := parseFeatures("", []string{"formatter-tests"}) + if err != nil { + t.Fatalf("failed to parse formatter features: %v", err) + } + + var buf bytes.Buffer + out := &tagColorWriter{w: &buf} + + suite := &Suite{ + features: features, + } + + suite.Step(`^(?:a )?failing step`, func() error { + return fmt.Errorf("step failed") + }) + suite.Step(`^this step should fail`, func() error { + return fmt.Errorf("step failed") + }) + suite.Step(`^(?:a )?pending step$`, func() error { + return ErrPending + }) + suite.Step(`^(?:a )?passing step$`, func() error { + return nil + }) + + for _, feat := range features { + for name := range AvailableFormatters() { + expectOutputPath := strings.Replace(feat.Path, "features", name, 1) + expectOutputPath = strings.TrimRight(expectOutputPath, ".feature") + if _, err := os.Stat(expectOutputPath); err != nil { + continue + } + + buf.Reset() // flush the output + suite.fmt = FindFmt(name)(name, out) // prepare formatter + suite.features = []*feature{feat} // set the feature + + expectedOutput, err := ioutil.ReadFile(expectOutputPath) + if err != nil { + t.Fatal(err) + } + + suite.run() + suite.fmt.Summary() + + expected := string(expectedOutput) + actual := buf.String() + + if actual != expected { + t.Fatalf("%s does not match to:\n%s", expectOutputPath, actual) + } + } + } +}