cucumber / godog

Cucumber for golang
MIT License
2.22k stars 250 forks source link

runAfterScenarioHooks invoke twice when step failed that is not the last step #560

Closed Milk-Tang closed 10 months ago

Milk-Tang commented 1 year ago

👓 What did you see?

i run scenario which has two steps with v0.12.6, when the first step failed, there invoke the AfterScenarioHooks, and then set the remaining steps skipped, there also invoke the AfterScenarioHooks. I want to know if this meets expectations

✅ What did you expect to see?

i want the AfterScenarioHooks func just invoke once in a scenario

📦 Which tool/library version are you using?

v0.12.6

and i find the condition of invoke the AfterScenarioHooks here

🔬 How could we reproduce it?

📚 Any additional context?


This text was originally generated from a template, then edited by hand. You can modify the template here.

roskee commented 1 year ago

AfterScenario is deprecated. use After to run your logic after each scenario regardless of its failure status.

Milk-Tang commented 1 year ago

AfterScenario is deprecated. use After to run your logic after each scenario regardless of its failure status.

i encountered this issue while using the After

vearutop commented 1 year ago

This sounds like a bug, I think Before and After hooks should only be invoked once for a scenario.

vearutop commented 12 months ago

https://go.dev/play/p/Jryfgn_VA_u

Here is a small reproducer for reference.

package main

import (
    "context"
    "errors"
    "fmt"

    "github.com/cucumber/godog"
)

func main() {
    suite := godog.TestSuite{
        ScenarioInitializer: func(s *godog.ScenarioContext) {
            s.Before(func(ctx context.Context, sc *godog.Scenario) (context.Context, error) {
                fmt.Println("BEFORE", sc.Name)

                return ctx, nil
            })

            s.After(func(ctx context.Context, sc *godog.Scenario, err error) (context.Context, error) {
                fmt.Println("AFTER", sc.Name)

                return ctx, nil
            })

            s.Step("fail", func() error {
                return errors.New("fail")
            })

            s.Step("pass", func() {})
        },
        Options: &godog.Options{
            Format:   "pretty",
            Strict:   true,
            NoColors: true,
            FeatureContents: []godog.Feature{
                {
                    Name: "test",
                    Contents: []byte(`
Feature: test
  Scenario: test 1
    When I fail
    Then I pass

  Scenario: test 2
    When I fail
    Then I pass

  Scenario: test 3
    When I fail
    Then I pass
`),
                },
            },
        },
    }

    if suite.Run() != 0 {
        fmt.Println("test failed")
    } else {
        fmt.Println("test passed")
    }
}

Output:

Feature: test
BEFORE test 1
AFTER test 1

  Scenario: test 1 # test:3
    When I fail    # prog.go:26 -> main.main.func1.3
    fail
    Then I pass    # prog.go:30 -> main.main.func1.4
AFTER test 1
BEFORE test 2
AFTER test 2

  Scenario: test 2 # test:7
    When I fail    # prog.go:26 -> main.main.func1.3
    fail
    Then I pass    # prog.go:30 -> main.main.func1.4
AFTER test 2
BEFORE test 3
AFTER test 3

  Scenario: test 3 # test:11
    When I fail    # prog.go:26 -> main.main.func1.3
    fail
    Then I pass    # prog.go:30 -> main.main.func1.4
AFTER test 3

--- Failed steps:

  Scenario: test 1 # test:3
    When I fail # test:4
      Error: fail

  Scenario: test 2 # test:7
    When I fail # test:8
      Error: fail

  Scenario: test 3 # test:11
    When I fail # test:12
      Error: fail

3 scenarios (3 failed)
6 steps (3 failed, 3 skipped)
0s
test failed