Added comments to feature node.
Fixed duration Fix defect is example id
Этот коммит содержится в:
родитель
afc629be69
коммит
7c9f5bfb02
1 изменённых файлов: 98 добавлений и 60 удалений
128
fmt_cucumber.go
128
fmt_cucumber.go
|
@ -7,6 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"github.com/DATA-DOG/godog/gherkin"
|
"github.com/DATA-DOG/godog/gherkin"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
const cukeurl = "https://www.relishapp.com/cucumber/cucumber/docs/formatters/json-output-formatter"
|
const cukeurl = "https://www.relishapp.com/cucumber/cucumber/docs/formatters/json-output-formatter"
|
||||||
|
@ -32,6 +33,10 @@ func makeId(name string) string {
|
||||||
return strings.Replace(strings.ToLower(name), " ", "-", -1)
|
return strings.Replace(strings.ToLower(name), " ", "-", -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type cukeComment struct {
|
||||||
|
Value string `json:"value"`
|
||||||
|
Line int `json:"line"`
|
||||||
|
}
|
||||||
type cukeTag struct {
|
type cukeTag struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Line int `json:"line"`
|
Line int `json:"line"`
|
||||||
|
@ -39,15 +44,14 @@ type cukeTag struct {
|
||||||
|
|
||||||
type cukeResult struct {
|
type cukeResult struct {
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Duration int `json:"duration"`
|
|
||||||
Error string `json:"error_message,omitempty"`
|
Error string `json:"error_message,omitempty"`
|
||||||
|
Duration int `json:"duration"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type cukeMatch struct {
|
type cukeMatch struct {
|
||||||
Location string `json:"location"`
|
Location string `json:"location"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type cukeStep struct {
|
type cukeStep struct {
|
||||||
Keyword string `json:"keyword"`
|
Keyword string `json:"keyword"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
@ -57,13 +61,13 @@ type cukeStep struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type cukeElement struct {
|
type cukeElement struct {
|
||||||
Keyword string `json:"keyword"`
|
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
|
Keyword string `json:"keyword"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Line int `json:"line"`
|
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Tags []cukeTag `json:"tags"`
|
Line int `json:"line"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
Tags []cukeTag `json:"tags,omitempty"`
|
||||||
Steps []cukeStep `json:"steps"`
|
Steps []cukeStep `json:"steps"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,9 +76,10 @@ type cukeFeatureJson struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
Keyword string `json:"keyword"`
|
Keyword string `json:"keyword"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Line int `json:"line"`
|
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Tags []cukeTag `json:"tags"`
|
Line int `json:"line"`
|
||||||
|
Comments []cukeComment `json:"comments,omitempty"`
|
||||||
|
Tags []cukeTag `json:"tags,omitempty"`
|
||||||
Elements []cukeElement `json:"elements"`
|
Elements []cukeElement `json:"elements"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,6 +100,10 @@ type cukefmt struct {
|
||||||
curFeature *cukeFeatureJson // track the current feature
|
curFeature *cukeFeatureJson // track the current feature
|
||||||
curOutline cukeElement // Each example show up as an outline element but the outline is parsed only once
|
curOutline cukeElement // Each example show up as an outline element but the outline is parsed only once
|
||||||
// so I need to keep track of the current outline
|
// so I need to keep track of the current outline
|
||||||
|
curRow int // current row of the example table as it is being processed.
|
||||||
|
curExampleTags []cukeTag // temporary storage for tags associate with the current example table.
|
||||||
|
startTime time.Time
|
||||||
|
curExampleName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *cukefmt) Node(n interface{}) {
|
func (f *cukefmt) Node(n interface{}) {
|
||||||
|
@ -102,53 +111,80 @@ func (f *cukefmt) Node(n interface{}) {
|
||||||
|
|
||||||
switch t := n.(type) {
|
switch t := n.(type) {
|
||||||
|
|
||||||
|
// When the example definition is seen we just need track the id and
|
||||||
|
// append the name associated with the example as part of the id.
|
||||||
case *gherkin.Examples:
|
case *gherkin.Examples:
|
||||||
fmt.Fprintln("Examples")
|
f.curExampleName = makeId(t.Name)
|
||||||
saveElement := f.curElement
|
f.curRow = 2 // there can be more than one example set per outline so reset row count.
|
||||||
|
// cucumber counts the header row as an example when creating the id.
|
||||||
|
|
||||||
f.curElement.Id = f.curElement.Id + ";" + makeId(t.Name)
|
// store any example level tags in a temp location.
|
||||||
f.curFeature.Elements = append(f.curFeature.Elements, f.curElement)
|
f.curExampleTags = make([]cukeTag, len(t.Tags))
|
||||||
|
for idx, element := range t.Tags {
|
||||||
f.curElement = saveElement
|
f.curExampleTags[idx].Line = element.Location.Line
|
||||||
|
f.curExampleTags[idx].Name = element.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// The outline node creates a placeholder and the actual element is added as each TableRow is processed.
|
||||||
case *gherkin.ScenarioOutline:
|
case *gherkin.ScenarioOutline:
|
||||||
fmt.Fprintln("Outline")
|
|
||||||
//f.curFeature.Elements = append(f.curFeature.Elements, cukeElement{})
|
|
||||||
//f.curElement = &f.curFeature.Elements[len(f.curFeature.Elements) - 1]
|
|
||||||
|
|
||||||
f.curElement=cukeElement{}
|
f.curOutline = cukeElement{}
|
||||||
f.curElement.Name = t.Name
|
f.curOutline.Name = t.Name
|
||||||
f.curElement.Line = t.Location.Line
|
f.curOutline.Line = t.Location.Line
|
||||||
f.curElement.Description = t.Description
|
f.curOutline.Description = t.Description
|
||||||
f.curElement.Keyword = t.Keyword
|
f.curOutline.Keyword = t.Keyword
|
||||||
f.curElement.Id = f.curFeature.Id + ";" + makeId(t.Name)
|
f.curOutline.Id = f.curFeature.Id + ";" + makeId(t.Name)
|
||||||
f.curElement.Type = "scenario"
|
f.curOutline.Type = "scenario"
|
||||||
f.curElement.Tags = make([]cukeTag, len(t.Tags))
|
f.curOutline.Tags = make([]cukeTag, len(t.Tags) + len(f.curFeature.Tags))
|
||||||
|
|
||||||
|
// apply feature level tags
|
||||||
|
if (len(f.curOutline.Tags) > 0) {
|
||||||
|
copy(f.curOutline.Tags, f.curFeature.Tags)
|
||||||
|
|
||||||
|
// apply outline level tags.
|
||||||
for idx, element := range t.Tags {
|
for idx, element := range t.Tags {
|
||||||
f.curElement.Tags[idx].Line = element.Location.Line
|
f.curOutline.Tags[idx + len(f.curFeature.Tags)].Line = element.Location.Line
|
||||||
f.curElement.Tags[idx].Name = element.Name
|
f.curOutline.Tags[idx + len(f.curFeature.Tags)].Name = element.Name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This scenario adds the element to the output immediately.
|
||||||
case *gherkin.Scenario:
|
case *gherkin.Scenario:
|
||||||
fmt.Fprintln("Scenario")
|
f.curFeature.Elements = append(f.curFeature.Elements, cukeElement{})
|
||||||
|
f.curElement = &f.curFeature.Elements[len(f.curFeature.Elements) - 1]
|
||||||
|
|
||||||
f.curElement = cukeElement{}
|
|
||||||
f.curElement.Name = t.Name
|
f.curElement.Name = t.Name
|
||||||
f.curElement.Line = t.Location.Line
|
f.curElement.Line = t.Location.Line
|
||||||
f.curElement.Description = t.Description
|
f.curElement.Description = t.Description
|
||||||
f.curElement.Keyword = t.Keyword
|
f.curElement.Keyword = t.Keyword
|
||||||
f.curElement.Id = f.curFeature.Id + ";" + makeId(t.Name)
|
f.curElement.Id = f.curFeature.Id + ";" + makeId(t.Name)
|
||||||
f.curElement.Type = "scenario"
|
f.curElement.Type = "scenario"
|
||||||
f.curElement.Tags = make([]cukeTag, len(t.Tags))
|
f.curElement.Tags = make([]cukeTag, len(t.Tags) + len(f.curFeature.Tags))
|
||||||
for idx, element := range t.Tags {
|
|
||||||
f.curElement.Tags[idx].Line = element.Location.Line
|
|
||||||
f.curElement.Tags[idx].Name = element.Name
|
|
||||||
}
|
|
||||||
f.curFeature.Elements = append(f.curFeature.Elements, f.curElement)
|
|
||||||
|
|
||||||
|
if (len(f.curElement.Tags) > 0) {
|
||||||
|
// apply feature level tags
|
||||||
|
copy(f.curElement.Tags, f.curFeature.Tags)
|
||||||
|
|
||||||
|
// apply scenario level tags.
|
||||||
|
for idx, element := range t.Tags {
|
||||||
|
f.curElement.Tags[idx + len(f.curFeature.Tags)].Line = element.Location.Line
|
||||||
|
f.curElement.Tags[idx + len(f.curFeature.Tags)].Name = element.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This is an outline scenario and the element is added to the output as
|
||||||
|
// the TableRows are encountered.
|
||||||
case *gherkin.TableRow:
|
case *gherkin.TableRow:
|
||||||
lastElement := &f.curFeature.Elements[len(f.curFeature.Elements) - 1]
|
tmpElem := f.curOutline
|
||||||
lastElement.Id = lastElement.Id + ";cnt"
|
tmpElem.Line = t.Location.Line
|
||||||
|
tmpElem.Id = tmpElem.Id + ";" + f.curExampleName + ";" + strconv.Itoa(f.curRow)
|
||||||
|
f.curRow++
|
||||||
|
f.curFeature.Elements = append(f.curFeature.Elements, tmpElem)
|
||||||
|
f.curElement = &f.curFeature.Elements[len(f.curFeature.Elements) - 1]
|
||||||
|
|
||||||
|
// copy in example level tags.
|
||||||
|
f.curElement.Tags = append(f.curElement.Tags, f.curExampleTags...)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,10 +211,16 @@ func (f *cukefmt) Feature(ft *gherkin.Feature, p string, c []byte) {
|
||||||
f.curFeature.Tags[idx].Name = element.Name
|
f.curFeature.Tags[idx].Name = element.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.curFeature.Comments = make([]cukeComment, len(ft.Comments))
|
||||||
|
for idx, comment := range ft.Comments {
|
||||||
|
f.curFeature.Comments[idx].Value = comment.Text
|
||||||
|
f.curFeature.Comments[idx].Line = comment.Location.Line
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *cukefmt) Summary() {
|
func (f *cukefmt) Summary() {
|
||||||
dat, err := json.MarshalIndent(f.results, "", "\t")
|
dat, err := json.MarshalIndent(f.results, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -188,14 +230,16 @@ func (f *cukefmt) Summary() {
|
||||||
func (f *cukefmt) step(res *stepResult) {
|
func (f *cukefmt) step(res *stepResult) {
|
||||||
|
|
||||||
// determine if test case has finished
|
// determine if test case has finished
|
||||||
switch t:= f.owner.(type) {
|
switch t := f.owner.(type) {
|
||||||
case *gherkin.TableRow:
|
case *gherkin.TableRow:
|
||||||
|
f.curStep.Result.Duration = int(time.Since(f.startTime).Nanoseconds())
|
||||||
f.curStep.Line = t.Location.Line
|
f.curStep.Line = t.Location.Line
|
||||||
f.curStep.Result.Status = res.typ.String()
|
f.curStep.Result.Status = res.typ.String()
|
||||||
if res.err != nil {
|
if res.err != nil {
|
||||||
f.curStep.Result.Error = res.err.Error()
|
f.curStep.Result.Error = res.err.Error()
|
||||||
}
|
}
|
||||||
case *gherkin.Scenario:
|
case *gherkin.Scenario:
|
||||||
|
f.curStep.Result.Duration = int(time.Since(f.startTime).Nanoseconds())
|
||||||
f.curStep.Result.Status = res.typ.String()
|
f.curStep.Result.Status = res.typ.String()
|
||||||
if res.err != nil {
|
if res.err != nil {
|
||||||
f.curStep.Result.Error = res.err.Error()
|
f.curStep.Result.Error = res.err.Error()
|
||||||
|
@ -204,17 +248,11 @@ func (f *cukefmt) step(res *stepResult) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *cukefmt) Defined(step *gherkin.Step, def *StepDef) {
|
func (f *cukefmt) Defined(step *gherkin.Step, def *StepDef) {
|
||||||
fmt.Fprintf(f.out, "Defined: step:%v stepDef:%v\n", step, def)
|
|
||||||
|
|
||||||
|
f.startTime = time.Now() // start timing the step
|
||||||
f.curElement.Steps = append(f.curElement.Steps, cukeStep{})
|
f.curElement.Steps = append(f.curElement.Steps, cukeStep{})
|
||||||
f.curStep = &f.curElement.Steps[len(f.curElement.Steps) - 1]
|
f.curStep = &f.curElement.Steps[len(f.curElement.Steps) - 1]
|
||||||
|
|
||||||
if def != nil {
|
|
||||||
if def.args != nil {
|
|
||||||
fmt.Fprintf(f.out, "Argument: %v\n", def.args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f.curStep.Name = step.Text
|
f.curStep.Name = step.Text
|
||||||
f.curStep.Line = step.Location.Line
|
f.curStep.Line = step.Location.Line
|
||||||
f.curStep.Keyword = step.Keyword
|
f.curStep.Keyword = step.Keyword
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче