Added features/formatter/pretty.feature

Этот коммит содержится в:
Fredrik Lönnblad 2020-02-10 19:55:44 -03:00
родитель 58d12bc7e6
коммит de8b0f071b
17 изменённых файлов: 1205 добавлений и 5042 удалений

Просмотреть файл

@ -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:24" Given a feature path "features/load.feature:25"
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:32" Given a feature path "features/load.feature:33"
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:
""" """

288
features/formatter/pretty.feature Обычный файл
Просмотреть файл

@ -0,0 +1,288 @@
Feature: pretty formatter
In order to support tools that import pretty output
I need to be able to support pretty formatted output
Scenario: Support of Feature Plus Scenario Node
Given a feature "features/simple.feature" file:
"""
Feature: simple feature
simple feature description
Scenario: simple scenario
simple scenario description
"""
When I run feature suite with formatter "pretty"
Then the rendered output will be as follows:
"""
Feature: simple feature
simple feature description
Scenario: simple scenario # features/simple.feature:3
1 scenarios (1 undefined)
No steps
0s
"""
Scenario: Support of Feature Plus Scenario Node With Tags
Given a feature "features/simple.feature" file:
"""
@TAG1
Feature: simple feature
simple feature description
@TAG2 @TAG3
Scenario: simple scenario
simple scenario description
"""
When I run feature suite with formatter "pretty"
Then the rendered output will be as follows:
"""
Feature: simple feature
simple feature description
Scenario: simple scenario # features/simple.feature:5
1 scenarios (1 undefined)
No steps
0s
"""
Scenario: Support of Feature Plus Scenario Outline
Given a feature "features/simple.feature" file:
"""
Feature: simple feature
simple feature description
Scenario Outline: simple scenario
simple scenario description
Examples: simple examples
| status |
| pass |
| fail |
"""
When I run feature suite with formatter "pretty"
Then the rendered output will be as follows:
"""
Feature: simple feature
simple feature description
Scenario Outline: simple scenario # features/simple.feature:4
Examples: simple examples
| status |
| pass |
| fail |
2 scenarios (2 undefined)
No steps
0s
"""
Scenario: Support of Feature Plus Scenario Outline With Tags
Given a feature "features/simple.feature" file:
"""
@TAG1
Feature: simple feature
simple feature description
@TAG2
Scenario Outline: simple scenario
simple scenario description
@TAG3
Examples: simple examples
| status |
| pass |
| fail |
"""
When I run feature suite with formatter "pretty"
Then the rendered output will be as follows:
"""
Feature: simple feature
simple feature description
Scenario Outline: simple scenario # features/simple.feature:6
Examples: simple examples
| status |
| pass |
| fail |
2 scenarios (2 undefined)
No steps
0s
"""
Scenario: Support of Feature Plus Scenario With Steps
Given a feature "features/simple.feature" file:
"""
Feature: simple feature
simple feature description
Scenario: simple scenario
simple scenario description
Given passing step
Then a failing step
"""
When I run feature suite with formatter "pretty"
Then the rendered output will be as follows:
"""
Feature: simple feature
simple feature description
Scenario: simple scenario # features/simple.feature:4
Given passing step # suite_context.go:72 -> github.com/cucumber/godog.SuiteContext.func2
Then a failing step # suite_context.go:318 -> *suiteContext
intentional failure
--- Failed steps:
Scenario: simple scenario # features/simple.feature:4
Then a failing step # features/simple.feature:8
Error: intentional failure
1 scenarios (1 failed)
2 steps (1 passed, 1 failed)
0s
"""
Scenario: Support of Feature Plus Scenario Outline With Steps
Given a feature "features/simple.feature" file:
"""
Feature: simple feature
simple feature description
Scenario Outline: simple scenario
simple scenario description
Given <status> step
Examples: simple examples
| status |
| passing |
| failing |
"""
When I run feature suite with formatter "pretty"
Then the rendered output will be as follows:
"""
Feature: simple feature
simple feature description
Scenario Outline: simple scenario # features/simple.feature:4
Given <status> step # suite_context.go:72 -> github.com/cucumber/godog.SuiteContext.func2
Examples: simple examples
| status |
| passing |
| failing |
intentional failure
--- Failed steps:
Scenario Outline: simple scenario # features/simple.feature:4
Given failing step # features/simple.feature:7
Error: intentional failure
2 scenarios (1 passed, 1 failed)
2 steps (1 passed, 1 failed)
0s
"""
# Currently godog only supports comments on Feature and not
# scenario and steps.
Scenario: Support of Comments
Given a feature "features/simple.feature" file:
"""
#Feature comment
Feature: simple feature
simple description
Scenario: simple scenario
simple feature description
"""
When I run feature suite with formatter "pretty"
Then the rendered output will be as follows:
"""
Feature: simple feature
simple description
Scenario: simple scenario # features/simple.feature:5
1 scenarios (1 undefined)
No steps
0s
"""
Scenario: Support of Docstrings
Given a feature "features/simple.feature" file:
"""
Feature: simple feature
simple description
Scenario: simple scenario
simple feature description
Given passing step
\"\"\" content type
step doc string
\"\"\"
"""
When I run feature suite with formatter "pretty"
Then the rendered output will be as follows:
"""
Feature: simple feature
simple description
Scenario: simple scenario # features/simple.feature:4
Given passing step # suite_context.go:72 -> github.com/cucumber/godog.SuiteContext.func2
\"\"\" content type
step doc string
\"\"\"
1 scenarios (1 passed)
1 steps (1 passed)
0s
"""
Scenario: Support of Undefined, Pending and Skipped status
Given a feature "features/simple.feature" file:
"""
Feature: simple feature
simple feature description
Scenario: simple scenario
simple scenario description
Given passing step
And pending step
And undefined
And passing step
"""
When I run feature suite with formatter "pretty"
Then the rendered output will be as follows:
"""
Feature: simple feature
simple feature description
Scenario: simple scenario # features/simple.feature:4
Given passing step # suite_context.go:72 -> github.com/cucumber/godog.SuiteContext.func2
And pending step # suite_context.go:69 -> github.com/cucumber/godog.SuiteContext.func1
TODO: write pending definition
And undefined
And passing step # suite_context.go:72 -> github.com/cucumber/godog.SuiteContext.func2
1 scenarios (1 pending, 1 undefined)
4 steps (1 passed, 1 pending, 1 undefined, 1 skipped)
0s
You can implement step definitions for undefined steps with these snippets:
func undefined() error {
return godog.ErrPending
}
func FeatureContext(s *godog.Suite) {
s.Step(`^undefined$`, undefined)
}
"""

Просмотреть файл

@ -8,12 +8,13 @@ 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 11 savybių failus: Tada aš turėčiau turėti 12 savybių failus:
""" """
features/background.feature features/background.feature
features/events.feature features/events.feature
features/formatter/cucumber.feature features/formatter/cucumber.feature
features/formatter/events.feature features/formatter/events.feature
features/formatter/pretty.feature
features/lang.feature features/lang.feature
features/load.feature features/load.feature
features/multistep.feature features/multistep.feature

Просмотреть файл

@ -6,12 +6,13 @@ 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 11 feature files: Then I should have 12 feature files:
""" """
features/background.feature features/background.feature
features/events.feature features/events.feature
features/formatter/cucumber.feature features/formatter/cucumber.feature
features/formatter/events.feature features/formatter/events.feature
features/formatter/pretty.feature
features/lang.feature features/lang.feature
features/load.feature features/load.feature
features/multistep.feature features/multistep.feature

Различия файлов не показаны, т.к. их слишком много Показать различия

Различия файлов не показаны, т.к. их слишком много Показать различия

Просмотреть файл

@ -1,7 +0,0 @@
// +build go1.12
package fixtures
const OutputFilenameProgress = "fixtures/progress_output.txt"
const OutputFilenameJUnit = "fixtures/junit_output.xml"
const OutputFilenameCucumber = "fixtures/cucumber_output.json"

Просмотреть файл

@ -1,7 +0,0 @@
// +build !go1.12
package fixtures
const OutputFilenameProgress = "fixtures/progress_output.txt"
const OutputFilenameJUnit = "fixtures/junit_output.xml"
const OutputFilenameCucumber = "fixtures/cucumber_output_go111.json"

Просмотреть файл

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<testsuites name="succeed" tests="60" skipped="0" failures="0" errors="0" time="0s"> <testsuites name="succeed" tests="69" skipped="0" failures="0" errors="0" time="0s">
<testsuite name="cucumber json formatter" tests="9" skipped="0" failures="0" errors="0" time="0s"> <testsuite name="cucumber json formatter" tests="9" skipped="0" failures="0" errors="0" time="0s">
<testcase name="Support of Feature Plus Scenario Node" status="passed" time="0s"></testcase> <testcase name="Support of Feature Plus Scenario Node" status="passed" time="0s"></testcase>
<testcase name="Support of Feature Plus Scenario Node With Tags" status="passed" time="0s"></testcase> <testcase name="Support of Feature Plus Scenario Node With Tags" status="passed" time="0s"></testcase>
@ -24,6 +24,17 @@
<testcase name="loaded feature should have a number of scenarios #3" status="passed" time="0s"></testcase> <testcase name="loaded feature should have a number of scenarios #3" status="passed" time="0s"></testcase>
<testcase name="load a number of feature files" status="passed" time="0s"></testcase> <testcase name="load a number of feature files" status="passed" time="0s"></testcase>
</testsuite> </testsuite>
<testsuite name="pretty formatter" tests="9" skipped="0" failures="0" errors="0" time="0s">
<testcase name="Support of Feature Plus Scenario Node" status="passed" time="0s"></testcase>
<testcase name="Support of Feature Plus Scenario Node With Tags" status="passed" time="0s"></testcase>
<testcase name="Support of Feature Plus Scenario Outline" status="passed" time="0s"></testcase>
<testcase name="Support of Feature Plus Scenario Outline With Tags" status="passed" time="0s"></testcase>
<testcase name="Support of Feature Plus Scenario With Steps" status="passed" time="0s"></testcase>
<testcase name="Support of Feature Plus Scenario Outline With Steps" status="passed" time="0s"></testcase>
<testcase name="Support of Comments" status="passed" time="0s"></testcase>
<testcase name="Support of Docstrings" status="passed" time="0s"></testcase>
<testcase name="Support of Undefined, Pending and Skipped status" status="passed" time="0s"></testcase>
</testsuite>
<testsuite name="run background" tests="3" skipped="0" failures="0" errors="0" time="0s"> <testsuite name="run background" tests="3" skipped="0" failures="0" errors="0" time="0s">
<testcase name="should run background steps" status="passed" time="0s"></testcase> <testcase name="should run background steps" status="passed" time="0s"></testcase>
<testcase name="should skip all consequent steps on failure" status="passed" time="0s"></testcase> <testcase name="should skip all consequent steps on failure" status="passed" time="0s"></testcase>

Просмотреть файл

@ -1,9 +1,9 @@
...................................................................... 70 ...................................................................... 70
...................................................................... 140 ...................................................................... 140
...................................................................... 210 ...................................................................... 210
....................................... 249 .................................................................. 276
60 scenarios (60 passed) 69 scenarios (69 passed)
249 steps (249 passed) 276 steps (276 passed)
0s 0s

Просмотреть файл

@ -76,14 +76,6 @@ func FeatureContext(s *godog.Suite) {
shouldMatchOutput(expected, actual, t) shouldMatchOutput(expected, actual, t)
} }
func trimAllLines(s string) string {
var lines []string
for _, ln := range strings.Split(strings.TrimSpace(s), "\n") {
lines = append(lines, strings.TrimSpace(ln))
}
return strings.Join(lines, "\n")
}
var basicGherkinFeature = ` var basicGherkinFeature = `
Feature: basic Feature: basic
@ -114,7 +106,7 @@ func TestProgressFormatterWhenStepPanics(t *testing.T) {
} }
out := buf.String() out := buf.String()
if idx := strings.Index(out, "godog/fmt_progress_test.go:108"); idx == -1 { if idx := strings.Index(out, "godog/fmt_progress_test.go:100"); idx == -1 {
t.Fatalf("expected to find panic stacktrace, actual:\n%s", out) t.Fatalf("expected to find panic stacktrace, actual:\n%s", out)
} }
} }

2
go.mod
Просмотреть файл

@ -1,3 +1,5 @@
module github.com/cucumber/godog module github.com/cucumber/godog
go 1.13 go 1.13
require github.com/stretchr/testify v1.4.0

11
go.sum
Просмотреть файл

@ -0,0 +1,11 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

Просмотреть файл

@ -6,11 +6,14 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"regexp"
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/cucumber/godog/colors" "github.com/cucumber/godog/colors"
"github.com/cucumber/godog/fixtures"
"github.com/cucumber/godog/gherkin" "github.com/cucumber/godog/gherkin"
) )
@ -52,16 +55,12 @@ func TestPrintsNoStepDefinitionsIfNoneFound(t *testing.T) {
s.printStepDefinitions(w) s.printStepDefinitions(w)
out := strings.TrimSpace(buf.String()) out := strings.TrimSpace(buf.String())
if out != "there were no contexts registered, could not find any step definition.." { assert.Equal(t, "there were no contexts registered, could not find any step definition..", out)
t.Fatalf("expected output does not match to: %s", out)
}
} }
func TestFailsOrPassesBasedOnStrictModeWhenHasPendingSteps(t *testing.T) { func TestFailsOrPassesBasedOnStrictModeWhenHasPendingSteps(t *testing.T) {
feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature)) feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err)
}
r := runner{ r := runner{
fmt: progressFunc("progress", ioutil.Discard), fmt: progressFunc("progress", ioutil.Discard),
@ -72,21 +71,15 @@ func TestFailsOrPassesBasedOnStrictModeWhenHasPendingSteps(t *testing.T) {
}, },
} }
if r.run() { assert.False(t, r.run())
t.Fatal("the suite should have passed")
}
r.strict = true r.strict = true
if !r.run() { assert.True(t, r.run())
t.Fatal("the suite should have failed")
}
} }
func TestFailsOrPassesBasedOnStrictModeWhenHasUndefinedSteps(t *testing.T) { func TestFailsOrPassesBasedOnStrictModeWhenHasUndefinedSteps(t *testing.T) {
feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature)) feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err)
}
r := runner{ r := runner{
fmt: progressFunc("progress", ioutil.Discard), fmt: progressFunc("progress", ioutil.Discard),
@ -97,21 +90,15 @@ func TestFailsOrPassesBasedOnStrictModeWhenHasUndefinedSteps(t *testing.T) {
}, },
} }
if r.run() { assert.False(t, r.run())
t.Fatal("the suite should have passed")
}
r.strict = true r.strict = true
if !r.run() { assert.True(t, r.run())
t.Fatal("the suite should have failed")
}
} }
func TestShouldFailOnError(t *testing.T) { func TestShouldFailOnError(t *testing.T) {
feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature)) feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err)
}
r := runner{ r := runner{
fmt: progressFunc("progress", ioutil.Discard), fmt: progressFunc("progress", ioutil.Discard),
@ -122,9 +109,7 @@ func TestShouldFailOnError(t *testing.T) {
}, },
} }
if !r.run() { assert.True(t, r.run())
t.Fatal("the suite should have failed")
}
} }
func TestFailsWithConcurrencyOptionError(t *testing.T) { func TestFailsWithConcurrencyOptionError(t *testing.T) {
@ -140,20 +125,15 @@ func TestFailsWithConcurrencyOptionError(t *testing.T) {
} }
status := RunWithOptions("fails", func(_ *Suite) {}, opt) status := RunWithOptions("fails", func(_ *Suite) {}, opt)
if status != exitOptionError { require.Equal(t, exitOptionError, status)
t.Fatalf("expected exit status to be 2, but was: %d", status)
}
closer() closer()
b, err := ioutil.ReadAll(stderr) b, err := ioutil.ReadAll(stderr)
if err != nil { require.NoError(t, err)
t.Fatal(err)
}
out := strings.TrimSpace(string(b)) out := strings.TrimSpace(string(b))
if out != `format "pretty" does not support concurrent execution` { assert.Equal(t, `format "pretty" does not support concurrent execution`, out)
t.Fatalf("unexpected error output: \"%s\"", out)
}
} }
func TestFailsWithUnknownFormatterOptionError(t *testing.T) { func TestFailsWithUnknownFormatterOptionError(t *testing.T) {
@ -168,20 +148,15 @@ func TestFailsWithUnknownFormatterOptionError(t *testing.T) {
} }
status := RunWithOptions("fails", func(_ *Suite) {}, opt) status := RunWithOptions("fails", func(_ *Suite) {}, opt)
if status != exitOptionError { require.Equal(t, exitOptionError, status)
t.Fatalf("expected exit status to be 2, but was: %d", status)
}
closer() closer()
b, err := ioutil.ReadAll(stderr) b, err := ioutil.ReadAll(stderr)
if err != nil { require.NoError(t, err)
t.Fatal(err)
}
out := strings.TrimSpace(string(b)) out := strings.TrimSpace(string(b))
if !strings.Contains(out, `unregistered formatter name: "unknown", use one of`) { assert.Contains(t, out, `unregistered formatter name: "unknown", use one of`)
t.Fatalf("unexpected error output: %q", out)
}
} }
func TestFailsWithOptionErrorWhenLookingForFeaturesInUnavailablePath(t *testing.T) { func TestFailsWithOptionErrorWhenLookingForFeaturesInUnavailablePath(t *testing.T) {
@ -196,20 +171,15 @@ func TestFailsWithOptionErrorWhenLookingForFeaturesInUnavailablePath(t *testing.
} }
status := RunWithOptions("fails", func(_ *Suite) {}, opt) status := RunWithOptions("fails", func(_ *Suite) {}, opt)
if status != exitOptionError { require.Equal(t, exitOptionError, status)
t.Fatalf("expected exit status to be 2, but was: %d", status)
}
closer() closer()
b, err := ioutil.ReadAll(stderr) b, err := ioutil.ReadAll(stderr)
if err != nil { require.NoError(t, err)
t.Fatal(err)
}
out := strings.TrimSpace(string(b)) out := strings.TrimSpace(string(b))
if out != `feature path "unavailable" is not available` { assert.Equal(t, `feature path "unavailable" is not available`, out)
t.Fatalf("unexpected error output: \"%s\"", out)
}
} }
func TestByDefaultRunsFeaturesPath(t *testing.T) { func TestByDefaultRunsFeaturesPath(t *testing.T) {
@ -221,24 +191,18 @@ func TestByDefaultRunsFeaturesPath(t *testing.T) {
status := RunWithOptions("fails", func(_ *Suite) {}, opt) status := RunWithOptions("fails", func(_ *Suite) {}, opt)
// should fail in strict mode due to undefined steps // should fail in strict mode due to undefined steps
if status != exitFailure { assert.Equal(t, exitFailure, status)
t.Fatalf("expected exit status to be 1, but was: %d", status)
}
opt.Strict = false opt.Strict = false
status = RunWithOptions("succeeds", func(_ *Suite) {}, opt) status = RunWithOptions("succeeds", func(_ *Suite) {}, opt)
// should succeed in non strict mode due to undefined steps // should succeed in non strict mode due to undefined steps
if status != exitSuccess { assert.Equal(t, exitSuccess, status)
t.Fatalf("expected exit status to be 0, but was: %d", status)
}
} }
func bufErrorPipe(t *testing.T) (io.ReadCloser, func()) { func bufErrorPipe(t *testing.T) (io.ReadCloser, func()) {
stderr := os.Stderr stderr := os.Stderr
r, w, err := os.Pipe() r, w, err := os.Pipe()
if err != nil { require.NoError(t, err)
t.Fatal(err)
}
os.Stderr = w os.Stderr = w
return r, func() { return r, func() {
@ -266,14 +230,10 @@ func TestFeatureFilePathParser(t *testing.T) {
{"D:\\home\\test.feature:3", "D:\\home\\test.feature", 3}, {"D:\\home\\test.feature:3", "D:\\home\\test.feature", 3},
} }
for i, c := range cases { for _, c := range cases {
p, ln := extractFeaturePathLine(c.input) p, ln := extractFeaturePathLine(c.input)
if p != c.path { assert.Equal(t, p, c.path)
t.Fatalf(`result path "%s" != "%s" at %d`, p, c.path, i) assert.Equal(t, ln, c.line)
}
if ln != c.line {
t.Fatalf(`result line "%d" != "%d" at %d`, ln, c.line, i)
}
} }
} }
@ -285,16 +245,14 @@ type succeedRunTestCase struct {
func TestSucceedRun(t *testing.T) { func TestSucceedRun(t *testing.T) {
testCases := []succeedRunTestCase{ testCases := []succeedRunTestCase{
{format: "progress", concurrency: 4, filename: fixtures.OutputFilenameProgress}, {format: "progress", concurrency: 4, filename: "fixtures/progress_output.txt"},
{format: "junit", concurrency: 4, filename: fixtures.OutputFilenameJUnit}, {format: "junit", concurrency: 4, filename: "fixtures/junit_output.xml"},
{format: "cucumber", concurrency: 2, filename: fixtures.OutputFilenameCucumber}, {format: "cucumber", concurrency: 2, filename: "fixtures/cucumber_output.json"},
} }
for _, tc := range testCases { for _, tc := range testCases {
expectedOutput, err := ioutil.ReadFile(tc.filename) expectedOutput, err := ioutil.ReadFile(tc.filename)
if err != nil { require.NoError(t, err)
t.Fatal(err)
}
for concurrency := range make([]int, tc.concurrency) { for concurrency := range make([]int, tc.concurrency) {
t.Run( t.Run(
@ -319,17 +277,16 @@ func testSucceedRun(t *testing.T, format string, concurrency int, expectedOutput
} }
status := RunWithOptions("succeed", func(s *Suite) { SuiteContext(s) }, opt) status := RunWithOptions("succeed", func(s *Suite) { SuiteContext(s) }, opt)
if status != exitSuccess { require.Equal(t, exitSuccess, status)
t.Fatalf("expected exit status to be 0, but was: %d", status)
}
b, err := ioutil.ReadAll(output) b, err := ioutil.ReadAll(output)
if err != nil { require.NoError(t, err)
t.Fatal(err)
}
out := strings.TrimSpace(string(b)) actual := strings.TrimSpace(string(b))
if out != expectedOutput {
t.Fatalf("unexpected output: \"%s\"", out) suiteCtxReg := regexp.MustCompile(`suite_context.go:\d+`)
} expectedOutput = suiteCtxReg.ReplaceAllString(expectedOutput, `suite_context.go:0`)
actual = suiteCtxReg.ReplaceAllString(actual, `suite_context.go:0`)
assert.Equalf(t, expectedOutput, actual, "[%s]", actual)
} }

Просмотреть файл

@ -11,6 +11,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/cucumber/godog/colors"
"github.com/cucumber/godog/gherkin" "github.com/cucumber/godog/gherkin"
) )
@ -74,6 +75,9 @@ func SuiteContext(s *Suite, additionalContextInitializers ...func(suite *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)
// Introduced to test formatter/pretty.feature
s.Step(`^the rendered output will be as follows:$`, c.theRenderOutputWillBe)
s.Step(`^(?:a )?failing multistep$`, func() Steps { s.Step(`^(?:a )?failing multistep$`, func() Steps {
return Steps{"passing step", "failing step"} return Steps{"passing step", "failing step"}
}) })
@ -133,7 +137,8 @@ func (s *suiteContext) iRunFeatureSuiteWithFormatter(name string) error {
if f == nil { if f == nil {
return fmt.Errorf(`formatter "%s" is not available`, name) return fmt.Errorf(`formatter "%s" is not available`, name)
} }
s.testedSuite.fmt = f("godog", &s.out)
s.testedSuite.fmt = f("godog", colors.Uncolored(&s.out))
if err := s.parseFeatures(); err != nil { if err := s.parseFeatures(); err != nil {
return err return err
} }
@ -457,14 +462,14 @@ func (s *suiteContext) theseEventsHadToBeFiredForNumberOfTimes(tbl *gherkin.Data
} }
func (s *suiteContext) theRenderJSONWillBe(docstring *gherkin.DocString) error { func (s *suiteContext) theRenderJSONWillBe(docstring *gherkin.DocString) error {
loc := regexp.MustCompile(`"suite_context.go:\d+"`) suiteCtxReg := regexp.MustCompile(`suite_context.go:\d+`)
var expected []cukeFeatureJSON var expected []cukeFeatureJSON
if err := json.Unmarshal([]byte(loc.ReplaceAllString(docstring.Content, `"suite_context.go:0"`)), &expected); err != nil { if err := json.Unmarshal([]byte(suiteCtxReg.ReplaceAllString(docstring.Content, `suite_context.go:0`)), &expected); err != nil {
return err return err
} }
var actual []cukeFeatureJSON var actual []cukeFeatureJSON
replaced := loc.ReplaceAllString(s.out.String(), `"suite_context.go:0"`) replaced := suiteCtxReg.ReplaceAllString(s.out.String(), `suite_context.go:0`)
if err := json.Unmarshal([]byte(replaced), &actual); err != nil { if err := json.Unmarshal([]byte(replaced), &actual); err != nil {
return err return err
} }
@ -475,6 +480,21 @@ func (s *suiteContext) theRenderJSONWillBe(docstring *gherkin.DocString) error {
return nil return nil
} }
func (s *suiteContext) theRenderOutputWillBe(docstring *gherkin.DocString) error {
suiteCtxReg := regexp.MustCompile(`suite_context.go:\d+`)
expected := trimAllLines(strings.TrimSpace(docstring.Content))
expected = suiteCtxReg.ReplaceAllString(expected, `suite_context.go:0`)
actual := trimAllLines(strings.TrimSpace(s.out.String()))
actual = suiteCtxReg.ReplaceAllString(actual, `suite_context.go:0`)
if expected != actual {
return fmt.Errorf("expected output\n%s\ndoes not match actual:\n%s\n", expected, actual)
}
return nil
}
type testFormatter struct { type testFormatter struct {
basefmt basefmt
scenarios []interface{} scenarios []interface{}

Просмотреть файл

@ -1,46 +0,0 @@
package godog
import (
"os"
"strings"
"testing"
"time"
)
func TestMain(m *testing.M) {
format := "progress" // non verbose mode
concurrency := 4
var specific bool
for _, arg := range os.Args[1:] {
if arg == "-test.v=true" { // go test transforms -v option - verbose mode
format = "pretty"
concurrency = 1
break
}
if strings.Index(arg, "-test.run") == 0 {
specific = true
}
}
var status int
if !specific {
status = RunWithOptions("godog", func(s *Suite) {
GodogContext(s)
}, Options{
Format: format, // pretty format for verbose mode, otherwise - progress
Paths: []string{"features"},
Concurrency: concurrency, // concurrency for verbose mode is 1
Randomize: time.Now().UnixNano(), // randomize scenario execution order
})
}
if st := m.Run(); st > status {
status = st
}
os.Exit(status)
}
// needed in order to use godog cli
func GodogContext(s *Suite) {
SuiteContext(s)
}

Просмотреть файл

@ -26,3 +26,11 @@ func s(n int) string {
var timeNowFunc = func() time.Time { var timeNowFunc = func() time.Time {
return time.Now() return time.Now()
} }
func trimAllLines(s string) string {
var lines []string
for _, ln := range strings.Split(strings.TrimSpace(s), "\n") {
lines = append(lines, strings.TrimSpace(ln))
}
return strings.Join(lines, "\n")
}