cucumber-rs / cucumber

Cucumber testing framework for Rust. Fully native, no external test runners or dependencies.
https://cucumber-rs.github.io/cucumber/main
Apache License 2.0
579 stars 70 forks source link

Documentation for Steps #248

Closed yds12 closed 1 year ago

yds12 commented 1 year ago

I have the need to generate some form of documentation for my cucumber steps, to make it easier to find them when writing feature files.

I have looked into rustdoc but it doesn't seem to be suitable.

The idea is to show the step definition based on the #[given("some step")], when and then attributes and use the doc comments above it as a description, something like:

/// We have an orange crab
#[given("a crab is orange")]
async fn given_crab_orange(...) {
    //...
}

/// It is some kind of crab
#[then(expr = "it is a {word} crab")]
async fn kind_of_crab(..., kind: String) {
    //...
}

would generate something like:

We have an orange crab
**Given a crab is orange**

It is some kind of crab
**Then it is a {word} crab**

Do you guys know of any easy way to do that, other than creating a script or a separate program?

tyranron commented 1 year ago

@yds12 I don't think something like this should be baked into the cucumber, as it's not something standardized or a general solution

However, World::collection() does return a step::Collection of all the steps defined via #[given]/#[when]/#[then] macros. Internally, it has the information about step matcher and location. Possibly, we could extend its API, allowing to iterate through the whole gathered collection, and even add there rustdoc comments (which are #[doc] attributes, essentially). This will fully serve your needs, while remain be a general solution: you just call the World::collection() and serialize it in the way you want.

But there is a caveat, I'd like to not do something about. We do always normalize step matchers into regexes internally. So, if you write:

/// We have an orange crab
#[given("a crab is orange")]
async fn given_crab_orange(...) {
    //...
}

/// It is some kind of crab
#[then(expr = "it is a {word} crab")]
async fn kind_of_crab(..., kind: String) {
    //...
}

you will have something like this:

We have an orange crab
**^Given a crab is orange$**

It is some kind of crab
**^Then it is a ([^\s]+) crab$**

And we don't have anything implementing a reverse conversion (going from regex to a raw string or Cucumber Expression).

Will this be OK for you?

tyranron commented 1 year ago

@yds12 ping

yds12 commented 1 year ago

Thanks @tyranron, I need to check this out. For now I went with a adhoc solution (a separate program that reads my sources and parses it). I wouldn't expect this to be baked into cucumber, but asked in case you guys knew some crate or some other trick to get this done.

Regarding the collection API you mentioned, I imagine adding the doc comments would be quite useful for that purpose (at least in my case, that's what I'm parsing from the sources.

tyranron commented 1 year ago

@yds12 if you solved your issue, then I think we can close this. We could reopen and implement if there will be further demand for it.