github.com/maps90/godog@v0.7.5-0.20170923143419-0093943021d4/fmt_progress_test.go (about)

     1  package godog
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/DATA-DOG/godog/colors"
    13  	"github.com/DATA-DOG/godog/gherkin"
    14  )
    15  
    16  func TestProgressFormatterOutput(t *testing.T) {
    17  	feat, err := gherkin.ParseFeature(strings.NewReader(sampleGherkinFeature))
    18  	if err != nil {
    19  		t.Fatalf("unexpected error: %v", err)
    20  	}
    21  
    22  	var buf bytes.Buffer
    23  	w := colors.Uncolored(&buf)
    24  	r := runner{
    25  		fmt: progressFunc("progress", w),
    26  		features: []*feature{&feature{
    27  			Path:    "any.feature",
    28  			Feature: feat,
    29  			Content: []byte(sampleGherkinFeature),
    30  		}},
    31  		initializer: func(s *Suite) {
    32  			s.Step(`^passing$`, func() error { return nil })
    33  			s.Step(`^failing$`, func() error { return fmt.Errorf("errored") })
    34  			s.Step(`^pending$`, func() error { return ErrPending })
    35  		},
    36  	}
    37  
    38  	expected := `
    39  ...F-.P-.UU.....F..P..U 23
    40  
    41  
    42  --- Failed steps:
    43  
    44      When failing # any.feature:11
    45  	  Error: errored
    46  
    47      When failing # any.feature:24
    48  	  Error: errored
    49  
    50  
    51  8 scenarios (2 passed, 2 failed, 2 pending, 2 undefined)
    52  23 steps (14 passed, 2 failed, 2 pending, 3 undefined, 2 skipped)
    53  %s
    54  
    55  Randomized with seed: %s
    56  
    57  You can implement step definitions for undefined steps with these snippets:
    58  
    59  func undefined() error {
    60  	return godog.ErrPending
    61  }
    62  
    63  func nextUndefined() error {
    64  	return godog.ErrPending
    65  }
    66  
    67  func FeatureContext(s *godog.Suite) {
    68  	s.Step(` + "`^undefined$`" + `, undefined)
    69  	s.Step(` + "`^next undefined$`" + `, nextUndefined)
    70  }`
    71  
    72  	var zeroDuration time.Duration
    73  	expected = fmt.Sprintf(expected, zeroDuration.String(), os.Getenv("GODOG_SEED"))
    74  	expected = trimAllLines(expected)
    75  
    76  	r.run()
    77  
    78  	actual := trimAllLines(buf.String())
    79  
    80  	shouldMatchOutput(expected, actual, t)
    81  }
    82  
    83  func trimAllLines(s string) string {
    84  	var lines []string
    85  	for _, ln := range strings.Split(strings.TrimSpace(s), "\n") {
    86  		lines = append(lines, strings.TrimSpace(ln))
    87  	}
    88  	return strings.Join(lines, "\n")
    89  }
    90  
    91  var basicGherkinFeature = `
    92  Feature: basic
    93  
    94    Scenario: passing scenario
    95  	When one
    96  	Then two
    97  `
    98  
    99  func TestProgressFormatterWhenStepPanics(t *testing.T) {
   100  	feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
   101  	if err != nil {
   102  		t.Fatalf("unexpected error: %v", err)
   103  	}
   104  
   105  	var buf bytes.Buffer
   106  	w := colors.Uncolored(&buf)
   107  	r := runner{
   108  		fmt:      progressFunc("progress", w),
   109  		features: []*feature{&feature{Feature: feat}},
   110  		initializer: func(s *Suite) {
   111  			s.Step(`^one$`, func() error { return nil })
   112  			s.Step(`^two$`, func() error { panic("omg") })
   113  		},
   114  	}
   115  
   116  	if !r.run() {
   117  		t.Fatal("the suite should have failed")
   118  	}
   119  
   120  	out := buf.String()
   121  	if idx := strings.Index(out, "github.com/DATA-DOG/godog/fmt_progress_test.go:116"); idx == -1 {
   122  		t.Fatalf("expected to find panic stacktrace, actual:\n%s", out)
   123  	}
   124  }
   125  
   126  func TestProgressFormatterWithPassingMultisteps(t *testing.T) {
   127  	feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
   128  	if err != nil {
   129  		t.Fatalf("unexpected error: %v", err)
   130  	}
   131  
   132  	var buf bytes.Buffer
   133  	w := colors.Uncolored(&buf)
   134  	r := runner{
   135  		fmt:      progressFunc("progress", w),
   136  		features: []*feature{&feature{Feature: feat}},
   137  		initializer: func(s *Suite) {
   138  			s.Step(`^sub1$`, func() error { return nil })
   139  			s.Step(`^sub-sub$`, func() error { return nil })
   140  			s.Step(`^sub2$`, func() Steps { return Steps{"sub-sub", "sub1", "one"} })
   141  			s.Step(`^one$`, func() error { return nil })
   142  			s.Step(`^two$`, func() Steps { return Steps{"sub1", "sub2"} })
   143  		},
   144  	}
   145  
   146  	if r.run() {
   147  		t.Fatal("the suite should have passed")
   148  	}
   149  }
   150  
   151  func TestProgressFormatterWithFailingMultisteps(t *testing.T) {
   152  	feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
   153  	if err != nil {
   154  		t.Fatalf("unexpected error: %v", err)
   155  	}
   156  
   157  	var buf bytes.Buffer
   158  	w := colors.Uncolored(&buf)
   159  	r := runner{
   160  		fmt:      progressFunc("progress", w),
   161  		features: []*feature{&feature{Feature: feat, Path: "some.feature"}},
   162  		initializer: func(s *Suite) {
   163  			s.Step(`^sub1$`, func() error { return nil })
   164  			s.Step(`^sub-sub$`, func() error { return fmt.Errorf("errored") })
   165  			s.Step(`^sub2$`, func() Steps { return Steps{"sub-sub", "sub1", "one"} })
   166  			s.Step(`^one$`, func() error { return nil })
   167  			s.Step(`^two$`, func() Steps { return Steps{"sub1", "sub2"} })
   168  		},
   169  	}
   170  
   171  	if !r.run() {
   172  		t.Fatal("the suite should have failed")
   173  	}
   174  
   175  	expected := `
   176  .F 2
   177  
   178  
   179  --- Failed steps:
   180  
   181  Then two # some.feature:6
   182  Error: sub2: sub-sub: errored
   183  
   184  
   185  1 scenarios (1 failed)
   186  2 steps (1 passed, 1 failed)
   187  %s
   188  
   189  Randomized with seed: %s
   190  `
   191  
   192  	expected = trimAllLines(expected)
   193  	var zeroDuration time.Duration
   194  	expected = fmt.Sprintf(expected, zeroDuration.String(), os.Getenv("GODOG_SEED"))
   195  	actual := trimAllLines(buf.String())
   196  
   197  	shouldMatchOutput(expected, actual, t)
   198  }
   199  
   200  func shouldMatchOutput(expected, actual string, t *testing.T) {
   201  	act := []byte(actual)
   202  	exp := []byte(expected)
   203  
   204  	if len(act) != len(exp) {
   205  		t.Fatalf("content lengths do not match, expected: %d, actual %d, actual output:\n%s", len(exp), len(act), actual)
   206  	}
   207  
   208  	for i := 0; i < len(exp); i++ {
   209  		if act[i] == exp[i] {
   210  			continue
   211  		}
   212  
   213  		cpe := make([]byte, len(exp))
   214  		copy(cpe, exp)
   215  		e := append(exp[:i], '^')
   216  		e = append(e, cpe[i:]...)
   217  
   218  		cpa := make([]byte, len(act))
   219  		copy(cpa, act)
   220  		a := append(act[:i], '^')
   221  		a = append(a, cpa[i:]...)
   222  
   223  		t.Fatalf("expected output does not match:\n%s\n\n%s", string(a), string(e))
   224  	}
   225  }
   226  
   227  func TestProgressFormatterWithPanicInMultistep(t *testing.T) {
   228  	feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
   229  	if err != nil {
   230  		t.Fatalf("unexpected error: %v", err)
   231  	}
   232  
   233  	var buf bytes.Buffer
   234  	w := colors.Uncolored(&buf)
   235  	r := runner{
   236  		fmt:      progressFunc("progress", w),
   237  		features: []*feature{&feature{Feature: feat}},
   238  		initializer: func(s *Suite) {
   239  			s.Step(`^sub1$`, func() error { return nil })
   240  			s.Step(`^sub-sub$`, func() error { return nil })
   241  			s.Step(`^sub2$`, func() []string { return []string{"sub-sub", "sub1", "one"} })
   242  			s.Step(`^one$`, func() error { return nil })
   243  			s.Step(`^two$`, func() []string { return []string{"sub1", "sub2"} })
   244  		},
   245  	}
   246  
   247  	if !r.run() {
   248  		t.Fatal("the suite should have failed")
   249  	}
   250  }
   251  
   252  func TestProgressFormatterMultistepTemplates(t *testing.T) {
   253  	feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
   254  	if err != nil {
   255  		t.Fatalf("unexpected error: %v", err)
   256  	}
   257  
   258  	var buf bytes.Buffer
   259  	w := colors.Uncolored(&buf)
   260  	r := runner{
   261  		fmt:      progressFunc("progress", w),
   262  		features: []*feature{&feature{Feature: feat}},
   263  		initializer: func(s *Suite) {
   264  			s.Step(`^sub-sub$`, func() error { return nil })
   265  			s.Step(`^substep$`, func() Steps { return Steps{"sub-sub", `unavailable "John" cost 5`, "one", "three"} })
   266  			s.Step(`^one$`, func() error { return nil })
   267  			s.Step(`^(t)wo$`, func(s string) Steps { return Steps{"undef", "substep"} })
   268  		},
   269  	}
   270  
   271  	if r.run() {
   272  		t.Fatal("the suite should have passed")
   273  	}
   274  
   275  	expected := `
   276  .U 2
   277  
   278  
   279  1 scenarios (1 undefined)
   280  2 steps (1 passed, 1 undefined)
   281  %s
   282  
   283  Randomized with seed: %s
   284  
   285  You can implement step definitions for undefined steps with these snippets:
   286  
   287  func undef() error {
   288  	return godog.ErrPending
   289  }
   290  
   291  func unavailableCost(arg1 string, arg2 int) error {
   292  	return godog.ErrPending
   293  }
   294  
   295  func three() error {
   296  	return godog.ErrPending
   297  }
   298  
   299  func FeatureContext(s *godog.Suite) {
   300  	s.Step(` + "`^undef$`" + `, undef)
   301  	s.Step(` + "`^unavailable \"([^\"]*)\" cost (\\d+)$`" + `, unavailableCost)
   302  	s.Step(` + "`^three$`" + `, three)
   303  }
   304  `
   305  
   306  	var zeroDuration time.Duration
   307  	expected = fmt.Sprintf(expected, zeroDuration.String(), os.Getenv("GODOG_SEED"))
   308  	expected = trimAllLines(expected)
   309  
   310  	actual := trimAllLines(buf.String())
   311  	if actual != expected {
   312  		t.Fatalf("expected output does not match: %s", actual)
   313  	}
   314  }
   315  
   316  func TestProgressFormatterWhenMultiStepHasArgument(t *testing.T) {
   317  
   318  	var featureSource = `
   319  Feature: basic
   320  
   321    Scenario: passing scenario
   322  	When one
   323  	Then two:
   324  	"""
   325  	text
   326  	"""
   327  `
   328  	feat, err := gherkin.ParseFeature(strings.NewReader(featureSource))
   329  	if err != nil {
   330  		t.Fatalf("unexpected error: %v", err)
   331  	}
   332  
   333  	r := runner{
   334  		fmt:      progressFunc("progress", ioutil.Discard),
   335  		features: []*feature{&feature{Feature: feat}},
   336  		initializer: func(s *Suite) {
   337  			s.Step(`^one$`, func() error { return nil })
   338  			s.Step(`^two:$`, func(doc *gherkin.DocString) Steps { return Steps{"one"} })
   339  		},
   340  	}
   341  
   342  	if r.run() {
   343  		t.Fatal("the suite should have passed")
   344  	}
   345  }
   346  
   347  func TestProgressFormatterWhenMultiStepHasStepWithArgument(t *testing.T) {
   348  
   349  	var featureSource = `
   350  Feature: basic
   351  
   352    Scenario: passing scenario
   353  	When one
   354  	Then two`
   355  
   356  	feat, err := gherkin.ParseFeature(strings.NewReader(featureSource))
   357  	if err != nil {
   358  		t.Fatalf("unexpected error: %v", err)
   359  	}
   360  
   361  	var subStep = `three:
   362  	"""
   363  	content
   364  	"""`
   365  
   366  	var buf bytes.Buffer
   367  	w := colors.Uncolored(&buf)
   368  	r := runner{
   369  		fmt:      progressFunc("progress", w),
   370  		features: []*feature{&feature{Feature: feat}},
   371  		initializer: func(s *Suite) {
   372  			s.Step(`^one$`, func() error { return nil })
   373  			s.Step(`^two$`, func() Steps { return Steps{subStep} })
   374  			s.Step(`^three:$`, func(doc *gherkin.DocString) error { return nil })
   375  		},
   376  	}
   377  
   378  	if !r.run() {
   379  		t.Fatal("the suite should have failed")
   380  	}
   381  
   382  	expected := `
   383  .F 2
   384  
   385  
   386  --- Failed steps:
   387  
   388      Then two # :6
   389        Error: nested steps cannot be multiline and have table or content body argument
   390  
   391  
   392  1 scenarios (1 failed)
   393  2 steps (1 passed, 1 failed)
   394  %s
   395  
   396  Randomized with seed: %s
   397  `
   398  
   399  	var zeroDuration time.Duration
   400  	expected = fmt.Sprintf(expected, zeroDuration.String(), os.Getenv("GODOG_SEED"))
   401  	expected = trimAllLines(expected)
   402  
   403  	actual := trimAllLines(buf.String())
   404  	if actual != expected {
   405  		t.Fatalf("expected output does not match: %s", actual)
   406  	}
   407  }