Tyler-Keith-Thompson / CucumberSwift

A lightweight swift Cucumber implementation
https://tyler-keith-thompson.github.io/CucumberSwift/documentation/cucumberswift/
MIT License
74 stars 19 forks source link

Cucumber Expression support #50

Closed hkingverily closed 2 years ago

hkingverily commented 2 years ago

Describe the bug Cucumber Expression support

To Reproduce Steps to reproduce the behavior:

  1. Create a function with a Cucumber Expression For example: Given("the member has {string}") { [self] matches, _ in let condition = matches[1] } Feature file: Given the member has "something"

Expected behavior Expect the Cucumber Expression to be matched, but instead got an error: invalid regex: The value “the member has {string}” is invalid.

Additional context

Tyler-Keith-Thompson commented 2 years ago

Thanks for calling this out! I'll add this to the backlog, it may be behind regex literal support and Swift Concurrency support.

Tyler-Keith-Thompson commented 2 years ago

Leaving this reference here for implementation: https://github.com/cucumber/cucumber-expressions#readme

Tyler-Keith-Thompson commented 2 years ago

Update: I started working on this over the weekend. There's a ways to go but it seemed reasonable to create a separate library for parsing Cucumber expressions.

When that library is complete I'll have it as a dependency of CucumberSwift.

In languages with regex literals cucumber expressions are used by default. Given that Swift just barely released regex literals I don't feel comfortable making it the default. So you'll need to be explicit about it:

Given("the member has {string}" as CucumberExpression) { match, _ in
    match.first(\.string) // whatever the member has
}

The matchers are typed, and custom matchers are supported. For the best examples, look at the tests for CucumberSwiftExpressions while I get docs more polished.

Tyler-Keith-Thompson commented 2 years ago

This is ready to rock in 3.3.19! Feel free to comment here with any questions. I still have some documentation work to do.

uo9qsuf commented 1 year ago

@Tyler-Keith-Thompson Thank you for this improvement, but for me the test with Cucumber expressions will not find. How I can fix this?

`Feature: Second Feature for test

Scenario: second scenario for test
    Given CucumberSwift is setup correctly 15 times
    When I execute the second these tests
    Then I can pull generated code with "matches" from the report explorer and get things set up for we cound run`
import XCTest
  import CucumberSwift
  import CucumberSwiftExpressions

  extension Cucumber: StepImplementation {
      public var bundle: Bundle {
          class Findme { }
          return Bundle(for: Findme.self)
      }

    public func setupSteps() {
        let app = XCUIApplication()
        BeforeScenario { (_) in
            app.launch()
        }

        Feature("Second Feature for test") {
            Scenario("second scenario for test") { [] in
                Given("CucumberSwift is setup correctly {Int}" as CucumberExpression) { count, _ in
                   print("count: \(count)")
                }

                When("I execute the second these tests" as CucumberExpression) { _, _ in
                    print("I execute the second these tests")
                }

                Then("I can pull generated code with {String} from the report explorer and get things set up for we cound run" as CucumberExpression) { matches, _ in
                    let string = try matches.first(\.string)
                }
            }
        }
    }
}

Thank you for the help :-)

Tyler-Keith-Thompson commented 1 year ago

@uo9qsuf it appears you've mixed and matched the Gherkin DSL with the matcher APIs. That's not an expressly supported use-case. Leave your gherkin as-is, but remove the Swift code that calls Feature("Second Feature for test") { and Scenario("second scenario for test") {

In other words, here is what your setupSteps function should look like:

public func setupSteps() {
    let app = XCUIApplication()
    BeforeScenario { (_) in
        app.launch()
    }

    Given("CucumberSwift is setup correctly {int}" as CucumberExpression) { matches, _ in
        let count = try matches.first(\.int)
        print("count: \(count)")
    }

    When("I execute the second these tests" as CucumberExpression) { _, _ in
        print("I execute the second these tests")
    }

    Then("I can pull generated code with {string} from the report explorer and get things set up for we cound run" as CucumberExpression) { matches, _ in
        let string = try matches.first(\.string)
    }
}

If you're still having issues after this change please open a new issue.

uo9qsuf commented 1 year ago

@Tyler-Keith-Thompson Thank you for your help. It works now. I was thinking I can use this structs to create a more readable test.

Is there a way to make more struct inside the steps? I split my feature over separate Test Classes in files.