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