enkessler / cuke_modeler

A gem to model a Cucumber test suite.
MIT License
22 stars 7 forks source link

Allow changing of features & scenarios via CukeModeler #16

Open leoc opened 1 month ago

leoc commented 1 month ago

Hey! Thanks for the abstraction of the gherkin parser here.

Since this is a gem to make life easier when working with gherkin feature files.

Would it be out of scope to add functionality to e.g. add tags, remove tags, replace tags, change feature title/description.

For example we could do things like:

file = CukeModeler::FeatureFile.new(filename)
file.feature.name = "Updated #{file.feature.name}"
file.feature.add_tag("ISSUE-5")
# or file.feature.replace_tag("id:5", "ISSUE-5")
file.write(filename)

This might also be worthwhile for cuke_tagger and cuke_cataloger. I see that you have a lot of custom code to modify the gherkin feature files.

What do you think?

enkessler commented 1 month ago

You can essentially do that kind of thing already. To continue off of your starting code

file = CukeModeler::FeatureFile.new(filename)
file.feature.name = "Updated #{file.feature.name}"
file.feature.add_tag("ISSUE-5")
# or file.feature.replace_tag("id:5", "ISSUE-5")
file.write(filename)

instead of trying to have the model write itself to a file with file.write(filename) you can convert the feature model inside of the file to a string and then write that with the normal Ruby file I/O methods

File.write(filename, file.feature.to_s)

The whitespace in the file won't be the same and you'll lose any comments in the file but, from a functionality perspective, the new Gherkin file will behave the same as the old one with your new changes.

enkessler commented 1 month ago

Because there will be as many different styles of laying out feature files as there are users of Gherkin, there isn't a particular way to output the models with #to_s that would be the 'correct' way. So I just went with something that seemed reasonable and would be interpreted by the Gherkin parser in an equivalent way to the original Gherkin that was being modeled. That is also why tools like cuke_cataloger and cuketagger modify the source files directly and only use the models for line number information. The idea was to impact the original file as little as possible because the gem has no idea how the user wants the file to look beyond "add a tag to this part".

I very much want these tools to enable a user's ability to do neat things with their features but 'enable' is as far as I have been able to take it. All of the needed parts are there but it is an exercise left to the user to arrange the parts in a way that best fits the needs of their own project.

Regarding adding more syntactic sugar methods like #add_tag/#remove_tag... it isn't necessarily out of scope for CukeModeler. Those actions are clearly still within the realm of model manipulation. Perhaps you are simply the first person to get tired of typing stuff like

model.tags.reject!{|tag| tag.name == '@old_tag}
model.tags << CukeModler::Tag.new('@new_tag')

and would rather have model.replace_tag('@old_tag', '@new_tag'). Admittedly, after having to come up with that pseudocode on the spot, I too suddenly appreciate the hypothetical helper methods.

leoc commented 1 month ago

I experimented with File.write(filename, file.feature.to_s) and it works for simple feature files, but the fact that I would loose any comment is a problem for me right now.

I am thinking about writing some gem like cuke_writer that could receive some formatting options, that even could be integrated with CukeLinter.

Anyways, I will have to investigate how the parser reads comments and how they could be reflected in CukeModeler. I am using Jira Xray as my task management tool and Background steps are referencing the Jira Pre-condition Issues via comments:

  Background:
    #@pre-cond1
    Given step 1
    #@pre-cond2
    Given step 2

A bit unfortunate, but it is what it is.

From your experience. Could that quick win? And how would it look like to be in scope of this gem?

enkessler commented 1 month ago

The fundamental problem with comments is that they are not related to any other model in a structural sense, even though the people writing them often mean them to be. Take your code, for example:

  Background:
    #@pre-cond1
    Given step 1
    #@pre-cond2
    Given step 2

For the reader, those comments 'belong' to the steps that they are above but, to the parser, they are just comments in a file and they don't belong to anything. Not in the same way that the Steps belong to the Background. That is what makes comments different when it comes to outputting a model tree. For all other model types, their structural relation to each other is sufficient to output them in a meaningful way. For comments, they have no relation to anything else except for their line number being very close to another model's line number.

If all models in a tree have source lines (most likely because the tree was made from an existing source file) then outputting an entire file would be feasible but, in that case, you don't really need to because you can just read the original source file again. If we consider the case of modified model trees (or trees that were made from scratch, without any source files), then we would have to come up with new line numbers ourselves or deal with some models having line numbers and some not having them. Sure, these are all solvable problems but they have always relied on too many assumptions and arbitrary decisions to tackle yet in the gem. For a formatter, however, making all of those decisions and having an 'official' way of handling the edge cases fits fine. That's what formatters are for and people can make additional formatters if they want to handle output differently.

enkessler commented 1 month ago

@leoc I've gotten away with not addressing the comment problem this long because, when the models first had #to_s implementations added, comments where not modeled at all and, because the string output of a FeatureFile is just its file path, the addition of comment models later on didn't impact the output at all. Comments should be included in the string output somewhere and the FeatureFile model is the only model that has the appropriate scope to include them. So...yeah, I'll have to update FeatureFile#to_s to generate Gherkin (like Feature#to_s but with comments included) and release a new major version of the gem.

Formatters are still a good idea. Making a custom formatter class is cleaner than trying to overwrite a bunch of #to_s methods on the models. And that's assuming that Gherkin is even the desired output. Maybe the formatter spits out JSon instead. Maybe the formatter takes a model tree and output location as input and generates a new directory structure on disk. The sky's the limit.

enkessler commented 1 month ago

I am thinking about writing some gem like cuke_writer that could receive some formatting options, that even could be integrated with CukeLinter.

Combining the writer (which could be a formatter or a whole collection of formatters) with the linter? Like how RuboCop can autocorrect some problems?

leoc commented 1 month ago

tead. Maybe the formatter takes a mod

First, let me thank you for your thorough feedback! Much appreciated!

My task at hand is implementing a synchronization to Jira and Xray which incorporates creating feature/test issues and adding the issue ids to the feature and scenario tags. That's what I am using cuke_modeler for.

I'd prefer not loosing comments, so when the general sync is done I will dabble a bit with your code and also look into the original gherkin parser to find out how comments could be handled. Until now I haven't had a lot of time to do that.

Then I will see that I implement a simple writer that fits my needs. :+1: