diff --git a/.github/workflows/gorelease.yml b/.github/workflows/gorelease.yml index 445ad3e..a733761 100644 --- a/.github/workflows/gorelease.yml +++ b/.github/workflows/gorelease.yml @@ -8,7 +8,7 @@ jobs: gorelease: strategy: matrix: - go-version: [ 1.16.x ] + go-version: [ 1.17.x ] runs-on: ubuntu-latest steps: - name: Install Go @@ -38,7 +38,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} header: gorelease message: | - ### Exported API Changes Report + ### API Changes
${{ steps.gorelease.outputs.report }} diff --git a/.github/workflows/test-unit.yml b/.github/workflows/test-unit.yml index 7304bfc..79ed0f6 100644 --- a/.github/workflows/test-unit.yml +++ b/.github/workflows/test-unit.yml @@ -13,7 +13,7 @@ jobs: test: strategy: matrix: - go-version: [ 1.13.x, 1.14.x, 1.15.x, 1.16.x ] + go-version: [ 1.13.x, 1.14.x, 1.15.x, 1.16.x, 1.17.x ] runs-on: ubuntu-latest steps: - name: Install Go @@ -35,7 +35,7 @@ jobs: restore-keys: | ${{ runner.os }}-go-cache - name: Restore base test coverage - if: matrix.go-version == '1.16.x' + if: matrix.go-version == '1.17.x' uses: actions/cache@v2 with: path: | @@ -43,13 +43,13 @@ jobs: # Use base sha for PR or new commit hash for master/main push in test result key. key: ${{ runner.os }}-unit-test-coverage-${{ (github.event.pull_request.base.sha != github.event.after) && github.event.pull_request.base.sha || github.event.after }} - name: Checkout base code - if: matrix.go-version == '1.16.x' && env.RUN_BASE_COVERAGE == 'on' && steps.benchmark-base.outputs.cache-hit != 'true' && github.event.pull_request.base.sha != '' + if: matrix.go-version == '1.17.x' && env.RUN_BASE_COVERAGE == 'on' && steps.benchmark-base.outputs.cache-hit != 'true' && github.event.pull_request.base.sha != '' uses: actions/checkout@v2 with: ref: ${{ github.event.pull_request.base.sha }} path: __base - name: Run test for base code - if: matrix.go-version == '1.16.x' && env.RUN_BASE_COVERAGE == 'on' && steps.benchmark-base.outputs.cache-hit != 'true' && github.event.pull_request.base.sha != '' + if: matrix.go-version == '1.17.x' && env.RUN_BASE_COVERAGE == 'on' && steps.benchmark-base.outputs.cache-hit != 'true' && github.event.pull_request.base.sha != '' run: | cd __base make | grep test-unit && (make test-unit && go tool cover -func=./unit.coverprofile | sed -e 's/.go:[0-9]*:\t/.go\t/g' | sed -e 's/\t\t*/\t/g' > ../unit-base.txt) || echo "No test-unit in base" @@ -69,7 +69,7 @@ jobs: if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' }} run: cp unit.txt unit-base.txt - name: Comment Test Coverage - if: matrix.go-version == '1.16.x' + if: matrix.go-version == '1.17.x' uses: marocchino/sticky-pull-request-comment@v2 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -85,7 +85,7 @@ jobs: - name: Upload code coverage - if: matrix.go-version == '1.16.x' + if: matrix.go-version == '1.17.x' uses: codecov/codecov-action@v1 with: file: ./unit.coverprofile diff --git a/README.md b/README.md index b59eb76..437d583 100644 --- a/README.md +++ b/README.md @@ -18,3 +18,37 @@ failing scenarios. skipped steps after the failure was encountered. You can enable it by calling `godogx.RegisterPrettyFailedFormatter()`. + +## Allure Formatter + +[Allure](https://github.com/allure-framework/allure2) is convenient UI to expose test results. + +You can enable it by calling `allure.RegisterFormatter()`. + +Additional configuration can be added with env vars before test run. + +`ALLURE_ENV_*` are added to allure environment report. + +`ALLURE_EXECUTOR_*` configure `Executor` info. + +`ALLURE_RESULTS_PATH` can change default `./allure-results` destination. + +Example: +```bash +export ALLURE_ENV_TICKET=JIRA-1234 +export ALLURE_ENV_APP=todo-list +export ALLURE_EXECUTOR_NAME=IntegrationTest +export ALLURE_EXECUTOR_TYPE=github +``` + +Then you can run test with +```bash +# Optionally clean up current result (if you have it). +rm -rf ./allure-results/* +# Optionally copy history from previous report. +cp -r ./allure-report/history ./allure-results/history +# Run suite with godog CLI tool or with go test. +godog -f allure +# Generate report with allure CLI tool. +allure generate --clean +``` \ No newline at end of file diff --git a/allure/allure_test.go b/allure/allure_test.go new file mode 100644 index 0000000..3074056 --- /dev/null +++ b/allure/allure_test.go @@ -0,0 +1,33 @@ +package allure_test + +import ( + "bytes" + "errors" + "testing" + + "github.com/bool64/godogx/allure" + "github.com/cucumber/godog" + "github.com/stretchr/testify/assert" +) + +func TestRegister(t *testing.T) { + allure.RegisterFormatter() + + out := bytes.NewBuffer(nil) + + suite := godog.TestSuite{ + ScenarioInitializer: func(s *godog.ScenarioContext) { + s.Step("I pass", func() {}) + s.Step("I fail", func() error { return errors.New("failed") }) + }, + Options: &godog.Options{ + Format: "allure", + Output: out, + NoColors: true, + Paths: []string{"../_testdata"}, + }, + } + + st := suite.Run() + assert.Equal(t, 1, st) // Failed. +} diff --git a/allure/doc.go b/allure/doc.go new file mode 100644 index 0000000..47ba2b0 --- /dev/null +++ b/allure/doc.go @@ -0,0 +1,2 @@ +// Package allure provides allure formatter for godog. +package allure diff --git a/allure/executor.go b/allure/executor.go new file mode 100644 index 0000000..6ac5e7f --- /dev/null +++ b/allure/executor.go @@ -0,0 +1,25 @@ +package allure + +// Executor describes execution context. +type Executor struct { + Name string `json:"name,omitempty" example:"Jenkins"` + // Type may be one of [github, gitlab, teamcity, bamboo, jenkins] or a custom one. + Type string `json:"type,omitempty" example:"jenkins"` + URL string `json:"url,omitempty" example:"url"` + BuildOrder int `json:"buildOrder,omitempty" example:"13"` + BuildName string `json:"buildName,omitempty" example:"allure-report_deploy#13"` + BuildURL string `json:"buildUrl,omitempty" example:"http://example.org/build#13"` + ReportURL string `json:"reportUrl,omitempty" example:"http://example.org/build#13/AllureReport"` + ReportName string `json:"reportName,omitempty" example:"Demo allure report"` +} + +//{ +// "name": "Jenkins", +// "type": "jenkins", +// "url": "http://example.org", +// "buildOrder": 13, +// "buildName": "allure-report_deploy#13", +// "buildUrl": "http://example.org/build#13", +// "reportUrl": "http://example.org/build#13/AllureReport", +// "reportName": "Demo allure report" +//} diff --git a/allure/formatter.go b/allure/formatter.go new file mode 100644 index 0000000..e0faa02 --- /dev/null +++ b/allure/formatter.go @@ -0,0 +1,281 @@ +package allure + +import ( + "bytes" + "encoding/csv" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "strconv" + "strings" + "sync" + "time" + + "github.com/cucumber/godog" + "github.com/cucumber/godog/formatters" + "github.com/google/uuid" +) + +var ( + // Exec allows configuring execution context information. + Exec Executor + + // ResultsPath controls report destination. + ResultsPath = os.Getenv("ALLURE_RESULTS_PATH") + + formatterRegister sync.Once +) + +// RegisterFormatter adds allure to available formatters. +func RegisterFormatter() { + formatterRegister.Do(func() { + if ResultsPath == "" { + ResultsPath = "./allure-results" + } + + godog.Format("allure", "Allure formatter.", + func(suite string, writer io.Writer) formatters.Formatter { + if suite == "" { + suite = "Features" + } + + return &formatter{ + resultsPath: strings.TrimSuffix(ResultsPath, "/"), + container: &Container{ + UUID: uuid.New().String(), + Start: getTimestampMs(), + Name: suite, + }, + BaseFmt: godog.NewBaseFmt(suite, writer), + } + }) + }) +} + +type formatter struct { + container *Container + res *Result + lastTime TimestampMs + resultsPath string + + *godog.BaseFmt +} + +func (f *formatter) writeResult(r *Result) { + f.lastTime = getTimestampMs() + + r.Stage = "finished" + r.Stop = f.lastTime + f.container.Children = append(f.container.Children, r.UUID) + + f.writeJSON(fmt.Sprintf("%s-result.json", r.UUID), r) +} + +// TestRunStarted prepares test result directory. +func (f *formatter) TestRunStarted() { + err := os.MkdirAll(f.resultsPath, 0o700) + if err != nil { + log.Fatal("failed create allure results directory:", err) + } +} + +// Pickle receives scenario. +func (f *formatter) Pickle(scenario *godog.Scenario) { + if f.res != nil { + f.writeResult(f.res) + } + + f.lastTime = getTimestampMs() + + feature := f.Storage.MustGetFeature(scenario.Uri) + + f.res = &Result{ + UUID: uuid.New().String(), + Name: scenario.Name, + HistoryID: feature.Feature.Name + ": " + scenario.Name, + FullName: scenario.Uri + ":" + scenario.Name, + Description: scenario.Uri, + Start: f.lastTime, + Labels: []Label{ + {Name: "feature", Value: feature.Feature.Name}, + {Name: "suite", Value: f.container.Name}, + {Name: "framework", Value: "godog"}, + {Name: "language", Value: "Go"}, + }, + } +} + +func getTimestampMs() TimestampMs { + return TimestampMs(time.Now().UnixNano() / int64(time.Millisecond)) +} + +const ( + csvMime = "text/csv" +) + +func mediaType(t string) string { + switch t { + case "json": + return "application/json" + case "xml": + return "application/xml" + case "csv": + return csvMime + default: + return "text/plain" + } +} + +func (f *formatter) argumentAttachment(st *godog.Step) *Attachment { + if st.Argument == nil { + return nil + } + + if st.Argument.DocString != nil { + att, err := NewAttachment("Doc", mediaType(st.Argument.DocString.MediaType), + f.resultsPath, []byte(st.Argument.DocString.Content)) + if err != nil { + log.Fatal("failed to create attachment:", err) + } + + return att + } else if st.Argument.DataTable != nil { + mt := csvMime + buf := bytes.NewBuffer(nil) + c := csv.NewWriter(buf) + + for _, r := range st.Argument.DataTable.Rows { + var rec []string + for _, cell := range r.Cells { + rec = append(rec, cell.Value) + } + if err := c.Write(rec); err != nil { + log.Fatal("failed write csv row:", err) + } + } + c.Flush() + + att, err := NewAttachment("Table", mt, f.resultsPath, buf.Bytes()) + if err != nil { + log.Fatal("failed create table attachment:", err) + } + + return att + } + + return nil +} + +func (f *formatter) step(st *godog.Step) Step { + step := Step{ + Name: st.Text, + Stage: "finished", + Start: f.lastTime, + } + + if att := f.argumentAttachment(st); att != nil { + step.Attachments = append(step.Attachments, *att) + } + + f.lastTime = getTimestampMs() + step.Stop = f.lastTime + + return step +} + +// Passed captures passed step. +func (f *formatter) Passed(_ *godog.Scenario, st *godog.Step, _ *godog.StepDefinition) { + step := f.step(st) + step.Status = Passed + f.res.Steps = append(f.res.Steps, step) + f.res.Status = Passed +} + +// Skipped captures skipped step. +func (f *formatter) Skipped(_ *godog.Scenario, st *godog.Step, _ *godog.StepDefinition) { + step := f.step(st) + step.Status = Skipped + f.res.Steps = append(f.res.Steps, step) +} + +// Undefined captures undefined step. +func (f *formatter) Undefined(_ *godog.Scenario, st *godog.Step, _ *godog.StepDefinition) { + step := f.step(st) + step.Status = Broken + + f.res.Steps = append(f.res.Steps, step) +} + +// Failed captures failed step. +func (f *formatter) Failed(_ *godog.Scenario, st *godog.Step, _ *godog.StepDefinition, err error) { + details := &StatusDetails{ + Message: err.Error(), + } + + step := f.step(st) + step.Status = Failed + step.StatusDetails = details + + f.res.Steps = append(f.res.Steps, step) + f.res.Status = Failed + f.res.StatusDetails = details +} + +// Pending captures pending step. +func (f *formatter) Pending(*godog.Scenario, *godog.Step, *godog.StepDefinition) { +} + +func (f *formatter) writeJSON(name string, v interface{}) { + j, err := json.Marshal(v) + if err != nil { + log.Fatal("failed to marshal json value:", err) + } + + if err := ioutil.WriteFile(f.resultsPath+"/"+name, j, 0o600); err != nil { + log.Fatal("failed to write a file:", err) + } +} + +// Summary finishes report. +func (f *formatter) Summary() { + if f.res != nil { + f.writeResult(f.res) + } + + f.container.Stop = getTimestampMs() + + f.writeJSON(f.container.UUID+"-container.json", f.container) + + // Populate from env vars. + if Exec.Name == "" { + Exec.Name = os.Getenv("ALLURE_EXECUTOR_NAME") + Exec.Type = os.Getenv("ALLURE_EXECUTOR_TYPE") + Exec.URL = os.Getenv("ALLURE_EXECUTOR_URL") + Exec.BuildOrder, _ = strconv.Atoi(os.Getenv("ALLURE_EXECUTOR_BUILD_ORDER")) // nolint:errcheck + Exec.BuildName = os.Getenv("ALLURE_EXECUTOR_BUILD_NAME") + Exec.BuildURL = os.Getenv("ALLURE_EXECUTOR_BUILD_URL") + Exec.ReportName = os.Getenv("ALLURE_EXECUTOR_REPORT_NAME") + Exec.ReportURL = os.Getenv("ALLURE_EXECUTOR_REPORT_URL") + } + + if Exec.Name != "" { + f.writeJSON("executor.json", Exec) + } + + var env []byte + + for _, l := range os.Environ() { + if strings.HasPrefix(l, "ALLURE_ENV_") { + env = append(env, []byte(strings.TrimPrefix(l, "ALLURE_ENV_")+"\n")...) + } + } + + if len(env) > 0 { + if err := ioutil.WriteFile(f.resultsPath+"/environment.properties", env, 0o600); err != nil { + log.Fatal("failed to write a file:", err) + } + } +} diff --git a/allure/result.go b/allure/result.go new file mode 100644 index 0000000..3c1524c --- /dev/null +++ b/allure/result.go @@ -0,0 +1,148 @@ +package allure + +import ( + "fmt" + "io/ioutil" + + "github.com/google/uuid" +) + +// Container lists all results. +type Container struct { + UUID string `json:"uuid,omitempty"` + Name string `json:"name"` + Children []string `json:"children"` + Start TimestampMs `json:"start,omitempty"` + Stop TimestampMs `json:"stop,omitempty"` +} + +// Result is the top level report object for a test. +// +// 18 known properties: "start", "descriptionHtml", "parameters", "name", "historyId", +// "statusDetails", "status", "links", "fullName", "uuid", "description", "testCaseId", +// "stage", "labels", "stop", "steps", "rerunOf", "attachments". +type Result struct { + UUID string `json:"uuid,omitempty"` + HistoryID string `json:"historyId,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Status Status `json:"status,omitempty"` + StatusDetails *StatusDetails `json:"statusDetails,omitempty"` + Stage string `json:"stage,omitempty"` // "finished" + Steps []Step `json:"steps,omitempty"` + Attachments []Attachment `json:"attachments,omitempty"` + Parameters []Parameter `json:"parameters,omitempty"` + Start TimestampMs `json:"start,omitempty"` + Stop TimestampMs `json:"stop,omitempty"` + Children []string `json:"children,omitempty"` + FullName string `json:"fullName,omitempty"` + Labels []Label `json:"labels,omitempty"` + Links []Link `json:"links,omitempty"` +} + +// Available statuses. +const ( + Broken = Status("broken") + Passed = Status("passed") + Failed = Status("failed") + Skipped = Status("skipped") + Unknown = Status("unknown") +) + +// TimestampMs is a timestamp in milliseconds. +type TimestampMs int64 + +// LinkType is a type of link. +type LinkType string + +// Types of links. +const ( + Issue LinkType = "issue" + TMS LinkType = "tms" + Custom LinkType = "custom" +) + +// Link references additional resources. +type Link struct { + Name string `json:"name,omitempty"` + Type LinkType `json:"type,omitempty"` + URL string `json:"url,omitempty"` +} + +// Status describes test result. +type Status string + +// StatusDetails provides additional information on status. +type StatusDetails struct { + Known bool `json:"known,omitempty"` + Muted bool `json:"muted,omitempty"` + Flaky bool `json:"flaky,omitempty"` + Message string `json:"message,omitempty"` + Trace string `json:"trace,omitempty"` +} + +// Step is a part of scenario result. +type Step struct { + Name string `json:"name,omitempty"` + Status Status `json:"status,omitempty"` + StatusDetails *StatusDetails `json:"statusDetails,omitempty"` + Stage string `json:"stage"` + ChildrenSteps []Step `json:"steps"` + Attachments []Attachment `json:"attachments"` + Parameters []Parameter `json:"parameters"` + Start TimestampMs `json:"start"` + Stop TimestampMs `json:"stop"` +} + +// Attachment can be attached. +type Attachment struct { + Name string `json:"name"` + Source string `json:"source"` + Type string `json:"type"` +} + +// NewAttachment creates and stores attachment. +func NewAttachment(name string, mimeType string, resultsPath string, content []byte) (*Attachment, error) { + var ext string + + switch mimeType { + case "application/json": + ext = ".json" + case "image/png": + ext = ".png" + case "image/jpeg": + ext = ".jpg" + case "image/gif": + ext = ".gif" + case csvMime: + ext = ".csv" + case "application/xml": + ext = ".xml" + default: + ext = ".txt" + } + + a := Attachment{ + Name: name, + Type: mimeType, + Source: fmt.Sprintf("%s-attachment%s", uuid.New().String(), ext), + } + + if err := ioutil.WriteFile(fmt.Sprintf("%s/%s", resultsPath, a.Source), content, 0o600); err != nil { + return nil, err + } + + return &a, nil +} + +// Parameter is a named value. +type Parameter struct { + Name string `json:"name,omitempty"` + Value string `json:"value,omitempty"` +} + +// Label is a named value. +type Label struct { + Name string `json:"name,omitempty"` + Value string `json:"value,omitempty"` +} diff --git a/go.mod b/go.mod index cdea0bd..fe0aed4 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,8 @@ module github.com/bool64/godogx go 1.13 require ( - github.com/bool64/dev v0.1.37 - github.com/cucumber/godog v0.12.0-rc2.0.20210815195939-92ea38e7ce8d + github.com/bool64/dev v0.1.38 + github.com/cucumber/godog v0.12.0 + github.com/google/uuid v1.3.0 github.com/stretchr/testify v1.7.0 ) diff --git a/go.sum b/go.sum index f2b240d..cc445bf 100644 --- a/go.sum +++ b/go.sum @@ -23,8 +23,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/bool64/dev v0.1.37 h1:/c8U4emt4xjMDx8Au+POOYo5LJIw+Mzi4e48j5CmGQo= -github.com/bool64/dev v0.1.37/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2zRWU= +github.com/bool64/dev v0.1.38 h1:RJZlSdbIDW/2RAQykcMziptk4zx/UcZD3n36HU4Zivo= +github.com/bool64/dev v0.1.38/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2zRWU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -35,8 +35,8 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cucumber/gherkin-go/v19 v19.0.3 h1:mMSKu1077ffLbTJULUfM5HPokgeBcIGboyeNUof1MdE= github.com/cucumber/gherkin-go/v19 v19.0.3/go.mod h1:jY/NP6jUtRSArQQJ5h1FXOUgk5fZK24qtE7vKi776Vw= -github.com/cucumber/godog v0.12.0-rc2.0.20210815195939-92ea38e7ce8d h1:dch/okb8/EavnI5TM3nzpYeuGtB1Rx3F15bIFkFGd6U= -github.com/cucumber/godog v0.12.0-rc2.0.20210815195939-92ea38e7ce8d/go.mod h1:u6SD7IXC49dLpPN35kal0oYEjsXZWee4pW6Tm9t5pIc= +github.com/cucumber/godog v0.12.0 h1:xVOc9ML+1joT0CqcdQTpfXiT7G1hOLbCmlUnYOyJ80w= +github.com/cucumber/godog v0.12.0/go.mod h1:u6SD7IXC49dLpPN35kal0oYEjsXZWee4pW6Tm9t5pIc= github.com/cucumber/messages-go/v16 v16.0.0/go.mod h1:EJcyR5Mm5ZuDsKJnT2N9KRnBK30BGjtYotDKpwQ0v6g= github.com/cucumber/messages-go/v16 v16.0.1 h1:fvkpwsLgnIm0qugftrw2YwNlio+ABe2Iu94Ap8GMYIY= github.com/cucumber/messages-go/v16 v16.0.1/go.mod h1:EJcyR5Mm5ZuDsKJnT2N9KRnBK30BGjtYotDKpwQ0v6g= @@ -73,6 +73,8 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= diff --git a/pretty_failed.go b/pretty_failed.go index 7c03d6e..b1365d9 100644 --- a/pretty_failed.go +++ b/pretty_failed.go @@ -53,7 +53,7 @@ func (p *prettyFailedFormatter) Pickle(scenario *godog.Scenario) { p.PrettyFmt.Pickle(scenario) } -func (p *prettyFailedFormatter) Feature(f *godog.Feature, ps string, c []byte) { +func (p *prettyFailedFormatter) Feature(f *godog.GherkinDocument, ps string, c []byte) { p.Lock.Lock() p.buf.Reset() p.Lock.Unlock()